b552ae7617a8cbca64a554898fbfd767144b3ba7
[goodfet] / firmware / apps / spi / spi.c
1 /*! \file spi.c
2   \author Travis Goodspeed
3   \brief SPI Master
4 */
5
6 //Higher level left to client application.
7
8
9 #include "command.h"
10
11 #ifdef __MSPGCC__
12 #include <msp430.h>
13 #else
14 #include <signal.h>
15 #include <io.h>
16 #include <iomacros.h>
17 #endif
18
19 #include "spi.h"
20
21 #define SPIAPPLICATION
22
23 #include "platform.h"
24
25 //! Handles a monitor command.
26 void spi_handle_fn( uint8_t const app,
27                                         uint8_t const verb,
28                                         uint32_t const len);
29
30 // define the spi app's app_t
31 app_t const spi_app = {
32
33         /* app number */
34         SPI,
35
36         /* handle fn */
37         spi_handle_fn,
38
39         /* name */
40         "SPI",
41
42         /* desc */
43         "\tThe SPI app handles the SPI bus protocol, turning\n"
44         "\tyour GoodFET into a USB-to-SPI adapter.\n"
45 };
46
47 //This could be more accurate.
48 //Does it ever need to be?
49 #define SPISPEED 0
50 #define SPIDELAY(x) delay(x)
51
52
53 //! Set up the pins for SPI mode.
54 void spisetup(){
55   SETSS;
56   SPIDIR|=MOSI+SCK+BIT0; //BIT0 might be SS
57   SPIDIR&=~MISO;
58   DIRSS;
59
60   //Begin a new transaction.
61
62   CLRSS;
63   SETSS;
64 }
65
66
67 //! Read and write an SPI byte.
68 unsigned char spitrans8(unsigned char byte){
69   register unsigned int bit;
70   //This function came from the SPI Wikipedia article.
71   //Minor alterations.
72
73   for (bit = 0; bit < 8; bit++) {
74     /* write MOSI on trailing edge of previous clock */
75     if (byte & 0x80)
76       SETMOSI;
77     else
78       CLRMOSI;
79     byte <<= 1;
80
81     //SPIDELAY(100);
82     SETCLK;
83     //SPIDELAY(100);
84
85     /* read MISO on trailing edge */
86     byte |= READMISO;
87     CLRCLK;
88   }
89   return byte;
90 }
91
92
93 //! Enable SPI writing
94 void spiflash_wrten(){
95   SETSS;
96   /*
97   CLRSS; //Drop !SS to begin transaction.
98   spitrans8(0x04);//Write Disable
99   SETSS;  //Raise !SS to end transaction.
100   */
101   CLRSS; //Drop !SS to begin transaction.
102   spitrans8(0x06);//Write Enable
103   SETSS;  //Raise !SS to end transaction.
104 }
105
106
107 //! Grab the SPI flash status byte.
108 unsigned char spiflash_status(){
109   unsigned char c;
110   SETSS;  //Raise !SS to end transaction.
111   CLRSS; //Drop !SS to begin transaction.
112   spitrans8(0x05);//GET STATUS
113   c=spitrans8(0xFF);
114   SETSS;  //Raise !SS to end transaction.
115   return c;
116 }
117
118
119 //! Grab the SPI flash status byte.
120 void spiflash_setstatus(unsigned char c){
121   SETSS;
122   CLRSS; //Drop !SS to begin transaction.
123   spitrans8(0x01);//SET STATUS
124   spitrans8(c);
125   SETSS;  //Raise !SS to end transaction.
126   //return c;
127 }
128
129
130 //! Read a block to a buffer.
131 void spiflash_peekblock(unsigned long adr,
132                         unsigned char *buf,
133                         unsigned int len){
134   unsigned char i;
135
136   SETSS;
137   CLRSS; //Drop !SS to begin transaction.
138   spitrans8(0x03);//Flash Read Command
139
140   //Send address
141   spitrans8((adr&0xFF0000)>>16);
142   spitrans8((adr&0xFF00)>>8);
143   spitrans8(adr&0xFF);
144
145   for(i=0;i<len;i++)
146     buf[i]=spitrans8(0);
147   SETSS;  //Raise !SS to end transaction.
148 }
149
150 //! Read a block to a buffer.
151 void spiflash_pokeblock(unsigned long adr,
152                         unsigned char *buf,
153                         unsigned int len){
154   unsigned int i;
155
156   SETSS;
157
158   //if(len!=0x100)
159   //  debugstr("Non-standard block size.");
160
161   while(spiflash_status()&0x01);//minor performance impact
162
163   spiflash_setstatus(0x02);
164   spiflash_wrten();
165
166   //Are these necessary?
167   //spiflash_setstatus(0x02);
168   //spiflash_wrten();
169
170   CLRSS; //Drop !SS to begin transaction.
171   spitrans8(0x02); //Poke command.
172
173   //Send address
174   spitrans8((adr&0xFF0000)>>16);
175   spitrans8((adr&0xFF00)>>8);
176   spitrans8(adr&0xFF);
177
178   for(i=0;i<len;i++)
179     spitrans8(buf[i]);
180   SETSS;  //Raise !SS to end transaction.
181
182   while(spiflash_status()&0x01);//minor performance impact
183   return;
184 }
185
186
187 //! Write many blocks to the SPI Flash.
188 void spiflash_pokeblocks(unsigned long adr,
189                          unsigned char *buf,
190                          unsigned int len){
191   long off=0;//offset of this block
192   int blen;//length of this block
193   SETSS;
194
195   while(off<len){
196     //calculate block length
197     blen=(len-off>0x100?0x100:len-off);
198     //write the block
199     spiflash_pokeblock(adr+off,
200                        buf+off,
201                        blen);
202     //add offset
203     off+=blen;
204   }
205 }
206
207
208
209 //! Peek some blocks.
210 void spiflash_peek(unsigned char app,
211                    unsigned char verb,
212                    unsigned long len){
213   unsigned int i;
214   CLRSS; //Drop !SS to begin transaction.
215   spitrans8(0x03);//Flash Read Command
216   len=3;//write 3 byte pointer
217   for(i=0;i<len;i++)
218     spitrans8(cmddata[i]);
219
220   //Send reply header
221   len=0x1000;
222   txhead(app,verb,len);
223
224   while(len--)
225     serial_tx(spitrans8(0));
226
227   SETSS;  //Raise !SS to end transaction.
228 }
229
230
231 //! Erase a sector.
232 void spiflash_erasesector(unsigned long adr){
233   //debugstr("Erasing a 4kB sector.");
234
235   //Write enable.
236   spiflash_wrten();
237
238   //Begin
239   CLRSS;
240
241   //Second command.
242   spitrans8(0x20);
243   //Send address
244   spitrans8((adr&0xFF0000)>>16);
245   spitrans8((adr&0xFF00)>>8);
246   spitrans8(adr&0xFF);
247
248   SETSS;
249   while(spiflash_status()&0x01);//while busy
250   //debugstr("Erased.");
251 }
252
253
254 //! Wake an EM260 Radio
255 void em260_wake(){
256   //debugstr("Waking EM260.");
257   #define RST BIT6
258   P2DIR|=RST;
259   SETRST;
260   delay(1024);
261
262   CLRRST;//Wake chip.
263   while(P4IN&1);
264   SETRST;//Woken.
265   //debugstr("EM260 is now awake.");
266   delay(1024);  //DO NOT REMOVE, fails without.
267 }
268 //! Handle an EM260 exchange.
269 void spi_rw_em260(u8 app, u8 verb, u32 len){
270   unsigned long i;
271   u8 lastin;
272
273   P4DIR=0; //TODO ASAP remove P4 references.
274   P4OUT=0xFF;
275   //P4REN=0xFF;
276
277   //See GoodFETEM260.py for details.
278   //The EM260 requires that the host wait for the client.
279
280   /*
281     if((~P4IN)&1)
282     debugstr("Detected HOST_INT.");
283   */
284
285   em260_wake();
286
287
288   SETMOSI; //Autodetected SPI mode.
289   CLRSS; //Drop !SS to begin transaction.
290   //Host to slave.  Ignore data.
291   for(i=0;i<len;i++){
292     lastin=spitrans8(cmddata[i]);
293     if(lastin!=0xFF){
294       //debugstr("EM260 transmission interrupted.");
295       cmddata[0]=lastin;
296       goto response;
297     }
298   }
299   //debugstr("Finished transmission to EM260.");
300
301   //Wait for nHOST_INT to drop.
302   i=0xffff;
303
304   /*
305   while(P4IN&1
306         && --i
307         )
308     spitrans8(0xFF);
309   */
310   while((cmddata[0]=spitrans8(0xFF))==0xFF
311         && --i);
312
313   if(!i)
314     debugstr("Gave up on host interrupt.");
315
316  response:
317   len=1;
318   while(
319         (cmddata[len++]=spitrans8(0xFF))!=0xA7
320         );
321   if(cmddata[0]==0xFE)
322     while(len<cmddata[1]+3)
323       cmddata[len++]=spitrans8(0xFF);
324   SETSS;  //Raise !SS to end transaction.
325
326   txdata(app,verb,len);
327   return;
328 }
329
330 //! Handles a monitor command.
331 void spi_handle_fn( uint8_t const app,
332                                         uint8_t const verb,
333                                         uint32_t const len)
334 {
335         unsigned long i, l;
336
337         //Raise !SS to end transaction, just in case we forgot.
338         SETSS;
339         //spisetup();
340
341         switch(verb)
342         {
343         case READ:
344         case WRITE:
345                 CLRSS; //Drop !SS to begin transaction.
346                 for(i=0;i<len;i++)
347                 cmddata[i]=spitrans8(cmddata[i]);
348                 SETSS;  //Raise !SS to end transaction.
349                 txdata(app,verb,len);
350                 break;
351
352         case SPI_RW_EM260:  //SPI exchange with an EM260
353                 spi_rw_em260(app,verb,len);
354                 break;
355
356         case SPI_JEDEC://Grab 3-byte JEDEC ID.
357                 CLRSS; //Drop !SS to begin transaction.
358                 spitrans8(0x9f);
359                 l=3;  //Length is variable in some chips, 3 minimum.
360                 for(i = 0; i < l; i++)
361                         cmddata[i]=spitrans8(cmddata[i]);
362                 txdata(app,verb,len);
363                 SETSS;  //Raise !SS to end transaction.
364                 break;
365
366         case PEEK://Grab 128 bytes from an SPI Flash ROM
367                 spiflash_peek(app,verb,len);
368                 break;
369
370         case POKE://Poke up bytes from an SPI Flash ROM.
371                 spiflash_pokeblocks(cmddatalong[0],//adr
372                 cmddata+4,//buf
373                 len-4);//len
374                 txdata(app,verb,0);
375                 break;
376
377         case SPI_ERASE://Erase the SPI Flash ROM.
378                 spiflash_wrten();
379                 CLRSS; //Drop !SS to begin transaction.
380                 spitrans8(0xC7);//Chip Erase
381                 SETSS;  //Raise !SS to end transaction.
382
383                 while(spiflash_status()&0x01)//while busy
384                         led_toggle();
385                 led_off();
386
387                 txdata(app,verb,0);
388                 break;
389
390         case SETUP:
391                 spisetup();
392                 txdata(app,verb,0);
393                 break;
394         }
395 }