turn ftdi driver into echo server
[goodfet] / firmware / apps / i2c / i2c.c
1 /*! \file i2c.c
2   \author Travis Goodspeed
3   \brief I2C Master  
4 */
5
6
7 //Higher level left to client application.
8
9 //Based upon a neighborly example at
10 //http://codinglab.blogspot.com/2008/10/i2c-on-avr-using-bit-banging.html
11
12 #include "platform.h"
13 #include "command.h"
14 #include "i2c.h"
15
16 #ifndef _GNU_ASSEMBLER_
17 #include <msp430.h>
18 #endif
19
20 //Pins and I/O
21 #include <jtag.h>
22
23 //! Handles an i2c command.
24 void i2c_handle_fn( uint8_t const app,
25                                         uint8_t const verb,
26                                         uint32_t const len);
27
28 // define the i2c app's app_t
29 app_t const i2c_app = {
30
31         /* app number */
32         I2C_APP,
33
34         /* handle fn */
35         i2c_handle_fn,
36
37         /* name */
38         "I2C",
39
40         /* desc */
41         "\tThe I2C app implements the i2c bus protocol thus\n"
42         "\tturning your GoodFET into a USB-to-i2c adapter.\n"
43 };
44
45 #define I2CDELAY(x) delay(x<<4)
46
47
48 //2xx only, need 1xx compat code
49 #define SDA TDI
50 #define SCL TDO
51
52 #define SDAINPUT SPIDIR&=~SDA
53 #define SDAOUTPUT SPIDIR|=SDA
54 #define SCLINPUT SPIDIR&=~SCL
55 #define SCLOUTPUT SPIDIR|=SCL
56
57 #define PULLON SPIREN|=(SDA|SCL)
58 #define PULLOFF SPIREN&=~(SDA|SCL)
59
60 #define CLRSDA SPIOUT&=~SDA
61 #define SETSDA SPIOUT|=SDA
62 #define CLRSCL SPIOUT&=~SCL
63 #define SETSCL SPIOUT|=SCL
64
65 #define READSDA (SPIIN&SDA?1:0)
66 #define SETBOTH SPIOUT|=(SDA|SCL)
67
68 #define I2C_DATA_HI() SETSDA
69 #define I2C_DATA_LO() CLRSDA
70
71 #define I2C_CLOCK_HI() SETSCL
72 #define I2C_CLOCK_LO() CLRSCL
73
74 //#warning "Using internal resistors.  Won't work on 161x devices."
75
76 // Take control of the bus
77 void I2C_Take()
78 {
79   I2C_CLOCK_HI();
80   I2C_DATA_HI();
81   SCLOUTPUT;
82   SDAOUTPUT;
83 }
84
85 void I2C_Release()
86 {
87   SDAINPUT;
88   SCLINPUT;
89 }
90
91 //! Inits bitbanging port, must be called before using the functions below
92 void I2C_Init()
93 {
94   I2C_Take();
95   //PULLON;
96   I2CDELAY(1);
97 }
98
99 // XXX This is never called...
100 void I2C_Exit()
101 {
102   I2C_Release();
103   PULLOFF;
104 }
105
106 //! Write an I2C bit.
107 void I2C_WriteBit( unsigned char c )
108 {
109   if(c>0)
110     I2C_DATA_HI();
111   else
112     I2C_DATA_LO();
113
114   I2C_CLOCK_HI();
115   I2CDELAY(1);
116
117   I2C_CLOCK_LO();
118   I2CDELAY(1);
119 }
120
121 //! Read an I2C bit.
122 unsigned char I2C_ReadBit()
123 {
124   SDAINPUT;
125   I2C_CLOCK_HI();
126   
127   unsigned char c = READSDA;
128   if(c)
129     I2C_DATA_HI();
130   else
131     I2C_DATA_LO();
132
133   SDAOUTPUT;
134   I2CDELAY(1);
135   I2C_CLOCK_LO();
136   I2CDELAY(1);
137
138   return c;
139 }
140
141 unsigned char I2C_ReadBit_Wait()
142 {
143   SDAINPUT;
144   I2C_CLOCK_HI();
145   
146   unsigned int i = 0;
147   unsigned char c = READSDA;
148
149   while(c>0 && i<=35)
150   {
151     I2CDELAY(1);
152     c = READSDA;
153     i++;
154   }
155
156   if(c)
157     I2C_DATA_HI();
158   else
159     I2C_DATA_LO();
160
161   SDAOUTPUT;
162   I2CDELAY(1);
163   I2C_CLOCK_LO();
164   I2CDELAY(1);
165
166   return c?0:1; // return true on ACK (0)
167 }
168
169 //! Send a START Condition
170 void I2C_Start()
171 {
172   I2C_Take();   // XXX Should probably check to see if someone else is using the bus before we do this
173   I2CDELAY(3);
174   
175   I2C_DATA_LO();
176   I2CDELAY(3);
177   
178   I2C_CLOCK_LO();
179   I2CDELAY(1);
180 }
181
182 //! Send a STOP Condition
183 void I2C_Stop()
184 {
185   I2C_DATA_LO();
186   I2CDELAY(3);
187
188   I2C_CLOCK_HI();
189   I2CDELAY(3);
190
191   I2C_DATA_HI();
192   I2CDELAY(1);
193   I2C_Release();
194 }
195
196 //! write a byte to the I2C slave device
197 unsigned char I2C_Write( unsigned char c )
198 {
199   char i;
200   for (i=0;i<8;i++){
201     I2C_WriteBit( c & 0x80 );
202     c<<=1;
203   }
204   
205   return I2C_ReadBit_Wait();
206 }
207
208
209 //! read a byte from the I2C slave device
210 unsigned char I2C_Read( unsigned char ack )
211 {
212   unsigned char res = 0;
213   char i;
214   
215   for (i=0;i<8;i++){
216     res <<= 1;
217     res |= I2C_ReadBit();  
218   }
219   
220   if( ack > 0)
221     I2C_WriteBit(0);
222   else
223     I2C_WriteBit(1);
224   
225   I2CDELAY(1);
226   
227   return res;
228 }
229
230 //! Handles an i2c command.
231 void i2c_handle_fn( uint8_t const app,
232                                         uint8_t const verb,
233                                         uint32_t const len)
234 {
235         unsigned char i;
236         unsigned long l;
237         switch(verb)
238         {
239         case READ:
240                 l = len;
241                 if(l > 0)                                       //optional parameter of length
242                         l=cmddata[0];
243                 if(!l)                                          //default value of 1
244                         l=1;
245                 I2C_Start();
246                 for(i=0; i < l; i++)
247                         cmddata[i]=I2C_Read(i<l?1:0);
248                 I2C_Stop();
249                 txdata(app,verb,l);
250                 break;
251         case WRITE:
252                 I2C_Start();
253                 cmddata[0] = cmddata[0] << 1;
254                 for(i=0; i<len; i++) {
255                         if (!I2C_Write(cmddata[i]))             //if NACK
256                                 break;
257                 }
258                 I2C_Stop();
259                 cmddata[0] = i;
260                 txdata(app,verb,1);
261                 break;
262         case PEEK:
263                 l = cmddata[0];
264                 I2C_Start();
265                 unsigned char address = cmddata[1] << 1;
266                 I2C_Write(address);
267                 for(i=2; i < len; i++){
268                         I2C_Write(cmddata[i]);
269                 }
270                 I2C_Start();
271                 I2C_Write(address|1);                           // spit out the target address again and flip the read bit
272                 I2CDELAY(1);    // XXX We should wait for clock to go high here XXX
273                 for(i=0; i < l; i++)
274                         cmddata[i]=I2C_Read(i+1<l?1:0);         // If the next i is still less than l, then ACK
275                 I2C_Stop();
276                 txdata(app,verb,l);
277                 break;
278         case POKE:
279                 break;
280
281         case START:
282                 I2C_Start();
283                 txdata(app,verb,0);
284                 break;
285         case STOP:
286                 I2C_Stop();
287                 txdata(app,verb,0);
288                 break;
289         case SETUP:
290                 I2C_Init();
291                 txdata(app,verb,0);
292                 break;
293         }
294 }