Faster SPI Flash dumping, but it's a bit ugly.
[goodfet] / firmware / apps / spi / spi.c
1 //GoodFET SPI Application
2 //Handles basic I/O
3
4 //Higher level left to client application.
5
6 #include "platform.h"
7 #include "command.h"
8
9 #include <signal.h>
10 #include <io.h>
11 #include <iomacros.h>
12
13
14 //Pins and I/O
15 #define SS   BIT0
16 #define MOSI BIT1
17 #define MISO BIT2
18 #define SCK  BIT3
19
20 //This could be more accurate.
21 //Does it ever need to be?
22 #define SPISPEED 0
23 #define SPIDELAY(x) delay(x)
24
25 #define SETMOSI P5OUT|=MOSI
26 #define CLRMOSI P5OUT&=~MOSI
27 #define SETCLK P5OUT|=SCK
28 #define CLRCLK P5OUT&=~SCK
29 #define READMISO (P5IN&MISO?1:0)
30
31
32
33 //! Set up the pins for SPI mode.
34 void spisetup(){
35   P5OUT|=SS;
36   P5DIR|=MOSI+SCK+SS;
37   P5DIR&=~MISO;
38   
39   //Begin a new transaction.
40   P5OUT&=~SS; 
41   P5OUT|=SS;
42 }
43
44 //! Read and write an SPI bit.
45 unsigned char spitrans8(unsigned char byte){
46   unsigned int bit;
47   //This function came from the SPI Wikipedia article.
48   //Minor alterations.
49   
50   for (bit = 0; bit < 8; bit++) {
51     /* write MOSI on trailing edge of previous clock */
52     if (byte & 0x80)
53       SETMOSI;
54     else
55       CLRMOSI;
56     byte <<= 1;
57  
58     /* half a clock cycle before leading/rising edge */
59     SPIDELAY(SPISPEED/2);
60     SETCLK;
61  
62     /* half a clock cycle before trailing/falling edge */
63     SPIDELAY(SPISPEED/2);
64  
65     /* read MISO on trailing edge */
66     byte |= READMISO;
67     CLRCLK;
68   }
69   
70   return byte;
71 }
72
73 //! Enable SPI writing
74 void spiflash_wrten(){
75   P5OUT&=~SS; //Drop !SS to begin transaction.
76   spitrans8(0x04);//Write Disable
77   P5OUT|=SS;  //Raise !SS to end transaction.
78   P5OUT&=~SS; //Drop !SS to begin transaction.
79   spitrans8(0x06);//Write Enable
80   P5OUT|=SS;  //Raise !SS to end transaction.
81 }
82
83 //! Grab the SPI flash status byte.
84 unsigned char spiflash_status(){
85   unsigned char c;
86   P5OUT|=SS;  //Raise !SS to end transaction.
87   P5OUT&=~SS; //Drop !SS to begin transaction.
88   spitrans8(0x05);//GET STATUS
89   c=spitrans8(0xFF);
90   P5OUT|=SS;  //Raise !SS to end transaction.
91   return c;
92 }
93 //! Grab the SPI flash status byte.
94 void spiflash_setstatus(unsigned char c){
95   P5OUT&=~SS; //Drop !SS to begin transaction.
96   spitrans8(0x01);//SET STATUS
97   spitrans8(c);
98   P5OUT|=SS;  //Raise !SS to end transaction.
99   //return c;
100 }
101
102 //! Peek some blocks.
103 void spiflash_peek(unsigned char app,
104                    unsigned char verb,
105                    unsigned char len){
106   register char blocks=(len>3?cmddata[3]:1);
107   unsigned char i,j;
108   
109   P5OUT&=~SS; //Drop !SS to begin transaction.
110   spitrans8(0x03);//Flash Read Command
111   len=3;//write 3 byte pointer
112   for(i=0;i<len;i++)
113     spitrans8(cmddata[i]);
114   
115   //Send reply header
116   len=0x80;//128 byte chunk, repeated for each block
117   serial_tx(app);
118   serial_tx(verb);
119   serial_tx(len); //multiplied by block count.
120   
121   while(blocks--){
122     for(i=0;i<len;i++)
123       serial_tx(spitrans8(0));
124     
125     /* old fashioned
126     for(i=0;i<len;i++)
127       cmddata[i]=spitrans8(0);
128     txdata(app,verb,len);
129     */
130   }
131   P5OUT|=SS;  //Raise !SS to end transaction.
132 }
133
134 //! Handles a monitor command.
135 void spihandle(unsigned char app,
136                unsigned char verb,
137                unsigned char len){
138   unsigned char i;
139   
140   
141   //Raise !SS to end transaction, just in case we forgot.
142   P5OUT|=SS;  
143   
144   switch(verb){
145     //PEEK and POKE might come later.
146   case READ:
147   case WRITE:
148     P5OUT&=~SS; //Drop !SS to begin transaction.
149     for(i=0;i<len;i++)
150       cmddata[i]=spitrans8(cmddata[i]);
151     P5OUT|=SS;  //Raise !SS to end transaction.
152     txdata(app,verb,len);
153     break;
154   case SPI_JEDEC://Grab 3-byte JEDEC ID.
155     P5OUT&=~SS; //Drop !SS to begin transaction.
156     spitrans8(0x9f);
157     len=3;
158     for(i=0;i<len;i++)
159       cmddata[i]=spitrans8(cmddata[i]);
160     txdata(app,verb,len);
161     P5OUT|=SS;  //Raise !SS to end transaction.
162     break;
163   case PEEK://Grab 128 bytes from an SPI Flash ROM
164     
165     spiflash_peek(app,verb,len);
166     break;
167   case POKE://Poke up bytes from an SPI Flash ROM.
168     spiflash_setstatus(0x02);
169     spiflash_wrten();
170     
171     P5OUT&=~SS; //Drop !SS to begin transaction.
172     spitrans8(0x02); //Poke command.
173     
174     //First three bytes are address, then data.
175     for(i=0;i<len;i++)
176       spitrans8(cmddata[i]);
177     P5OUT|=SS;  //Raise !SS to end transaction.
178     while(spiflash_status()&0x01);//while busy
179     txdata(app,verb,len);
180     break;
181   case SPI_ERASE://Erase the SPI Flash ROM.
182     spiflash_wrten();
183     P5OUT&=~SS; //Drop !SS to begin transaction.
184     spitrans8(0xC7);//Chip Erase
185     P5OUT|=SS;  //Raise !SS to end transaction.
186     txdata(app,verb,0);
187     break;
188   case SETUP:
189     spisetup();
190     txdata(app,verb,0);
191     break;
192   }
193   
194 }