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