Contiki-NG
i2c.c
1/*
2 * Copyright (c) 2006, Swedish Institute of Computer Science
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31/*
32 * Small and portable implementation of a bit-banging I2C bus master.
33 *
34 * The code should port really easily to platforms other than the
35 * msp430 but has some hardcoded constants in it.
36 *
37 * More info at:
38 * http://i2c-bus.org/
39 * http://www.esacademy.com/faq/i2c/
40 */
41
42#include <stdio.h>
43#include <contiki.h>
44#include "dev/spi-legacy.h"
45#include <dev/leds.h>
46
47#include "dev/i2c.h"
48
49/*
50 * On the Tmote sky access to I2C/SPI/UART0 must always be exclusive.
51 */
52
53void i2c_enable(void);
54void i2c_disable(void);
55int i2c_start(void);
56unsigned i2c_read(int send_ack);
57int i2c_write(unsigned);
58void i2c_stop(void);
59
60#define I2C_PxDIR P3DIR
61#define I2C_PxIN P3IN
62#define I2C_PxOUT P3OUT
63#define I2C_PxSEL P3SEL
64/*
65 * SDA == P3.1
66 * SCL == P3.3
67 */
68#define SDA 1
69#define SCL 3
70
71#define SDA_0() (I2C_PxDIR |= BV(SDA)) /* SDA Output */
72#define SDA_1() (I2C_PxDIR &= ~BV(SDA)) /* SDA Input */
73#define SDA_IS_1 (I2C_PxIN & BV(SDA))
74
75#define SCL_0() (I2C_PxDIR |= BV(SCL)) /* SCL Output */
76#define SCL_1() (I2C_PxDIR &= ~BV(SCL)) /* SCL Input */
77#define SCL_IS_1 (I2C_PxIN & BV(SCL))
78
79/*
80 * Should avoid infinite looping while waiting for SCL_IS_1. xxx/bg
81 */
82#define SCL_WAIT_FOR_1() do{}while (!SCL_IS_1)
83
84#define delay_4_7us() do{ _NOP(); _NOP(); _NOP(); _NOP(); \
85 _NOP(); _NOP(); _NOP(); _NOP(); \
86 _NOP(); _NOP(); _NOP(); _NOP(); }while(0)
87
88#define delay_4us() do{ _NOP(); _NOP(); _NOP(); _NOP(); \
89 _NOP(); _NOP(); _NOP(); _NOP(); \
90 _NOP(); _NOP(); }while(0)
91
92static unsigned char old_pxsel, old_pxout, old_pxdir;
93
94/*
95 * Grab SDA and SCL pins for exclusive use but remember old
96 * configuration so that it may be restored when we are done.
97 */
98void
99i2c_enable(void)
100{
101 unsigned char sda_scl = BV(SDA)|BV(SCL);
102
103 old_pxsel = I2C_PxSEL & sda_scl;
104 old_pxout = I2C_PxOUT & sda_scl;
105 old_pxdir = I2C_PxDIR & sda_scl;
106
107 spi_busy = 1;
108
109 I2C_PxSEL &= ~sda_scl;
110
111 I2C_PxOUT &= ~sda_scl;
112
113 I2C_PxDIR |= BV(SCL); /* SCL Output */
114 I2C_PxDIR &= ~BV(SDA); /* SDA Input */
115}
116
117/*
118 * Restore bus to what it was before i2c_enable.
119 *
120 */
121void
122i2c_disable(void)
123{
124 unsigned char not_sda_scl = ~(BV(SDA)|BV(SCL));
125
126 I2C_PxDIR = (I2C_PxDIR & not_sda_scl) | old_pxdir;
127 I2C_PxOUT = (I2C_PxOUT & not_sda_scl) | old_pxout;
128 I2C_PxSEL = (I2C_PxSEL & not_sda_scl) | old_pxsel;
129
130 spi_busy = 0;
131}
132
133int
134i2c_start(void)
135{
136 SDA_1();
137 SCL_1();
138#if 1
139 SCL_WAIT_FOR_1();
140#else
141 {
142 unsigned long n;
143 for (n = 0; n < 100000 && !SCL_IS_1; n++)
144 ;
145 if (!SCL_IS_1)
146 return -1;
147 }
148#endif
149 delay_4_7us();
150 SDA_0();
151 delay_4us();
152 SCL_0();
153 return 0;
154}
155
156void
157i2c_stop(void)
158{
159 SDA_0();
160 delay_4us();
161 SCL_1();
162 SCL_WAIT_FOR_1();
163 SDA_1();
164}
165
166/*
167 * Return true if we received an ACK.
168 */
169int
170i2c_write(unsigned _c)
171{
172 unsigned char c = _c;
173 unsigned long n;
174 int i;
175 int ret;
176
177 for (i = 0; i < 8; i++, c <<= 1) {
178 if (c & 0x80)
179 SDA_1();
180 else
181 SDA_0();
182 SCL_1();
183 SCL_WAIT_FOR_1();
184 SCL_0();
185 }
186
187 SDA_1();
188 SCL_1();
189 ret = 0; /* Loop waiting for an ACK to arrive. */
190 for (n = 0; n < 250000; n++) {
191 if (!SDA_IS_1) {
192 ret = 1;
193 break;
194 }
195 }
196 SCL_WAIT_FOR_1(); /* clock stretching? */
197 SCL_0();
198
199 return ret;
200}
201
202unsigned
203i2c_read(int send_ack)
204{
205 int i;
206 unsigned char c = 0x00;
207
208 SDA_1();
209 for (i = 0; i < 8; i++) {
210 c <<= 1;
211 SCL_1();
212 SCL_WAIT_FOR_1();
213 if (SDA_IS_1)
214 c |= 0x1;
215 SCL_0();
216 }
217
218 if (send_ack)
219 SDA_0();
220 SCL_1();
221 SCL_WAIT_FOR_1();
222 SCL_0();
223
224 return c;
225}
Header file for the LED HAL.
Basic SPI macros.