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