Rev Author Line No. Line
3471 miho 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 #include "tpi.h"
26 #include "tpi_defs.h"
27  
28 static uchar replyBuffer[8];
29  
30 static uchar prog_state = PROG_STATE_IDLE;
31 static uchar prog_sck = USBASP_ISP_SCK_AUTO;
32  
33 static uchar prog_address_newmode = 0;
34 static unsigned long prog_address;
35 static unsigned int prog_nbytes = 0;
36 static unsigned int prog_pagesize;
37 static uchar prog_blockflags;
38 static uchar prog_pagecounter;
39  
40 uchar usbFunctionSetup(uchar data[8]) {
41  
42 uchar len = 0;
43  
44 if (data[1] == USBASP_FUNC_CONNECT) {
45  
46 /* set SCK speed */
47 if ((PINC & (1 << PC2)) == 0) {
48 ispSetSCKOption(USBASP_ISP_SCK_8);
49 } else {
50 ispSetSCKOption(prog_sck);
51 }
52  
53 /* set compatibility mode of address delivering */
54 prog_address_newmode = 0;
55  
56 ledRedOn();
57 ispConnect();
58  
59 } else if (data[1] == USBASP_FUNC_DISCONNECT) {
60 ispDisconnect();
61 ledRedOff();
62  
63 } else if (data[1] == USBASP_FUNC_TRANSMIT) {
64 replyBuffer[0] = ispTransmit(data[2]);
65 replyBuffer[1] = ispTransmit(data[3]);
66 replyBuffer[2] = ispTransmit(data[4]);
67 replyBuffer[3] = ispTransmit(data[5]);
68 len = 4;
69  
70 } else if (data[1] == USBASP_FUNC_READFLASH) {
71  
72 if (!prog_address_newmode)
73 prog_address = (data[3] << 8) | data[2];
74  
75 prog_nbytes = (data[7] << 8) | data[6];
76 prog_state = PROG_STATE_READFLASH;
77 len = 0xff; /* multiple in */
78  
79 } else if (data[1] == USBASP_FUNC_READEEPROM) {
80  
81 if (!prog_address_newmode)
82 prog_address = (data[3] << 8) | data[2];
83  
84 prog_nbytes = (data[7] << 8) | data[6];
85 prog_state = PROG_STATE_READEEPROM;
86 len = 0xff; /* multiple in */
87  
88 } else if (data[1] == USBASP_FUNC_ENABLEPROG) {
89 replyBuffer[0] = ispEnterProgrammingMode();
90 len = 1;
91  
92 } else if (data[1] == USBASP_FUNC_WRITEFLASH) {
93  
94 if (!prog_address_newmode)
95 prog_address = (data[3] << 8) | data[2];
96  
97 prog_pagesize = data[4];
98 prog_blockflags = data[5] & 0x0F;
99 prog_pagesize += (((unsigned int) data[5] & 0xF0) << 4);
100 if (prog_blockflags & PROG_BLOCKFLAG_FIRST) {
101 prog_pagecounter = prog_pagesize;
102 }
103 prog_nbytes = (data[7] << 8) | data[6];
104 prog_state = PROG_STATE_WRITEFLASH;
105 len = 0xff; /* multiple out */
106  
107 } else if (data[1] == USBASP_FUNC_WRITEEEPROM) {
108  
109 if (!prog_address_newmode)
110 prog_address = (data[3] << 8) | data[2];
111  
112 prog_pagesize = 0;
113 prog_blockflags = 0;
114 prog_nbytes = (data[7] << 8) | data[6];
115 prog_state = PROG_STATE_WRITEEEPROM;
116 len = 0xff; /* multiple out */
117  
118 } else if (data[1] == USBASP_FUNC_SETLONGADDRESS) {
119  
120 /* set new mode of address delivering (ignore address delivered in commands) */
121 prog_address_newmode = 1;
122 /* set new address */
123 prog_address = *((unsigned long*) &data[2]);
124  
125 } else if (data[1] == USBASP_FUNC_SETISPSCK) {
126  
127 /* set sck option */
128 prog_sck = data[2];
129 replyBuffer[0] = 0;
130 len = 1;
131  
132 } else if (data[1] == USBASP_FUNC_TPI_CONNECT) {
133 tpi_dly_cnt = data[2] | (data[3] << 8);
134  
135 /* RST high */
136 ISP_OUT |= (1 << ISP_RST);
137 ISP_DDR |= (1 << ISP_RST);
138  
139 clockWait(3);
140  
141 /* RST low */
142 ISP_OUT &= ~(1 << ISP_RST);
143 ledRedOn();
144  
145 clockWait(16);
146 tpi_init();
147  
148 } else if (data[1] == USBASP_FUNC_TPI_DISCONNECT) {
149  
150 tpi_send_byte(TPI_OP_SSTCS(TPISR));
151 tpi_send_byte(0);
152  
153 clockWait(10);
154  
155 /* pulse RST */
156 ISP_OUT |= (1 << ISP_RST);
157 clockWait(5);
158 ISP_OUT &= ~(1 << ISP_RST);
159 clockWait(5);
160  
161 /* set all ISP pins inputs */
162 ISP_DDR &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI));
163 /* switch pullups off */
164 ISP_OUT &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI));
165  
166 ledRedOff();
167  
168 } else if (data[1] == USBASP_FUNC_TPI_RAWREAD) {
169 replyBuffer[0] = tpi_recv_byte();
170 len = 1;
171  
172 } else if (data[1] == USBASP_FUNC_TPI_RAWWRITE) {
173 tpi_send_byte(data[2]);
174  
175 } else if (data[1] == USBASP_FUNC_TPI_READBLOCK) {
176 prog_address = (data[3] << 8) | data[2];
177 prog_nbytes = (data[7] << 8) | data[6];
178 prog_state = PROG_STATE_TPI_READ;
179 len = 0xff; /* multiple in */
180  
181 } else if (data[1] == USBASP_FUNC_TPI_WRITEBLOCK) {
182 prog_address = (data[3] << 8) | data[2];
183 prog_nbytes = (data[7] << 8) | data[6];
184 prog_state = PROG_STATE_TPI_WRITE;
185 len = 0xff; /* multiple out */
186  
187 } else if (data[1] == USBASP_FUNC_GETCAPABILITIES) {
188 replyBuffer[0] = USBASP_CAP_0_TPI;
189 replyBuffer[1] = 0;
190 replyBuffer[2] = 0;
191 replyBuffer[3] = 0;
192 len = 4;
193 }
194  
195 usbMsgPtr = replyBuffer;
196  
197 return len;
198 }
199  
200 uchar usbFunctionRead(uchar *data, uchar len) {
201  
202 uchar i;
203  
204 /* check if programmer is in correct read state */
205 if ((prog_state != PROG_STATE_READFLASH) && (prog_state
206 != PROG_STATE_READEEPROM) && (prog_state != PROG_STATE_TPI_READ)) {
207 return 0xff;
208 }
209  
210 /* fill packet TPI mode */
211 if(prog_state == PROG_STATE_TPI_READ)
212 {
213 tpi_read_block(prog_address, data, len);
214 prog_address += len;
215 return len;
216 }
217  
218 /* fill packet ISP mode */
219 for (i = 0; i < len; i++) {
220 if (prog_state == PROG_STATE_READFLASH) {
221 data[i] = ispReadFlash(prog_address);
222 } else {
223 data[i] = ispReadEEPROM(prog_address);
224 }
225 prog_address++;
226 }
227  
228 /* last packet? */
229 if (len < 8) {
230 prog_state = PROG_STATE_IDLE;
231 }
232  
233 return len;
234 }
235  
236 uchar usbFunctionWrite(uchar *data, uchar len) {
237  
238 uchar retVal = 0;
239 uchar i;
240  
241 /* check if programmer is in correct write state */
242 if ((prog_state != PROG_STATE_WRITEFLASH) && (prog_state
243 != PROG_STATE_WRITEEEPROM) && (prog_state != PROG_STATE_TPI_WRITE)) {
244 return 0xff;
245 }
246  
247 if (prog_state == PROG_STATE_TPI_WRITE)
248 {
249 tpi_write_block(prog_address, data, len);
250 prog_address += len;
251 prog_nbytes -= len;
252 if(prog_nbytes <= 0)
253 {
254 prog_state = PROG_STATE_IDLE;
255 return 1;
256 }
257 return 0;
258 }
259  
260 for (i = 0; i < len; i++) {
261  
262 if (prog_state == PROG_STATE_WRITEFLASH) {
263 /* Flash */
264  
265 if (prog_pagesize == 0) {
266 /* not paged */
267 ispWriteFlash(prog_address, data[i], 1);
268 } else {
269 /* paged */
270 ispWriteFlash(prog_address, data[i], 0);
271 prog_pagecounter--;
272 if (prog_pagecounter == 0) {
273 ispFlushPage(prog_address, data[i]);
274 prog_pagecounter = prog_pagesize;
275 }
276 }
277  
278 } else {
279 /* EEPROM */
280 ispWriteEEPROM(prog_address, data[i]);
281 }
282  
283 prog_nbytes--;
284  
285 if (prog_nbytes == 0) {
286 prog_state = PROG_STATE_IDLE;
287 if ((prog_blockflags & PROG_BLOCKFLAG_LAST) && (prog_pagecounter
288 != prog_pagesize)) {
289  
290 /* last block and page flush pending, so flush it now */
291 ispFlushPage(prog_address, data[i]);
292 }
293  
294 retVal = 1; // Need to return 1 when no more data is to be received
295 }
296  
297 prog_address++;
298 }
299  
300 return retVal;
301 }
302  
303 int main(void) {
304 uchar i, j;
305  
306 /* no pullups on USB and ISP pins */
307 PORTD = 0;
308 PORTB = 0;
309 /* all outputs except PD2 = INT0 */
310 DDRD = ~(1 << 2);
311  
312 /* output SE0 for USB reset */
313 DDRB = ~0;
314 j = 0;
315 /* USB Reset by device only required on Watchdog Reset */
316 while (--j) {
317 i = 0;
318 /* delay >10ms for USB reset */
319 while (--i)
320 ;
321 }
322 /* all USB and ISP pins inputs */
323 DDRB = 0;
324  
325 /* all inputs except PC0, PC1 */
326 DDRC = 0x03;
327 PORTC = 0xfe;
328  
329 /* init timer */
330 clockInit();
331  
332 /* main event loop */
333 usbInit();
334 sei();
335 for (;;) {
336 usbPoll();
337 }
338 return 0;
339 }
340