USBasp 2007.10.23.
[pub/USBasp.git] / firmware / main.c
1 /*
2 USBasp - USB in-circuit programmer for Atmel AVR controllers
3
4 Thomas Fischl <tfischl@gmx.de>
5
6 License........: GNU GPL v2 (see Readme.txt)
7 Target.........: ATMega8 at 12 MHz
8 Creation Date..: 2005-02-20
9 Last change....: 2007-07-23
10
11 PC2 SCK speed option. GND -> slow (8khz SCK),
12 open -> fast (375kHz SCK)
13 */
14
15 #include <avr/io.h>
16 #include <avr/interrupt.h>
17 #include <avr/pgmspace.h>
18 #include <avr/wdt.h>
19
20 #include "usbdrv.h"
21 #include "isp.h"
22 #include "clock.h"
23
24 #define USBASP_FUNC_CONNECT 1
25 #define USBASP_FUNC_DISCONNECT 2
26 #define USBASP_FUNC_TRANSMIT 3
27 #define USBASP_FUNC_READFLASH 4
28 #define USBASP_FUNC_ENABLEPROG 5
29 #define USBASP_FUNC_WRITEFLASH 6
30 #define USBASP_FUNC_READEEPROM 7
31 #define USBASP_FUNC_WRITEEEPROM 8
32 #define USBASP_FUNC_SETLONGADDRESS 9
33
34 #define PROG_STATE_IDLE 0
35 #define PROG_STATE_WRITEFLASH 1
36 #define PROG_STATE_READFLASH 2
37 #define PROG_STATE_READEEPROM 3
38 #define PROG_STATE_WRITEEEPROM 4
39
40 #define PROG_BLOCKFLAG_FIRST 1
41 #define PROG_BLOCKFLAG_LAST 2
42
43 #define ledRedOn() PORTC &= ~(1 << PC1)
44 #define ledRedOff() PORTC |= (1 << PC1)
45 #define ledGreenOn() PORTC &= ~(1 << PC0)
46 #define ledGreenOff() PORTC |= (1 << PC0)
47
48 static uchar replyBuffer[8];
49
50 static uchar prog_state = PROG_STATE_IDLE;
51
52 static uchar prog_address_newmode = 0;
53 static unsigned long prog_address;
54 static unsigned int prog_nbytes = 0;
55 static unsigned int prog_pagesize;
56 static uchar prog_blockflags;
57 static uchar prog_pagecounter;
58
59
60 uchar usbFunctionSetup(uchar data[8]) {
61
62 uchar len = 0;
63
64 if(data[1] == USBASP_FUNC_CONNECT){
65
66 /* set SCK speed */
67 if ((PINC & (1 << PC2)) == 0) {
68 ispSetSCKOption(ISP_SCK_SLOW);
69 } else {
70 ispSetSCKOption(ISP_SCK_FAST);
71 }
72
73 /* set compatibility mode of address delivering */
74 prog_address_newmode = 0;
75
76 ledRedOn();
77 ispConnect();
78
79 } else if (data[1] == USBASP_FUNC_DISCONNECT) {
80 ispDisconnect();
81 ledRedOff();
82
83 } else if (data[1] == USBASP_FUNC_TRANSMIT) {
84 replyBuffer[0] = ispTransmit(data[2]);
85 replyBuffer[1] = ispTransmit(data[3]);
86 replyBuffer[2] = ispTransmit(data[4]);
87 replyBuffer[3] = ispTransmit(data[5]);
88 len = 4;
89
90 } else if (data[1] == USBASP_FUNC_READFLASH) {
91
92 if (!prog_address_newmode)
93 prog_address = (data[3] << 8) | data[2];
94
95 prog_nbytes = (data[7] << 8) | data[6];
96 prog_state = PROG_STATE_READFLASH;
97 len = 0xff; /* multiple in */
98
99 } else if (data[1] == USBASP_FUNC_READEEPROM) {
100
101 if (!prog_address_newmode)
102 prog_address = (data[3] << 8) | data[2];
103
104 prog_nbytes = (data[7] << 8) | data[6];
105 prog_state = PROG_STATE_READEEPROM;
106 len = 0xff; /* multiple in */
107
108 } else if (data[1] == USBASP_FUNC_ENABLEPROG) {
109 replyBuffer[0] = ispEnterProgrammingMode();;
110 len = 1;
111
112 } else if (data[1] == USBASP_FUNC_WRITEFLASH) {
113
114 if (!prog_address_newmode)
115 prog_address = (data[3] << 8) | data[2];
116
117 prog_pagesize = data[4];
118 prog_blockflags = data[5] & 0x0F;
119 prog_pagesize += (((unsigned int)data[5] & 0xF0)<<4);
120 if (prog_blockflags & PROG_BLOCKFLAG_FIRST) {
121 prog_pagecounter = prog_pagesize;
122 }
123 prog_nbytes = (data[7] << 8) | data[6];
124 prog_state = PROG_STATE_WRITEFLASH;
125 len = 0xff; /* multiple out */
126
127 } else if (data[1] == USBASP_FUNC_WRITEEEPROM) {
128
129 if (!prog_address_newmode)
130 prog_address = (data[3] << 8) | data[2];
131
132 prog_pagesize = 0;
133 prog_blockflags = 0;
134 prog_nbytes = (data[7] << 8) | data[6];
135 prog_state = PROG_STATE_WRITEEEPROM;
136 len = 0xff; /* multiple out */
137
138 } else if(data[1] == USBASP_FUNC_SETLONGADDRESS) {
139
140 /* set new mode of address delivering (ignore address delivered in commands) */
141 prog_address_newmode = 1;
142 /* set new address */
143 prog_address = *((unsigned long*)&data[2]);
144 }
145
146 usbMsgPtr = replyBuffer;
147
148 return len;
149 }
150
151
152 uchar usbFunctionRead(uchar *data, uchar len) {
153
154 uchar i;
155
156 /* check if programmer is in correct read state */
157 if ((prog_state != PROG_STATE_READFLASH) &&
158 (prog_state != PROG_STATE_READEEPROM)) {
159 return 0xff;
160 }
161
162 /* fill packet */
163 for (i = 0; i < len; i++) {
164 if (prog_state == PROG_STATE_READFLASH) {
165 data[i] = ispReadFlash(prog_address);
166 } else {
167 data[i] = ispReadEEPROM(prog_address);
168 }
169 prog_address++;
170 }
171
172 /* last packet? */
173 if (len < 8) {
174 prog_state = PROG_STATE_IDLE;
175 }
176
177 return len;
178 }
179
180
181 uchar usbFunctionWrite(uchar *data, uchar len) {
182
183 uchar retVal = 0;
184 uchar i;
185
186 /* check if programmer is in correct write state */
187 if ((prog_state != PROG_STATE_WRITEFLASH) &&
188 (prog_state != PROG_STATE_WRITEEEPROM)) {
189 return 0xff;
190 }
191
192
193 for (i = 0; i < len; i++) {
194
195 if (prog_state == PROG_STATE_WRITEFLASH) {
196 /* Flash */
197
198 if (prog_pagesize == 0) {
199 /* not paged */
200 ispWriteFlash(prog_address, data[i], 1);
201 } else {
202 /* paged */
203 ispWriteFlash(prog_address, data[i], 0);
204 prog_pagecounter --;
205 if (prog_pagecounter == 0) {
206 ispFlushPage(prog_address, data[i]);
207 prog_pagecounter = prog_pagesize;
208 }
209 }
210
211 } else {
212 /* EEPROM */
213 ispWriteEEPROM(prog_address, data[i]);
214 }
215
216 prog_nbytes --;
217
218 if (prog_nbytes == 0) {
219 prog_state = PROG_STATE_IDLE;
220 if ((prog_blockflags & PROG_BLOCKFLAG_LAST) &&
221 (prog_pagecounter != prog_pagesize)) {
222
223 /* last block and page flush pending, so flush it now */
224 ispFlushPage(prog_address, data[i]);
225 }
226
227 retVal = 1; // Need to return 1 when no more data is to be received
228 }
229
230 prog_address ++;
231 }
232
233 return retVal;
234 }
235
236
237 int main(void)
238 {
239 uchar i, j;
240
241 PORTD = 0;
242 PORTB = 0; /* no pullups on USB and ISP pins */
243 DDRD = ~(1 << 2); /* all outputs except PD2 = INT0 */
244
245 DDRB = ~0; /* output SE0 for USB reset */
246 j = 0;
247 while(--j){ /* USB Reset by device only required on Watchdog Reset */
248 i = 0;
249 while(--i); /* delay >10ms for USB reset */
250 }
251 DDRB = 0; /* all USB and ISP pins inputs */
252
253 DDRC = 0x03; /* all inputs except PC0, PC1 */
254 PORTC = 0xfe;
255
256 clockInit(); /* init timer */
257
258 ispSetSCKOption(ISP_SCK_FAST);
259
260 usbInit();
261 sei();
262 for(;;){ /* main event loop */
263 usbPoll();
264 }
265 return 0;
266 }