- New code to dump the contents of Atmel's 2-wire EEPROM chips
[goodfet] / firmware / apps / twe / twe.c
1 /*! \file spi.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 <io.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   //~ else {
144     //~ SETSDA;
145   //~ }
146   
147   
148   return rd;
149 }
150
151 //! Read a block to a buffer.
152 void twe_peekblock(uint8_t const app,
153               uint8_t const verb,
154               uint16_t adr,
155               uint32_t len)
156 {
157   unsigned char i;
158   
159   // start command / write
160   twe_start();
161   twe_tx(0xa0); // preamble=1010, device adr=000, write=0
162   
163   // output address bytes
164   //~ debughex((adr >> 8) & 0xff);
165   twe_tx((adr >> 8) & 0xff);
166   //~ debughex(adr & 0xff);
167   twe_tx(adr & 0xff);
168   
169   // start command / read
170   twe_start();
171   twe_tx(0xa1); // preamble=1010, device adr=000, read=1
172   
173   //Send reply header
174   txhead(app, verb, len);
175   
176   for(i=0;i<len;i++)
177     serial_tx(twe_rx(i != (len-1)));
178   
179   twe_stop();
180   
181   return;
182 }
183
184 //! Read a block to a buffer.
185 void twe_pokeblock(uint16_t adr,
186               uint8_t *buf,
187               uint32_t len)
188 {
189   unsigned char i;
190   // start command / write
191   twe_start();
192   twe_tx(0xa0); // preamble=1010, device adr=000, write=0
193   
194   // output address bytes
195   twe_tx((adr >> 8) & 0xFF);
196   twe_tx(adr & 0xFF);
197   
198   for(i=0;i<len;i++)
199     twe_tx(buf[i]);
200   
201   twe_stop();
202   
203   return;
204 }
205
206 //! Set up the pins for SPI mode.
207 void twe_setup()
208 {
209   int i;
210   
211   SETSDA; // normal position
212   CLRSCL; // normal position
213   SPIDIR |= SDA | SCL;
214   
215   twe_start();
216   
217   SETSDA;
218   for(i=0;i<9;i++) {
219     SETSCL;
220     delay_us(15);
221     CLRSCL;
222     delay_us(15);
223   }
224   
225   twe_start();
226   twe_stop();
227   
228   
229 }
230
231 //! Handles a monitor command.
232 void twe_handle_fn( uint8_t const app,
233                                         uint8_t const verb,
234                                         uint32_t const len)
235 {
236   uint16_t adr;
237   switch(verb)
238   {
239     case PEEK: //Grab 128 bytes from an SPI Flash ROM
240       adr = cmddataword[0];
241       twe_setup();
242       twe_peekblock(app, verb, adr, 128);
243       break;
244
245     //~ case POKE: //Grab 128 bytes from an SPI Flash ROM
246       //~ debugstr("reading");
247       //~ twe_pokeblock(cmddata, len);
248       //~ break;
249
250     case SETUP:
251       twe_setup();
252       txdata(app,verb,0);
253       break;
254   }
255 }