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