snapshot of my first "working" version from turn-on of Altus Metrum v0.1
[fw/openalt] / i2c / i2cInt.c
1 #include "FreeRTOS.h"
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <sys/times.h>
6
7 #include "i2c.h"
8
9 //
10 //  Default timeout, in milliseconds for generic read/write
11 //
12 #define I2C_DEFAULT_TIMEOUT 100
13 #undef  I2C_DEBUG
14
15 //
16 //
17 //
18 typedef enum
19 {
20   ACKPOLL_NO = 0,
21   ACKPOLL_YES
22 }
23 ackPoll_e;
24
25 //
26 //
27 //
28 static volatile int i2cBusInUse;
29 static U8 i2cAddress;
30 static U8 *i2cDataBuffer;
31 static int i2cDataLenWrite;
32 static int i2cDataLenRead;
33 static unsigned int i2cTimeoutInTicks = I2C_DEFAULT_TIMEOUT / portTICK_RATE_MS;
34 static int i2cDataCnt;
35 static ackPoll_e i2cAckPoll = ACKPOLL_NO;
36
37 //
38 //
39 //
40 #ifdef I2C_DEBUG
41 static U8 i2cTransactions [64];
42 static int i2cTransactionsIndex;
43 #define i2cDebug(x) do { if (i2cAckPoll && (i2cTransactionsIndex < (int) sizeof (i2cTransactions))) i2cTransactions [i2cTransactionsIndex++] = x; } while (0)
44 #define i2cDebugReset() do { i2cTransactionsIndex = 0; } while (0)
45 #else
46 #define i2cDebug(x) do { } while (0)
47 #define i2cDebugReset() do { } while (0)
48 #endif
49
50 static void i2cISR (void) __attribute__ ((interrupt ("IRQ")));
51 static void i2cISR (void)
52 {
53   i2cErrno = (I2C0_STAT & I2C_STAT_STATMASK);
54   i2cDebug (i2cErrno);
55
56   switch (i2cErrno)
57   {
58     //
59     //  Transmit conditions
60     //
61     case I2CERR_BUSERRORx : // 0x00
62       {
63         I2C0_CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
64         i2cAckPoll = ACKPOLL_NO;
65         i2cBusInUse = FALSE;
66       }
67       break;
68
69     case I2CERR_STARTTX : // 0x08
70     case I2CERR_REPEATEDSTARTTX : // 0x10
71       {
72         i2cDebug (i2cAddress);
73         I2C0_DAT = i2cAddress;
74       }
75       break;
76
77     case I2CERR_SLAWTX_ACKRX : // 0x18
78     case I2CERR_DATTX_ACKRX : // 0x28
79       {
80         i2cAckPoll = ACKPOLL_NO;
81
82         if (i2cDataLenWrite && (i2cDataCnt < i2cDataLenWrite))
83         {
84           i2cDebug (i2cDataBuffer [i2cDataCnt]);
85           I2C0_DAT = i2cDataBuffer [i2cDataCnt++];
86           I2C0_CONCLR = I2C_CONCLR_STAC;
87         }
88         else
89         {
90           if (!i2cDataLenRead)
91           {
92             i2cDebug (0xff);
93             I2C0_CONCLR = I2C_CONCLR_STAC;
94             I2C0_CONSET = I2C_CONSET_STO;
95             i2cErrno = I2CERR_NONE;
96             i2cBusInUse = FALSE;
97           }
98           else
99           {
100             i2cDebug (0xfe);
101             i2cAddress |= 0x01;
102             i2cDataCnt = 0;
103             I2C0_CONSET = I2C_CONSET_STA;
104           }
105         }
106       }
107       break;
108
109     case I2CERR_DATRX_NACKTX : // 0x58
110       {
111         i2cDataBuffer [i2cDataCnt++] = I2C0_DAT;
112         i2cDebug (i2cDataBuffer [i2cDataCnt - 1]);
113         i2cErrno = I2CERR_NONE;
114       }
115
116     case I2CERR_SLAWTX_NACKRX : // 0x20
117     case I2CERR_SLARTX_NACKRX : // 0x48
118       {
119         if (i2cAckPoll)
120           break;
121       }
122
123     case I2CERR_DATTX_NACKRX : // 0x30
124       {
125         I2C0_CONCLR = I2C_CONCLR_STAC;
126         I2C0_CONSET = I2C_CONSET_STO;
127         i2cBusInUse = FALSE;
128       }
129       break;
130
131     case I2CERR_ARBLOST : // 0x38
132       {
133         I2C0_CONSET = I2C_CONSET_STA;
134       }
135       break;
136
137     //
138     //  Receive byte conditions (fall through is intentional)
139     //
140     case I2CERR_DATRX_ACKTX : // 0x50
141       {
142         i2cDataBuffer [i2cDataCnt++] = I2C0_DAT;
143         i2cDebug (i2cDataBuffer [i2cDataCnt - 1]);
144       }
145
146     case I2CERR_SLARTX_ACKRX : // 0x40
147       {
148         if (i2cDataCnt < i2cDataLenRead - 1)
149         {
150           I2C0_CONCLR = I2C_CONCLR_STAC;
151           I2C0_CONSET = I2C_CONSET_AA;
152         }
153         else
154           I2C0_CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_AAC;
155       }
156       break;
157
158     case I2CERR_NOINFO :
159       break;
160
161     default:
162       {
163         I2C0_CONCLR = I2C_CONCLR_I2ENC;
164         i2cAckPoll = ACKPOLL_NO;
165         i2cBusInUse = FALSE;
166       }
167       break;
168   }
169
170   I2C0_CONCLR = I2C_CONSET_SI;
171   VIC_VectAddr = 0;
172 }
173
174 //
175 // i2c1Init
176 //
177 void i2cInit (void)
178 {
179   i2cBusInUse = FALSE;
180   i2cAckPoll = ACKPOLL_NO;
181
182   SCB_PCONP |= SCB_PCONP_PCI2C0;
183
184   PCB_PINSEL0 = (PCB_PINSEL0 & ~(PCB_PINSEL0_P02_MASK | PCB_PINSEL0_P03_MASK)) | (PCB_PINSEL0_P02_SCL0 | PCB_PINSEL0_P03_SDA0);
185
186   I2C0_CONCLR = I2C_CONCLR_MASK;
187   I2C0_CONSET = I2C_CONSET_I2EN;
188 #ifdef FC1025
189   // the Microchip 24FC1025 can handle a 1 Mhz clock
190   // PCLK / (i2c_clock * 2), with 48 Mhz PCLK that's 24...
191   // for AltusMetrum, 14.7456 Mhz xtal, it's 29.4912, use 30.
192   I2C0_SCLL   = 30;
193   I2C0_SCLH   = 30;
194 #else
195   I2C0_SCLL   = 240;
196   I2C0_SCLH   = 240;
197 #endif
198
199   //
200   //  Initialize the interrupt vector
201   //
202   VIC_IntSelect &= ~VIC_IntSelect_I2C0;
203   VIC_VectCntl7 = VIC_VectCntl_ENABLE | VIC_Channel_I2C0;
204   VIC_VectAddr7 = (int) i2cISR;
205   VIC_IntEnable = VIC_IntEnable_I2C0;
206 }
207
208 //
209 //
210 //
211 static int i2cWaitComplete (int ticks)
212 {
213   if (i2cBusInUse)
214   {
215     clock_t theFuture;
216
217     for (theFuture = times (NULL) + ticks; i2cBusInUse; )
218     {
219       if (times (NULL) > theFuture)
220       {
221         I2C0_CONCLR = I2C_CONCLR_I2ENC;
222         i2cErrno = I2CERR_TIMEOUTWC;
223         return -1;
224       }
225     }
226   }
227
228   return (i2cErrno == I2CERR_NONE) ? 0 : -1;
229 }
230
231 static int i2cPoll (U8 address)
232 {
233   clock_t theFuture = times (NULL) + 10;
234
235   VIC_IntEnClr = VIC_IntEnClr_I2C0;
236
237   while (times (NULL) < theFuture)
238   {
239     I2C0_CONCLR = I2C_CONSET_SI;
240     I2C0_CONSET = I2C_CONSET_STA;
241
242     while (!(I2C0_CONSET & I2C_CONSET_SI))
243       ;
244
245     I2C0_CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_SIC;
246     I2C0_DAT = address & ~0x01;
247
248     while (!(I2C0_CONSET & I2C_CONSET_SI))
249       ;
250
251     if ((i2cErrno = I2C0_STAT) == I2CERR_SLAWTX_ACKRX)
252       break;
253   }
254
255   if (i2cErrno != I2CERR_SLAWTX_ACKRX)
256     i2cErrno = I2CERR_TIMEOUTACKPOLL;
257
258   I2C0_CONCLR = I2C_CONCLR_SIC;
259   I2C0_CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
260
261   while (I2C0_CONSET & I2C_CONSET_STO)
262     ;
263
264   VIC_IntEnable = VIC_IntEnable_I2C0;
265
266   return (i2cErrno == I2CERR_SLAWTX_ACKRX) ? 0 : -1;
267 }
268
269 //
270 //
271 //
272 static int i2cKickOff (U8 address, U8 *buffer, int bufferLenWrite, int bufferLenRead, ackPoll_e ackPoll)
273 {
274   //
275   //  Determine if our first operation will be a write or read.  If both, the
276   //  write always occurs first.
277   //
278   if (bufferLenWrite)
279     address &= ~0x01;
280   else if (bufferLenRead)
281     address |= 0x01;
282   else
283     address &= ~0x01;
284
285   //
286   //  Wait until last I2C operation has finished.  
287   //
288   if (i2cBusInUse && i2cWaitComplete (i2cTimeoutInTicks))
289   {
290     i2cErrno = I2CERR_TIMEOUT;
291     return -1;
292   }
293
294   //
295   //  Mark bus as in use, save the address, buffer and length
296   //
297   i2cBusInUse = TRUE;
298   i2cAddress = address;
299   i2cDataBuffer = buffer;
300   i2cDataLenWrite = bufferLenWrite;
301   i2cDataLenRead = bufferLenRead;
302   i2cDataCnt = 0;
303   i2cAckPoll = ackPoll;
304   i2cDebugReset ();
305
306   //
307   //  Clear any outstanding bits, enable the interface, and send a start bit.
308   //  Once the start bit goes out, the interrupt drive state machine begins.
309   //
310   I2C0_CONCLR = I2C_CONCLR_MASK;
311   I2C0_CONSET = I2C_CONSET_I2EN;
312   I2C0_CONSET = I2C_CONSET_STA;
313
314   return 0;
315 }
316
317 //
318 //
319 //
320 static int i2cWriteBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
321 {
322   int r;
323
324   if (!(r = i2cKickOff (address, buffer, bufferLength, 0, ACKPOLL_NO)))
325     r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
326
327   return r;
328 }
329
330 static int i2cReadBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
331 {
332   int r;
333
334   if (!(r = i2cKickOff (address, buffer, 0, bufferLength, ACKPOLL_NO)))
335     r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
336
337   return r;
338 }
339
340 static int i2cWriteReadBufferEx (U8 address, U8 *buffer, U32 putLength, U32 getLength, int milliseconds)
341 {
342   int r;
343
344   if (!(r = i2cKickOff (address, buffer, putLength, getLength, ACKPOLL_NO)))
345     r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
346
347   return r;
348 }
349
350 //
351 //
352 //
353 void i2cSetTimeout (unsigned int timeoutInMilliseconds)
354 {
355   if (timeoutInMilliseconds < portTICK_RATE_MS)
356     timeoutInMilliseconds = portTICK_RATE_MS;
357
358   i2cTimeoutInTicks = timeoutInMilliseconds / portTICK_RATE_MS;
359 }
360
361 void i2cDump (void)
362 {
363 #ifdef I2C_DEBUG
364   int i;
365
366   for (i = 0; i < i2cTransactionsIndex; i++)
367     printf ("0x%02x ", i2cTransactions [i]);
368
369   printf ("\n");
370 #else
371   printf ("Not compiled for i2c debugging\n");
372 #endif
373 }
374
375 //
376 //  DANGER, WILL ROBINSON!  The callers buffer must persist until we're done
377 //
378 int i2cWriteBuffer (U8 address, U8 *buffer, U32 bufferLength)
379 {
380   return i2cWriteBufferEx (address, buffer, bufferLength, i2cTimeoutInTicks);
381 }
382
383 int i2cReadBuffer (U8 address, U8 *buffer, U32 bufferLength)
384 {
385   return i2cReadBufferEx (address, buffer, bufferLength, i2cTimeoutInTicks);
386 }
387
388 int i2cWriteReadBuffer (U8 address, U8 *buffer, U32 putLength, U32 getLength)
389 {
390   return i2cWriteReadBufferEx (address, buffer, putLength, getLength, i2cTimeoutInTicks);
391 }
392
393 int i2cWriteBufferPoll (U8 address, U8 *buffer, U32 bufferLength)
394 {
395   int r;
396
397   if (!(r = i2cKickOff (address, buffer, bufferLength, 0, ACKPOLL_NO)))
398     if (!(r = i2cWaitComplete (i2cTimeoutInTicks)))
399       r = i2cPoll (address);
400
401   return r;
402 }
403
404 int i2cWriteReadBufferPoll (U8 address, U8 *buffer, U32 putLength, U32 getLength)
405 {
406   int r;
407
408   if (!(r = i2cKickOff (address, buffer, putLength, getLength, ACKPOLL_NO)))
409     if (!(r = i2cWaitComplete (i2cTimeoutInTicks)))
410       r = i2cPoll (address);
411
412   return r;
413 }