Cleaned up EM260 code, about to fork into separate module.
[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   static int state=0;
242   unsigned long i;
243   u8 lastin;
244     
245   P4DIR=0; //TODO ASAP remove P4 references.
246   P4OUT=0xFF;
247   P4REN=0xFF;
248     
249   //See GoodFETEM260.py for details.
250   //The EM260 requires that the host wait for the client.
251     
252   /*
253     if((~P4IN)&1)
254     debugstr("Detected HOST_INT.");
255   */
256     
257   //if(!state++)
258   //if(state++&1)
259   em260_wake();
260   
261  em260woken:
262     
263   SETMOSI; //Autodetected SPI mode.
264   CLRSS; //Drop !SS to begin transaction.
265   //Host to slave.  Ignore data.
266   for(i=0;i<len;i++){
267     lastin=spitrans8(cmddata[i]);
268     if(lastin!=0xFF){
269       debugstr("Got a byte during transmission.  (Shouldn't happen with EM260.)");
270       debughex(lastin);
271     }
272   }
273   //debugstr("Finished transmission to EM260.");
274     
275   //Wait for nHOST_INT to drop.
276   i=0xffff;
277   
278   /*
279   while(P4IN&1
280         && --i
281         )
282     spitrans8(0xFF);
283   */
284   while((cmddata[0]=spitrans8(0xFF))==0xFF
285         && --i);
286   
287   if(!i)
288     debugstr("Gave up on host interrupt.");
289   
290   debugstr("Reading response.");
291   len=1;
292   while(
293         (cmddata[len++]=spitrans8(0xFF))!=0xA7
294         );
295   SETSS;  //Raise !SS to end transaction.
296   
297   
298   if(cmddata[0]==0x02){
299     debugstr("Aborted transaction. :(");
300     //goto em260woken;
301   }
302   
303   txdata(app,verb,len);
304   return;
305 }
306
307 //! Handles a monitor command.
308 void spihandle(unsigned char app,
309                unsigned char verb,
310                unsigned long len){
311   unsigned long i;
312   
313   
314   //Raise !SS to end transaction, just in case we forgot.
315   SETSS;
316   //spisetup();
317   
318   switch(verb){
319     //PEEK and POKE might come later.
320   case READ:
321   case WRITE:
322     CLRSS; //Drop !SS to begin transaction.
323     for(i=0;i<len;i++)
324       cmddata[i]=spitrans8(cmddata[i]);
325     SETSS;  //Raise !SS to end transaction.
326     txdata(app,verb,len);
327     break;
328     
329   case SPI_RW_EM260:  //SPI exchange with an EM260
330     spi_rw_em260(app,verb,len);
331     break;
332     
333   case SPI_JEDEC://Grab 3-byte JEDEC ID.
334     CLRSS; //Drop !SS to begin transaction.
335     spitrans8(0x9f);
336     len=3;  //Length is variable in some chips, 3 minimum.
337     for(i=0;i<len;i++)
338       cmddata[i]=spitrans8(cmddata[i]);
339     txdata(app,verb,len);
340     SETSS;  //Raise !SS to end transaction.
341     break;
342     
343   case PEEK://Grab 128 bytes from an SPI Flash ROM
344     spiflash_peek(app,verb,len);
345     break;
346
347
348   case POKE://Poke up bytes from an SPI Flash ROM.
349     spiflash_pokeblocks(cmddatalong[0],//adr
350                         cmddata+4,//buf
351                         len-4);//len    
352     
353     txdata(app,verb,0);
354     break;
355
356
357   case SPI_ERASE://Erase the SPI Flash ROM.
358     spiflash_wrten();
359     CLRSS; //Drop !SS to begin transaction.
360     spitrans8(0xC7);//Chip Erase
361     SETSS;  //Raise !SS to end transaction.
362     
363     
364     while(spiflash_status()&0x01)//while busy
365       PLEDOUT^=PLEDPIN;
366     PLEDOUT&=~PLEDPIN;
367     
368     txdata(app,verb,0);
369     break;
370
371   case SETUP:
372     spisetup();
373     txdata(app,verb,0);
374     break;
375   }
376   
377 }