94fbf0e4d09fdf97ca46b9fdadd82844c76c7e0e
[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   P5OUT&=~SS; //Drop !SS to begin transaction.
70   spitrans8(0x04);//Write Disable
71   P5OUT|=SS;  //Raise !SS to end transaction.
72   P5OUT&=~SS; //Drop !SS to begin transaction.
73   spitrans8(0x06);//Write Enable
74   P5OUT|=SS;  //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   P5OUT|=SS;  //Raise !SS to end transaction.
82   P5OUT&=~SS; //Drop !SS to begin transaction.
83   spitrans8(0x05);//GET STATUS
84   c=spitrans8(0xFF);
85   P5OUT|=SS;  //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
122 //! Read a block to a buffer.
123 void spiflash_pokeblock(unsigned long adr,
124                         unsigned char *buf,
125                         unsigned int len){
126   unsigned char i;
127   
128   SETSS;
129   
130   spiflash_setstatus(0x02);
131   spiflash_wrten();
132   
133   CLRSS; //Drop !SS to begin transaction.
134   spitrans8(0x02); //Poke command.
135   
136   //Send address
137   spitrans8((adr&0xFF0000)>>16);
138   spitrans8((adr&0xFF00)>>8);
139   spitrans8(adr&0xFF);
140
141   for(i=0;i<len;i++)
142     spitrans8(buf[i]);
143   SETSS;  //Raise !SS to end transaction.
144   
145   //while(spiflash_status()&0x01);
146   
147   return;
148 }
149
150
151 //! Peek some blocks.
152 void spiflash_peek(unsigned char app,
153                    unsigned char verb,
154                    unsigned char len){
155   register char blocks=(len>3?cmddata[3]:1);
156   unsigned char i;
157   
158   P5OUT&=~SS; //Drop !SS to begin transaction.
159   spitrans8(0x03);//Flash Read Command
160   len=3;//write 3 byte pointer
161   for(i=0;i<len;i++)
162     spitrans8(cmddata[i]);
163   
164   //Send reply header
165   len=0x80;//128 byte chunk, repeated for each block
166   serial_tx(app);
167   serial_tx(verb);
168   serial_tx(len); //multiplied by block count.
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;
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     while(spiflash_status()&0x01)//while busy
235       P1OUT^=1;
236     P1OUT&=~1;
237     
238     txdata(app,verb,len);
239     break;
240
241
242   case SPI_ERASE://Erase the SPI Flash ROM.
243     spiflash_wrten();
244     P5OUT&=~SS; //Drop !SS to begin transaction.
245     spitrans8(0xC7);//Chip Erase
246     P5OUT|=SS;  //Raise !SS to end transaction.
247     
248         
249     while(spiflash_status()&0x01)//while busy
250       P1OUT^=1;
251     P1OUT&=~1;
252     
253     txdata(app,verb,0);
254     break;
255
256   case SETUP:
257     spisetup();
258     txdata(app,verb,0);
259     break;
260   }
261   
262 }