Atmel JEDEC info for SPI Flash.
[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   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     /* half a clock cycle before leading/rising edge */
51     SPIDELAY(SPISPEED/2);
52     SETCLK;
53  
54     /* half a clock cycle before trailing/falling edge */
55     SPIDELAY(SPISPEED/2);
56  
57     /* read MISO on trailing edge */
58     byte |= READMISO;
59     CLRCLK;
60   }
61   
62   return byte;
63 }
64
65
66 //! Enable SPI writing
67 void spiflash_wrten(){
68   SETSS;
69   /*
70   P5OUT&=~SS; //Drop !SS to begin transaction.
71   spitrans8(0x04);//Write Disable
72   P5OUT|=SS;  //Raise !SS to end transaction.
73   */
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;  //Length is variable in some chips, 3 minimum.
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     
237     while(spiflash_status()&0x01)
238       P1OUT^=1;
239     
240     P1OUT&=~1;
241     
242     txdata(app,verb,len);
243     break;
244
245
246   case SPI_ERASE://Erase the SPI Flash ROM.
247     spiflash_wrten();
248     P5OUT&=~SS; //Drop !SS to begin transaction.
249     spitrans8(0xC7);//Chip Erase
250     P5OUT|=SS;  //Raise !SS to end transaction.
251     
252         
253     while(spiflash_status()&0x01)//while busy
254       P1OUT^=1;
255     P1OUT&=~1;
256     
257     txdata(app,verb,0);
258     break;
259
260   case SETUP:
261     spisetup();
262     txdata(app,verb,0);
263     break;
264   }
265   
266 }