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