1018c5fba8d7e28723c3105425b95bcdd5d24a73
[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 //! Inits bitbanging port, must be called before using the functions below
77 void I2C_Init()
78 {
79   
80   //Clear SDA and SCL.
81   //Direction, not value, is used to set the value.
82   
83   SCLOUTPUT;
84   SDAOUTPUT;
85   
86   I2C_CLOCK_HI();
87   I2C_DATA_HI();
88   //PULLON;
89
90   I2CDELAY(1);
91 }
92
93 // This is never called...
94 void I2C_Exit()
95 {
96   SDAINPUT;
97   SCLINPUT;
98   PULLOFF;
99 }
100
101 //! Write an I2C bit.
102 void I2C_WriteBit( unsigned char c )
103 {
104   if(c>0)
105     I2C_DATA_HI();
106   else
107     I2C_DATA_LO();
108
109   I2C_CLOCK_HI();
110   I2CDELAY(1);
111
112   I2C_CLOCK_LO();
113   I2CDELAY(1);
114
115   /*if(c>0)
116    *I2C_DATA_LO();
117    *
118    *I2CDELAY(1);
119    */
120 }
121
122 //! Read an I2C bit.
123 unsigned char I2C_ReadBit()
124 {
125   SDAINPUT;
126   I2C_CLOCK_HI();
127   
128   unsigned char c = READSDA;
129   if(c)
130     I2C_DATA_HI();
131   else
132     I2C_DATA_LO();
133
134   SDAOUTPUT;
135   I2CDELAY(1);
136   I2C_CLOCK_LO();
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
165   return c;
166 }
167
168 //! Send a START Condition
169 void I2C_Start()
170 {
171   // set both to high at the same time
172   SETBOTH;
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 }
194
195 //! write a byte to the I2C slave device
196 unsigned char I2C_Write( unsigned char c )
197 {
198   char i;
199   for (i=0;i<8;i++){
200     I2C_WriteBit( c & 0x80 );
201     c<<=1;
202   }
203   
204   return I2C_ReadBit_Wait();
205 }
206
207
208 //! read a byte from the I2C slave device
209 unsigned char I2C_Read( unsigned char ack )
210 {
211   unsigned char res = 0;
212   char i;
213   
214   for (i=0;i<8;i++){
215     res <<= 1;
216     res |= I2C_ReadBit();  
217   }
218   
219   if( ack > 0)
220     I2C_WriteBit(0);
221   else
222     I2C_WriteBit(1);
223   
224   I2CDELAY(1);
225   
226   return res;
227 }
228
229 //! Handles an i2c command.
230 void i2c_handle_fn( uint8_t const app,
231                                         uint8_t const verb,
232                                         uint32_t const len)
233 {
234         unsigned char i;
235         unsigned long l;
236         switch(verb)
237         {
238         case READ:
239                 l = len;
240                 if(l > 0)                                       //optional parameter of length
241                         l=cmddata[0];
242                 if(!l)                                          //default value of 1
243                         l=1;
244                 I2C_Start();
245                 for(i=0; i < l; i++)
246                         cmddata[i]=I2C_Read(i<l?1:0);
247                 I2C_Stop();
248                 txdata(app,verb,l);
249                 break;
250         case WRITE:
251                 I2C_Start();
252                 for(i=0; i<len; i++)
253                         cmddata[0]+=I2C_Write(cmddata[i]);
254                 I2C_Stop();
255                 txdata(app,verb,1);
256                 break;
257         case PEEK:
258                 l = cmddata[0];
259                 I2C_Start();
260                 unsigned char address = cmddata[1]<<1;
261                 I2C_Write(address);
262                 for(i=2; i < len; i++){
263                         I2C_Write(cmddata[i]);
264                 }
265                 I2C_Start();
266                 I2C_Write(address|1);                           // spit out the target address again and flip the read bit
267                 I2CDELAY(1);    // XXX We should wait for clock to go high here XXX
268                 for(i=0; i < l; i++)
269                         cmddata[i]=I2C_Read(i+1<l?1:0);         // If the next i is still less than l, then ACK
270                 I2C_Stop();
271                 txdata(app,verb,l);
272                 break;
273         case POKE:
274                 break;
275
276         case START:
277                 I2C_Start();
278                 txdata(app,verb,0);
279                 break;
280         case STOP:
281                 I2C_Stop();
282                 txdata(app,verb,0);
283                 break;
284         case SETUP:
285                 I2C_Init();
286                 txdata(app,verb,0);
287                 break;
288         }
289 }