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