f02d4022146479c4622f2edf15c5f23a3bfe36f5
[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   P5OUT|=SS;
27   P5DIR|=MOSI+SCK+SS;
28   P5DIR&=~MISO;
29   
30   //Begin a new transaction.
31   P5OUT&=~SS; 
32   P5OUT|=SS;
33 }
34
35
36 //! Read and write an SPI byte.
37 unsigned char spitrans8(unsigned char byte){
38   register unsigned int bit;
39   //This function came from the SPI Wikipedia article.
40   //Minor alterations.
41   
42   for (bit = 0; bit < 8; bit++) {
43     /* write MOSI on trailing edge of previous clock */
44     if (byte & 0x80)
45       SETMOSI;
46     else
47       CLRMOSI;
48     byte <<= 1;
49  
50     SETCLK;
51   
52     /* read MISO on trailing edge */
53     byte |= READMISO;
54     CLRCLK;
55   }
56   
57   return byte;
58 }
59
60
61 //! Enable SPI writing
62 void spiflash_wrten(){
63   SETSS;
64   /*
65   P5OUT&=~SS; //Drop !SS to begin transaction.
66   spitrans8(0x04);//Write Disable
67   P5OUT|=SS;  //Raise !SS to end transaction.
68   */
69   P5OUT&=~SS; //Drop !SS to begin transaction.
70   spitrans8(0x06);//Write Enable
71   P5OUT|=SS;  //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   P5OUT|=SS;  //Raise !SS to end transaction.
79   P5OUT&=~SS; //Drop !SS to begin transaction.
80   spitrans8(0x05);//GET STATUS
81   c=spitrans8(0xFF);
82   P5OUT|=SS;  //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 //! Write many blocks to the SPI Flash.
119 void spiflash_pokeblocks(unsigned long adr,
120                          unsigned char *buf,
121                          unsigned int len){
122   long off=0;//offset of this block
123   int blen;//length of this block
124   SETSS;
125   spiflash_setstatus(0x02);
126   spiflash_wrten();
127   
128   while(off<len){
129     //calculate block length
130     blen=(len-off>0x100?0x100:len-off);
131     //write the block
132     spiflash_pokeblock(adr+off,
133                        buf+off,
134                        blen);
135     //add offset
136     off+=blen;
137   }
138 }
139
140 //! Read a block to a buffer.
141 void spiflash_pokeblock(unsigned long adr,
142                         unsigned char *buf,
143                         unsigned int len){
144   unsigned int i;
145   
146   SETSS;
147   
148   //while(spiflash_status()&0x01);//minor performance impact
149   
150   //Are these necessary?
151   //spiflash_setstatus(0x02);
152   //spiflash_wrten();
153   
154   CLRSS; //Drop !SS to begin transaction.
155   spitrans8(0x02); //Poke command.
156   
157   //Send address
158   spitrans8((adr&0xFF0000)>>16);
159   spitrans8((adr&0xFF00)>>8);
160   spitrans8(adr&0xFF);
161
162   for(i=0;i<len;i++)
163     spitrans8(buf[i]);
164   SETSS;  //Raise !SS to end transaction.
165   
166   while(spiflash_status()&0x01);//minor performance impact
167   return;
168 }
169
170
171 //! Peek some blocks.
172 void spiflash_peek(unsigned char app,
173                    unsigned char verb,
174                    unsigned long len){
175   unsigned int i;
176   P5OUT&=~SS; //Drop !SS to begin transaction.
177   spitrans8(0x03);//Flash Read Command
178   len=3;//write 3 byte pointer
179   for(i=0;i<len;i++)
180     spitrans8(cmddata[i]);
181   
182   //Send reply header
183   len=0x1000;
184   txhead(app,verb,len);
185   
186   while(len--)
187     serial_tx(spitrans8(0));
188   
189   P5OUT|=SS;  //Raise !SS to end transaction.
190 }
191
192 //! Handles a monitor command.
193 void spihandle(unsigned char app,
194                unsigned char verb,
195                unsigned long len){
196   unsigned long i;
197   
198   //Raise !SS to end transaction, just in case we forgot.
199   P5OUT|=SS;
200   spisetup();
201   
202   switch(verb){
203     //PEEK and POKE might come later.
204   case READ:
205   case WRITE:
206     P5OUT&=~SS; //Drop !SS to begin transaction.
207     for(i=0;i<len;i++)
208       cmddata[i]=spitrans8(cmddata[i]);
209     P5OUT|=SS;  //Raise !SS to end transaction.
210     txdata(app,verb,len);
211     break;
212
213
214   case SPI_JEDEC://Grab 3-byte JEDEC ID.
215     P5OUT&=~SS; //Drop !SS to begin transaction.
216     spitrans8(0x9f);
217     len=3;  //Length is variable in some chips, 3 minimum.
218     for(i=0;i<len;i++)
219       cmddata[i]=spitrans8(cmddata[i]);
220     txdata(app,verb,len);
221     P5OUT|=SS;  //Raise !SS to end transaction.
222     break;
223
224
225   case PEEK://Grab 128 bytes from an SPI Flash ROM
226     spiflash_peek(app,verb,len);
227     break;
228
229
230   case POKE://Poke up bytes from an SPI Flash ROM.
231     spiflash_pokeblocks(cmddatalong[0],//adr
232                         cmddata+4,//buf
233                         len-4);//len    
234     
235     txdata(app,verb,len);
236     break;
237
238
239   case SPI_ERASE://Erase the SPI Flash ROM.
240     spiflash_wrten();
241     P5OUT&=~SS; //Drop !SS to begin transaction.
242     spitrans8(0xC7);//Chip Erase
243     P5OUT|=SS;  //Raise !SS to end transaction.
244     
245     
246     while(spiflash_status()&0x01)//while busy
247       P1OUT^=1;
248     P1OUT&=~1;
249     
250     txdata(app,verb,0);
251     break;
252
253   case SETUP:
254     spisetup();
255     txdata(app,verb,0);
256     break;
257   }
258   
259 }