Rearranging firmware for use with Doxygen.
[goodfet] / firmware / apps / spi / spi.c
1 /*! \file spi.c
2   \author Travis Goodspeed
3   
4   This is an implementation of the SPI protocol
5   for the GoodFET project.
6 */
7
8 //Higher level left to client application.
9
10 #include "platform.h"
11 #include "command.h"
12
13 #include <signal.h>
14 #include <io.h>
15 #include <iomacros.h>
16
17 #include <spi.h>
18
19 //This could be more accurate.
20 //Does it ever need to be?
21 #define SPISPEED 0
22 #define SPIDELAY(x)
23 //delay(x)
24
25
26 //! Set up the pins for SPI mode.
27 void spisetup(){
28   P5OUT|=SS;
29   P5DIR|=MOSI+SCK+SS;
30   P5DIR&=~MISO;
31   
32   //Begin a new transaction.
33   P5OUT&=~SS; 
34   P5OUT|=SS;
35 }
36
37
38 //! Read and write an SPI byte.
39 unsigned char spitrans8(unsigned char byte){
40   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     /* half a clock cycle before leading/rising edge */
53     SPIDELAY(SPISPEED/2);
54     SETCLK;
55  
56     /* half a clock cycle before trailing/falling edge */
57     SPIDELAY(SPISPEED/2);
58  
59     /* read MISO on trailing edge */
60     byte |= READMISO;
61     CLRCLK;
62   }
63   
64   return byte;
65 }
66
67
68 //! Enable SPI writing
69 void spiflash_wrten(){
70   SETSS;
71   P5OUT&=~SS; //Drop !SS to begin transaction.
72   spitrans8(0x04);//Write Disable
73   P5OUT|=SS;  //Raise !SS to end transaction.
74   P5OUT&=~SS; //Drop !SS to begin transaction.
75   spitrans8(0x06);//Write Enable
76   P5OUT|=SS;  //Raise !SS to end transaction.
77 }
78
79
80 //! Grab the SPI flash status byte.
81 unsigned char spiflash_status(){
82   unsigned char c;
83   P5OUT|=SS;  //Raise !SS to end transaction.
84   P5OUT&=~SS; //Drop !SS to begin transaction.
85   spitrans8(0x05);//GET STATUS
86   c=spitrans8(0xFF);
87   P5OUT|=SS;  //Raise !SS to end transaction.
88   return c;
89 }
90
91
92 //! Grab the SPI flash status byte.
93 void spiflash_setstatus(unsigned char c){
94   SETSS;
95   CLRSS; //Drop !SS to begin transaction.
96   spitrans8(0x01);//SET STATUS
97   spitrans8(c);
98   SETSS;  //Raise !SS to end transaction.
99   //return c;
100 }
101
102
103 //! Read a block to a buffer.
104 void spiflash_peekblock(unsigned long adr,
105                         unsigned char *buf,
106                         unsigned int len){
107   unsigned char i;
108   
109   SETSS;
110   CLRSS; //Drop !SS to begin transaction.
111   spitrans8(0x03);//Flash Read Command
112   
113   //Send address
114   spitrans8((adr&0xFF0000)>>16);
115   spitrans8((adr&0xFF00)>>8);
116   spitrans8(adr&0xFF);
117   
118   for(i=0;i<len;i++)
119     buf[i]=spitrans8(0);
120   SETSS;  //Raise !SS to end transaction.
121 }
122
123
124 //! Read a block to a buffer.
125 void spiflash_pokeblock(unsigned long adr,
126                         unsigned char *buf,
127                         unsigned int len){
128   unsigned char i;
129   
130   SETSS;
131   
132   spiflash_setstatus(0x02);
133   spiflash_wrten();
134   
135   CLRSS; //Drop !SS to begin transaction.
136   spitrans8(0x02); //Poke command.
137   
138   //Send address
139   spitrans8((adr&0xFF0000)>>16);
140   spitrans8((adr&0xFF00)>>8);
141   spitrans8(adr&0xFF);
142
143   for(i=0;i<len;i++)
144     spitrans8(buf[i]);
145   SETSS;  //Raise !SS to end transaction.
146   
147   //while(spiflash_status()&0x01);
148   
149   return;
150 }
151
152
153 //! Peek some blocks.
154 void spiflash_peek(unsigned char app,
155                    unsigned char verb,
156                    unsigned char len){
157   register char blocks=(len>3?cmddata[3]:1);
158   unsigned char i;
159   
160   P5OUT&=~SS; //Drop !SS to begin transaction.
161   spitrans8(0x03);//Flash Read Command
162   len=3;//write 3 byte pointer
163   for(i=0;i<len;i++)
164     spitrans8(cmddata[i]);
165   
166   //Send reply header
167   len=0x80;//128 byte chunk, repeated for each block
168   serial_tx(app);
169   serial_tx(verb);
170   serial_tx(len); //multiplied by block count.
171   
172   while(blocks--){
173     for(i=0;i<len;i++)
174       serial_tx(spitrans8(0));
175     
176     /* old fashioned
177     for(i=0;i<len;i++)
178       cmddata[i]=spitrans8(0);
179     txdata(app,verb,len);
180     */
181   }
182   P5OUT|=SS;  //Raise !SS to end transaction.
183 }
184
185 //! Handles a monitor command.
186 void spihandle(unsigned char app,
187                unsigned char verb,
188                unsigned char len){
189   unsigned char i;
190   
191   //Raise !SS to end transaction, just in case we forgot.
192   P5OUT|=SS;
193   spisetup();
194   
195   switch(verb){
196     //PEEK and POKE might come later.
197   case READ:
198   case WRITE:
199     P5OUT&=~SS; //Drop !SS to begin transaction.
200     for(i=0;i<len;i++)
201       cmddata[i]=spitrans8(cmddata[i]);
202     P5OUT|=SS;  //Raise !SS to end transaction.
203     txdata(app,verb,len);
204     break;
205
206
207   case SPI_JEDEC://Grab 3-byte JEDEC ID.
208     P5OUT&=~SS; //Drop !SS to begin transaction.
209     spitrans8(0x9f);
210     len=3;
211     for(i=0;i<len;i++)
212       cmddata[i]=spitrans8(cmddata[i]);
213     txdata(app,verb,len);
214     P5OUT|=SS;  //Raise !SS to end transaction.
215     break;
216
217
218   case PEEK://Grab 128 bytes from an SPI Flash ROM
219     spiflash_peek(app,verb,len);
220     break;
221
222
223   case POKE://Poke up bytes from an SPI Flash ROM.
224     spiflash_setstatus(0x02);
225     spiflash_wrten();
226     
227     P5OUT&=~SS; //Drop !SS to begin transaction.
228     spitrans8(0x02); //Poke command.
229     
230     //First three bytes are address, then data.
231     for(i=0;i<len;i++)
232       spitrans8(cmddata[i]);
233     P5OUT|=SS;  //Raise !SS to end transaction.
234     
235     
236     while(spiflash_status()&0x01)//while busy
237       P1OUT^=1;
238     P1OUT&=~1;
239     
240     txdata(app,verb,len);
241     break;
242
243
244   case SPI_ERASE://Erase the SPI Flash ROM.
245     spiflash_wrten();
246     P5OUT&=~SS; //Drop !SS to begin transaction.
247     spitrans8(0xC7);//Chip Erase
248     P5OUT|=SS;  //Raise !SS to end transaction.
249     
250         
251     while(spiflash_status()&0x01)//while busy
252       P1OUT^=1;
253     P1OUT&=~1;
254     
255     txdata(app,verb,0);
256     break;
257
258   case SETUP:
259     spisetup();
260     txdata(app,verb,0);
261     break;
262   }
263   
264 }