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