Lots of new CC2420 stabilization.
[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 #include <signal.h>
17 #include <msp430.h>
18 #include <iomacros.h>
19
20
21 //Pins and I/O
22 #include <jtag.h>
23
24 //! Handles an i2c command.
25 void i2c_handle_fn( uint8_t const app,
26                                         uint8_t const verb,
27                                         uint32_t const len);
28
29 // define the i2c app's app_t
30 app_t const i2c_app = {
31
32         /* app number */
33         I2C_APP,
34
35         /* handle fn */
36         i2c_handle_fn,
37
38         /* name */
39         "I2C",
40
41         /* desc */
42         "\tThe I2C app implements the i2c bus protocol thus\n"
43         "\tturning your GoodFET into a USB-to-i2c adapter.\n"
44 };
45
46 #define I2CDELAY(x) delay(x<<4)
47
48
49 //2xx only, need 1xx compat code
50 #if (board == tilaunchpad)
51 // P3.1 SDA
52 // P3.3 SCL
53 #define SDA (1<<1)
54 #define SCL (1<<3)
55
56 #define CLRSDA P3OUT&=~SDA
57 #define SETSDA P3OUT|=SDA
58 #define CLRSCL P3OUT&=~SCL
59 #define SETSCL P3OUT|=SCL
60
61 #define READSDA (P3IN&SDA?1:0)
62 #define SDAINPUT P3DIR&=~SDA
63 #define SDAOUTPUT P3DIR|=SDA
64 #define SCLINPUT P3DIR&=~SCL
65 #define SCLOUTPUT P3DIR|=SCL
66 #define SETBOTH P3OUT|=(SDA|SCL)
67
68 #else
69
70 #define SDA TDI
71 #define SCL TDO
72
73 #define CLRSDA P5OUT&=~SDA
74 #define SETSDA P5OUT|=SDA
75 #define CLRSCL P5OUT&=~SCL
76 #define SETSCL P5OUT|=SCL
77
78 #define READSDA (P5IN&SDA?1:0)
79 #define SETBOTH P5OUT|=(SDA|SCL)
80 #endif
81
82 #define I2C_DATA_HI() SETSDA
83 #define I2C_DATA_LO() CLRSDA
84
85 #define I2C_CLOCK_HI() SETSCL
86 #define I2C_CLOCK_LO() CLRSCL
87
88 //#warning "Using internal resistors.  Won't work on 161x devices."
89
90 //! Inits bitbanging port, must be called before using the functions below
91 void I2C_Init()
92 {
93   
94   //Clear SDA and SCL.
95   //Direction, not value, is used to set the value.
96   //(Pull-up or 0.)
97   
98 #if (platform == tilaunchpad)
99   SDAOUTPUT;
100   SCLOUTPUT;
101 #else
102   P5DIR|=(SDA|SCL);
103 #endif
104   //P5REN|=SDA|SCL;
105   
106   
107   I2C_CLOCK_HI();
108   I2C_DATA_HI();
109
110   I2CDELAY(1);
111 }
112
113 #if (platform == tilaunchpad)
114 void I2C_Exit()
115 {
116   SDAINPUT;
117   SCLINPUT;
118 }
119 #endif
120
121 //! Write an I2C bit.
122 void I2C_WriteBit( unsigned char c )
123 {
124   if(c>0)
125     I2C_DATA_HI();
126   else
127     I2C_DATA_LO();
128
129   I2C_CLOCK_HI();
130   I2CDELAY(1);
131
132   I2C_CLOCK_LO();
133   I2CDELAY(1);
134
135   if(c>0)
136     I2C_DATA_LO();
137
138   I2CDELAY(1);
139 }
140
141 //! Read an I2C bit.
142 unsigned char I2C_ReadBit()
143 {
144   I2C_DATA_HI();
145
146   I2C_CLOCK_HI();
147   SDAINPUT;
148   I2CDELAY(1);
149   
150   unsigned char c = READSDA;
151
152   I2C_CLOCK_LO();
153   I2CDELAY(1);
154   SDAOUTPUT;
155
156   return c;
157 }
158
159
160 //! Send a START Condition
161 void I2C_Start()
162 {
163   // set both to high at the same time
164   SETBOTH;
165   I2CDELAY(1);
166   
167   I2C_DATA_LO();
168   I2CDELAY(1);
169   
170   I2C_CLOCK_LO();
171   I2CDELAY(1);
172 }
173
174 //! Send a STOP Condition
175 void I2C_Stop()
176 {
177   I2C_CLOCK_HI();
178   I2CDELAY(1);
179
180   I2C_DATA_HI();
181   I2CDELAY(1);
182 }
183
184 //! write a byte to the I2C slave device
185 unsigned char I2C_Write( unsigned char c )
186 {
187   char i;
188   for (i=0;i<8;i++){
189     I2C_WriteBit( c & 0x80 );
190     c<<=1;
191   }
192   
193   return I2C_ReadBit();
194 }
195
196
197 //! read a byte from the I2C slave device
198 unsigned char I2C_Read( unsigned char ack )
199 {
200   unsigned char res = 0;
201   char i;
202   
203   for (i=0;i<8;i++){
204     res <<= 1;
205     res |= I2C_ReadBit();  
206   }
207   
208   if( ack > 0)
209     I2C_WriteBit(0);
210   else
211     I2C_WriteBit(1);
212   
213   I2CDELAY(1);
214   
215   return res;
216 }
217
218
219 //! Handles an i2c command.
220 void i2c_handle_fn( uint8_t const app,
221                                         uint8_t const verb,
222                                         uint32_t const len)
223 {
224         unsigned char i;
225         unsigned long l;
226         switch(verb)
227         {
228
229         case PEEK:
230                 break;
231         case POKE:
232                 break;
233
234         case READ:
235                 l = len;
236                 if(l > 0)                                       //optional parameter of length
237                         l=cmddata[0];
238                 if(!l)                                          //default value of 1
239                         l=1;
240                 for(i = 0; i < l; i++)
241                         cmddata[i]=I2C_Read(1); //Always acknowledge
242                 txdata(app,verb,l);
243                 break;
244         case WRITE:
245                 cmddata[0]=0;
246                 for(i=0;i<len;i++)
247                         cmddata[0]+=I2C_Write(cmddata[i]);
248                 txdata(app,verb,1);
249                 break;
250         case START:
251                 I2C_Start();
252                 txdata(app,verb,0);
253                 break;
254         case STOP:
255                 I2C_Stop();
256                 txdata(app,verb,0);
257                 break;
258         case SETUP:
259                 I2C_Init();
260                 txdata(app,verb,0);
261                 break;
262         }
263 }