Wixel SDK
i2c.c
1 /* i2c.c: A basic software implementation of a master node for I2C communication
2  * (the CC2511 does not have a hardware I2C module). This library does not
3  * support multi-master I2C buses.
4  */
5 
6 /* Dependencies ***************************************************************/
7 
8 #include <cc2511_map.h>
9 #include <board.h>
10 #include <time.h>
11 #include <gpio.h>
12 #include <i2c.h>
13 
14 /* Global Constants & Variables ***********************************************/
15 
16 uint8 DATA i2cPinScl = 10; // P1_0
17 uint8 DATA i2cPinSda = 11; // P1_1
18 
19 static uint16 XDATA halfPeriodUs = 5; // freq = 100 kHz
20 static uint16 XDATA timeout = 10;
21 static BIT started = 0;
22 
23 /* i2cTimeoutOccurred is the publicly readable error flag. It must be manually
24  * cleared.
25  * We have an internal timeout flag too so that e.g. i2cReadByte can abort if
26  * i2cReadBit times out, but we can clear the internal flag at the beginning of
27  * i2cReadByte so an earlier timeout doesn't affect a later call.
28  */
30 static BIT internalTimeoutOccurred = 0;
31 
32 
33 /* Functions ******************************************************************/
34 
35 void i2cSetFrequency(uint16 freqKHz)
36 {
37  // delayMicroseconds takes a uint8, so halfPeriodUs cannot be more than 255
38  if (freqKHz < 2)
39  {
40  freqKHz = 2;
41  }
42 
43  // force halfPeriodUs to round up so we don't use a higher frequency than what was chosen
44  // TODO: implement a timing function with better resolution than delayMicroseconds to allow finer-grained frequency control?
45  halfPeriodUs = (500 + freqKHz - 1) / freqKHz;
46 }
47 
48 void i2cSetTimeout(uint16 timeoutMs)
49 {
50  timeout = timeoutMs;
51 }
52 
53 BIT i2cReadScl(void)
54 {
56  return isPinHigh(i2cPinScl);
57 }
58 
59 BIT i2cReadSda(void)
60 {
62  return isPinHigh(i2cPinSda);
63 }
64 
65 void i2cClearScl(void)
66 {
68 }
69 
70 void i2cClearSda(void)
71 {
73 }
74 
75 void i2cWaitForHighScl(uint16 timeoutMs)
76 {
77  uint32 time = getMs();
78  while (i2cReadScl() == 0)
79  {
80  if (getMs() - time > timeoutMs)
81  {
82  internalTimeoutOccurred = 1;
84  started = 0;
85  return;
86  }
87  }
88 }
89 
90 /* Generate an I2C STOP condition (P):
91  * SDA goes high while SCL is high
92  */
93 void i2cStop(void)
94 {
95  i2cClearSda(); // drive SDA low while SCL is low
96  delayMicroseconds(halfPeriodUs);
97 
98  // handle clock stretching
99  i2cWaitForHighScl(timeout);
100  if (internalTimeoutOccurred) return;
101 
102  // SCL is now high
103  i2cReadSda(); // let SDA line go high while SCL is high
104  delayMicroseconds(halfPeriodUs);
105  started = 0;
106 }
107 
108 /* Generate an I2C START or repeated START condition (S):
109  * SDA goes low while SCL is high
110  */
111 void i2cStart(void)
112 {
113  // if started == 1, do a repeated start
114  if (started)
115  {
116  i2cReadSda(); // let SDA line go high while SCL is low
117  delayMicroseconds(halfPeriodUs);
118  }
119 
120  // handle clock stretching
121  i2cWaitForHighScl(timeout);
122  if (internalTimeoutOccurred) return;
123 
124  // SCL is now high
125  i2cClearSda(); // drive SDA low while SCL is high
126  delayMicroseconds(halfPeriodUs);
127  i2cClearScl(); // drive SCL low
128  started = 1;
129 }
130 
131 /* Write a bit to the I2C bus
132  * It is assumed that SCL is low when this function starts.
133  * SDA is set to the appropriate bit value while SCL is low, there is a
134  * delay for half of the clock period while SDA stablizes, then SCL
135  * is allowed to go high for the second half of the clock period, which
136  * indicates the on SDA is valid. This function drives SCL low again
137  * before it returns.
138  */
139 void i2cWriteBit(BIT b)
140 {
141  if (b)
142  {
143  i2cReadSda(); // let SDA go high
144  }
145  else
146  {
147  i2cClearSda(); // drive SDA low
148  }
149  delayMicroseconds(halfPeriodUs);
150 
151  // handle clock stretching
152  i2cWaitForHighScl(timeout);
153  if (internalTimeoutOccurred) return;
154 
155  // SCL is now high, data is valid
156  delayMicroseconds(halfPeriodUs);
157  i2cClearScl(); // drive SCL low
158 }
159 
160 /* Read a bit to the I2C bus
161  * It is assumed that SCL is low when this function starts.
162  * The master tristates SDA so the slave transmitter can control the state
163  * and delays for half of the clock period (or longer if the slave is holding
164  * SCL low). It then lets SCL go high, records the state of the SDA line,
165  * and delays for the second half of the clock period. This function drives SCL
166  * low again before it returns. Return value is not meaningful if timeout
167  * occurs.
168  */
169 BIT i2cReadBit(void)
170 {
171  BIT b;
172 
173  i2cReadSda(); // let slave transmitter control state of SDA line
174  delayMicroseconds(halfPeriodUs);
175 
176  // handle clock stretching
177  i2cWaitForHighScl(timeout);
178  if (internalTimeoutOccurred) return 0;
179 
180  // SCL is now high, data is valid
181  b = i2cReadSda(); // store state of SDA line now that SCL is high
182  delayMicroseconds(halfPeriodUs);
183  i2cClearScl(); // drive SCL low
184  return b;
185 }
186 
187 /* Write a byte to I2C bus. Return 0 if ack by the slave, 1 if nack.
188  * The return value is not meaningful if a timeout occurs.
189  */
191 {
192  uint8 i;
193  BIT nack;
194 
195  internalTimeoutOccurred = 0;
196 
197  for (i = 0; i < 8; i++)
198  {
199  i2cWriteBit(byte & 0x80);
200  if (internalTimeoutOccurred) return 0;
201  byte <<= 1;
202  }
203  nack = i2cReadBit();
204  if (internalTimeoutOccurred) return 0;
205 
206  if (nack)
207  {
208  i2cStop();
209  if (internalTimeoutOccurred) return 0;
210  }
211  return nack;
212 }
213 
214 /* Read a byte from I2C bus.
215  * The return value is not meaningful if a timeout occurs.
216  */
218 {
219  uint16 byte = 0;
220  uint8 i;
221  BIT b;
222 
223  internalTimeoutOccurred = 0;
224 
225  for (i = 0; i < 8; i++)
226  {
227  b = i2cReadBit();
228  if (internalTimeoutOccurred) return 0;
229  byte = (byte << 1) | b;
230  }
231 
232  i2cWriteBit(nack);
233  if (internalTimeoutOccurred) return 0;
234 
235  return byte;
236 }
#define DATA
Definition: cc2511_types.h:52
void setDigitalInput(uint8 pinNumber, BIT pulled) __reentrant
Configures the specified pin as an input.
Definition: gpio.c:41
#define LOW
Definition: gpio.h:121
void setDigitalOutput(uint8 pinNumber, BIT value) __reentrant
Configures the specified pin as a digital output.
Definition: gpio.c:36
uint8 DATA i2cPinSda
Definition: i2c.c:17
#define XDATA
Definition: cc2511_types.h:65
void i2cStart(void)
Definition: i2c.c:111
void i2cSetTimeout(uint16 timeoutMs)
Definition: i2c.c:48
BIT i2cTimeoutOccurred
Definition: i2c.c:29
uint8 DATA i2cPinScl
Definition: i2c.c:16
void i2cSetFrequency(uint16 freqKHz)
Definition: i2c.c:35
uint8 i2cReadByte(BIT nack)
Definition: i2c.c:217
#define HIGH_IMPEDANCE
Definition: gpio.h:128
unsigned long uint32
Definition: cc2511_types.h:21
__bit BIT
Definition: cc2511_types.h:32
unsigned short uint16
Definition: cc2511_types.h:15
void delayMicroseconds(uint8 microseconds)
BIT i2cWriteByte(uint8 byte)
Definition: i2c.c:190
unsigned char uint8
Definition: cc2511_types.h:9
BIT isPinHigh(uint8 pinNumber) __reentrant
Returns the current input or output value of the pin.
Definition: gpio.c:46
uint32 getMs()
Definition: time.c:19
void i2cStop(void)
Definition: i2c.c:93