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