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