d6d52567d943f3ee49521881a57bdde4b58e0726
[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   txhead(app,verb,len);
169   
170   while(blocks--){
171     for(i=0;i<len;i++)
172       serial_tx(spitrans8(0));
173     
174     /* old fashioned
175     for(i=0;i<len;i++)
176       cmddata[i]=spitrans8(0);
177     txdata(app,verb,len);
178     */
179   }
180   P5OUT|=SS;  //Raise !SS to end transaction.
181 }
182
183 //! Handles a monitor command.
184 void spihandle(unsigned char app,
185                unsigned char verb,
186                unsigned char len){
187   unsigned char i;
188   
189   //Raise !SS to end transaction, just in case we forgot.
190   P5OUT|=SS;
191   spisetup();
192   
193   switch(verb){
194     //PEEK and POKE might come later.
195   case READ:
196   case WRITE:
197     P5OUT&=~SS; //Drop !SS to begin transaction.
198     for(i=0;i<len;i++)
199       cmddata[i]=spitrans8(cmddata[i]);
200     P5OUT|=SS;  //Raise !SS to end transaction.
201     txdata(app,verb,len);
202     break;
203
204
205   case SPI_JEDEC://Grab 3-byte JEDEC ID.
206     P5OUT&=~SS; //Drop !SS to begin transaction.
207     spitrans8(0x9f);
208     len=3;  //Length is variable in some chips, 3 minimum.
209     for(i=0;i<len;i++)
210       cmddata[i]=spitrans8(cmddata[i]);
211     txdata(app,verb,len);
212     P5OUT|=SS;  //Raise !SS to end transaction.
213     break;
214
215
216   case PEEK://Grab 128 bytes from an SPI Flash ROM
217     spiflash_peek(app,verb,len);
218     break;
219
220
221   case POKE://Poke up bytes from an SPI Flash ROM.
222     spiflash_setstatus(0x02);
223     spiflash_wrten();
224     
225     P5OUT&=~SS;         //Drop !SS to begin transaction.
226     spitrans8(0x02);    //Poke command.
227     
228     //First three bytes are address, then data.
229     for(i=0;i<len;i++)
230       spitrans8(cmddata[i]);
231     P5OUT|=SS;          //Raise !SS to end transaction.
232     
233     
234     
235     while(spiflash_status()&0x01)
236       P1OUT^=1;
237     
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 }