io.h is deprecated, so now msp430.h is included instead.
[goodfet] / firmware / apps / twe / twe.c
1 /*! \file twe.c
2   \author EiNSTeiN_ <einstein@g3nius.org>
3   \brief Atmel 2-wire EEPROM
4 */
5
6 #include "command.h"
7
8 #include <signal.h>
9 #include <msp430.h>
10 #include <iomacros.h>
11
12 #include "twe.h"
13
14 #include "platform.h"
15
16 //! Handles a monitor command.
17 void spi_handle_fn( uint8_t const app,
18                                         uint8_t const verb,
19                                         uint32_t const len);
20
21 // define the spi app's app_t
22 app_t const twe_app = {
23
24         /* app number */
25         TWE,
26
27         /* handle fn */
28         twe_handle_fn,
29
30         /* name */
31         "2-wire EEPROM",
32
33         /* desc */
34         "\tThis app handles Atmel's 2-wire EEPROM protocol.\n"
35 };
36
37 // Transmit the START condition
38 void twe_start()
39 {
40     SETSDA;
41     
42     SETSCL;
43     delay_us(1);
44     
45     // high to low transision of SDA while SCL is high
46     CLRSDA;
47     delay_us(1);
48     
49     CLRSCL;
50     delay_us(2);
51     
52     SETSDA;
53   
54 }
55
56 // transmit the STOP condition
57 void twe_stop()
58 {
59     CLRSDA;
60     SETSCL;
61     delay_us(1);
62     
63     // low to high transision of SDA while SCL is high
64     SETSDA;
65     delay_us(2);
66     
67     CLRSCL;
68     delay_us(1);
69 }
70
71 //! Write 8 bits and read 1
72 unsigned char twe_tx(unsigned char byte){
73   unsigned int bit;
74   
75   for (bit = 0; bit < 8; bit++) {
76     delay_us(15);
77     
78     /* write SDA on trailing edge of previous clock */
79     if (byte & 0x80)
80       SETSDA;
81     else
82       CLRSDA;
83     byte <<= 1;
84     
85     SETSCL;
86     delay_us(1);
87     CLRSCL;
88   }
89   
90   // 9th bit is ACK
91   SPIDIR &= ~SDA;
92   SPIREN |= SDA;  /* as per datasheet, SDA must be pulled high externally */
93   SPIOUT |= SDA;
94   SETSCL;
95   delay_us(1);
96   bit = (SPIIN & SDA) ? 1 : 0;
97   delay_us(1);
98   CLRSCL;
99   delay_us(10);
100   SPIOUT &= ~SDA;
101   SPIREN &= ~SDA;
102   SPIDIR |= SDA;
103   
104   if(bit) {
105     debugstr("not acked :s");
106   }
107   
108   return bit;
109 }
110
111 //! Read 8 bits, optionally acking it
112 unsigned char twe_rx(unsigned int ack){
113   unsigned int rd = 0;
114   unsigned int bit = 0;
115   
116   SPIDIR &= ~SDA;
117   SPIREN |= SDA; /* as per datasheet, SDA must be pulled high externally */
118   SPIOUT |= SDA;
119   
120   for (bit = 0; bit < 8; bit++) {
121     delay_us(10);
122     SETSCL;
123     delay_us(1);
124     if(SPIIN & SDA)
125         rd |= 1 << (7-bit);
126     delay_us(1);
127     CLRSCL;
128   }
129   
130   SPIOUT &= ~SDA;
131   SPIREN &= ~SDA;
132   SPIDIR |= SDA;
133   
134   if(ack) {
135     // 9th bit is ACK
136     CLRSDA;
137       
138     SETSCL;
139     delay_us(15);
140     CLRSCL;
141     delay_us(15);
142   }
143   
144   return rd;
145 }
146
147 //! Read a block to a buffer.
148 void twe_peekblock(uint8_t const app,
149               uint8_t const verb,
150               uint16_t adr,
151               uint32_t len)
152 {
153   unsigned char i;
154   
155   // start command / write
156   twe_start();
157   twe_tx(0xa0); // preamble=1010, device adr=000, write=0
158   
159   // output address bytes
160   twe_tx((adr >> 8) & 0xff);
161   twe_tx(adr & 0xff);
162   
163   // start command / read
164   twe_start();
165   twe_tx(0xa1); // preamble=1010, device adr=000, read=1
166   
167   //Send reply header
168   txhead(app, verb, len);
169   
170   for(i=0;i<len;i++)
171     serial_tx(twe_rx(i != (len-1)));
172   
173   twe_stop();
174   
175   return;
176 }
177
178 //! Read a block to a buffer.
179 void twe_pokeblock(uint16_t adr,
180               uint8_t *buf,
181               uint32_t len)
182 {
183   unsigned char i;
184   // start command / write
185   twe_start();
186   twe_tx(0xa0); // preamble=1010, device adr=000, write=0
187   
188   // output address bytes
189   twe_tx((adr >> 8) & 0xFF);
190   twe_tx(adr & 0xFF);
191   
192   for(i=0;i<len;i++)
193     twe_tx(buf[i]);
194   
195   twe_stop();
196   
197   return;
198 }
199
200 //! Set up the pins for SPI mode.
201 void twe_setup()
202 {
203   int i;
204   
205   SETSDA; // normal position
206   CLRSCL; // normal position
207   SPIDIR |= SDA | SCL;
208   
209   twe_start();
210   
211   SETSDA;
212   for(i=0;i<9;i++) {
213     SETSCL;
214     delay_us(15);
215     CLRSCL;
216     delay_us(15);
217   }
218   
219   twe_start();
220   twe_stop();
221 }
222
223 //! Handles a monitor command.
224 void twe_handle_fn( uint8_t const app,
225                                         uint8_t const verb,
226                                         uint32_t const len)
227 {
228   uint16_t adr;
229   switch(verb)
230   {
231     case PEEK: //Grab 128 bytes from an SPI Flash ROM
232       adr = cmddataword[0];
233       twe_setup();
234       twe_peekblock(app, verb, adr, 128);
235       break;
236
237     //~ case POKE: //Grab 128 bytes from an SPI Flash ROM
238       //~ debugstr("reading");
239       //~ twe_pokeblock(cmddata, len);
240       //~ break;
241
242     case SETUP:
243       twe_setup();
244       txdata(app,verb,0);
245       break;
246   }
247 }