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