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