a8d9d341b82672cf199673e73c56cf610dd61d20
[goodfet] / firmware / apps / avr / avr.c
1 /*! \file avr.c
2   \author Travis Goodspeed
3   \brief AVR SPI Programmer
4 */
5
6 #include "platform.h"
7 #include "command.h"
8
9 #include <signal.h>
10 #include <io.h>
11 #include <iomacros.h>
12
13 #include "avr.h"
14
15 //! Setup the AVR pins.
16 void avrsetup(){
17   spisetup();
18 }
19
20 //! Initialized an attached AVR.
21 void avrconnect(){
22   //set I/O pins
23   avrsetup();
24   
25   //Pulse !RST (SS) at least twice while CLK is low.
26   CLRCLK;
27   CLRSS;
28
29   SETSS;
30   CLRCLK;
31   delay(500);
32   CLRSS;
33   delay(500);
34   
35   //Enable programming
36   avr_prgen();
37 }
38
39 //! Read and write an SPI byte with delays.
40 unsigned char avrtrans8(unsigned char byte){
41   register unsigned int bit;
42   //This function came from the SPI Wikipedia article.
43   //Minor alterations.
44   
45   for (bit = 0; bit < 8; bit++) {
46     /* write MOSI on trailing edge of previous clock */
47     if (byte & 0x80)
48       SETMOSI;
49     else
50       CLRMOSI;
51     byte <<= 1;
52     
53     delay(2);
54     SETCLK;
55   
56     /* read MISO on trailing edge */
57     byte |= READMISO;
58     delay(2);
59     CLRCLK;
60   }
61   
62   return byte;
63 }
64
65 //! Perform a 4-byte exchange.
66 u8 avrexchange(u8 a, u8 b, u8 c, u8 d){
67   avrtrans8(a);
68   avrtrans8(b);
69   if(avrtrans8(c)!=b){
70     debugstr("AVR sync error, b not returned as c.");
71     //Reconnect here?
72   }
73   return avrtrans8(d);
74 }
75
76 //! Enable AVR programming mode.
77 void avr_prgen(){
78   avrexchange(0xAC, 0x53, 0, 0);
79 }
80
81 //! Is the AVR ready or busy?
82 u8 avr_isready(){
83   return avrexchange(0xF0, 0, 0, 0);
84 }
85
86 //! Read AVR device code.
87 u8 avr_sig(u8 i){
88   return avrexchange(0x30, //Read signature byte
89               0x00,
90               i&0x03,      //sig adr
91               0x00         //don't care.
92               );
93 }
94
95 //! Erase an AVR device
96 void avr_erase(){
97   avrexchange(0xAC, 0x80, 0, 0);
98 }
99
100 //! Read lock bits.
101 u8 avr_lockbits(){
102   return avrexchange(0x58, 0, 0, 0);
103 }
104
105 //! Read a byte of EEPROM.
106 u8 avr_peekeeprom(u16 adr){
107   return avrexchange(0xA0, adr>>8, adr&0xFF, 0);
108 }
109 //! Read a byte of EEPROM.
110 u8 avr_pokeeeprom(u16 adr, u8 val){
111   return avrexchange(0xC0, adr>>8, adr&0xFF, val);
112 }
113
114 //! Read a byte of Flash
115 u8 avr_peekflash(u16 adr){
116   u16 a=adr>>1;
117   if(adr&1) //high byte
118     return avrexchange(0x28,a>>8,a&0xff,0);
119   else      //low byte
120     return avrexchange(0x20,a>>8,a&0xff,0);
121 }
122
123
124 //! Handles an AVR command.
125 void avrhandle(unsigned char app,
126                unsigned char verb,
127                unsigned long len){
128   unsigned long i;
129   unsigned int at;
130   static u8 connected=0;
131   
132   if(!avr_isready() && connected)
133     debugstr("AVR is not yet ready.");
134   
135   switch(verb){
136   case READ:
137   case WRITE:
138     for(i=0;i<len;i++)
139       cmddata[i]=avrtrans8(cmddata[i]);
140     txdata(app,verb,len);
141     break;
142   case SETUP:
143     avrsetup();
144     txdata(app,verb,0);
145     break;
146   case START://returns device code
147     avrconnect();
148     //no break here
149   case AVR_PEEKSIG:
150     for(i=0;i<4;i++)
151       cmddata[i]=avr_sig(i);
152     txdata(app,verb,4);
153     break;
154   case AVR_ERASE:
155     avr_erase();
156     txdata(app,verb,0);
157     break;
158   case AVR_PEEKLOCK:
159     cmddata[0]=avr_lockbits();
160     txdata(app,verb,1);
161     break;
162
163   case AVR_POKEEEPROM:
164     avr_pokeeeprom(cmddataword[0], cmddata[2]);
165     //no break here.
166   case AVR_PEEKEEPROM:
167     cmddata[0]=avr_peekeeprom(cmddataword[0]);
168     txdata(app,verb,1);
169     break;
170   case PEEK:
171     //cmddata[0]=avr_peekflash(cmddataword[0]);
172     //txdata(app,verb,1);
173     at=cmddataword[0];
174     
175     //Fetch large blocks for bulk fetches,
176     //small blocks for individual peeks.
177     if(len>2){
178       len=(cmddataword[1]);//always even.
179     }else{
180       len=1;
181     }
182     txhead(app,verb,len);
183     for(i=0;i<len;i++){
184       serial_tx(avr_peekflash(at++));
185     }
186     break;
187   case POKE:
188   default:
189     debugstr("Verb unimplemented in AVR application.");
190     txdata(app,NOK,0);
191     break;
192   }
193 }
194