2 * Project: USBaspLoader
3 * Author: Christian Starkjohann
4 * Author: Stephan Baerwolf
5 * Creation Date: 2007-12-08
6 * Modification Date: 2013-03-31
8 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
9 * License: GNU GPL v2 (see License.txt)
12 #include "spminterface.h" /* must be included as first! */
14 #include "../misc/iofixes.h"
16 #include <avr/interrupt.h>
17 #include <avr/pgmspace.h>
20 #include <avr/eeprom.h>
21 #include <util/delay.h>
26 * 29.09.2012 / 30.09.2012
28 * Since cpufunc.h is not needed in this context and
29 * since it is not available in all toolchains, this include
30 * becomes deactivated by github issue-report.
31 * (In case of trouble it remains in sourcecode for reactivation.)
33 * The autor would like to thank Lena-M for reporting this
34 * issue (https://github.com/baerwolf/USBaspLoader/issues/1).
36 #include <avr/cpufunc.h>
45 #include "bootloaderconfig.h"
46 #include "usbdrv/usbdrv.c"
48 #ifndef BOOTLOADER_ADDRESS
49 #error need to know the bootloaders flash address!
51 #define BOOTLOADER_PAGEADDR (BOOTLOADER_ADDRESS - (BOOTLOADER_ADDRESS % SPM_PAGESIZE))
53 /* ------------------------------------------------------------------------ */
55 /* Request constants used by USBasp */
56 #define USBASP_FUNC_CONNECT 1
57 #define USBASP_FUNC_DISCONNECT 2
58 #define USBASP_FUNC_TRANSMIT 3
59 #define USBASP_FUNC_READFLASH 4
60 #define USBASP_FUNC_ENABLEPROG 5
61 #define USBASP_FUNC_WRITEFLASH 6
62 #define USBASP_FUNC_READEEPROM 7
63 #define USBASP_FUNC_WRITEEEPROM 8
64 #define USBASP_FUNC_SETLONGADDRESS 9
66 // additional USBasp Commands
67 #define USBASP_FUNC_SETISPSCK 10
68 #define USBASP_FUNC_TPI_CONNECT 11
69 #define USBASP_FUNC_TPI_DISCONNECT 12
70 #define USBASP_FUNC_TPI_RAWREAD 13
71 #define USBASP_FUNC_TPI_RAWWRITE 14
72 #define USBASP_FUNC_TPI_READBLOCK 15
73 #define USBASP_FUNC_TPI_WRITEBLOCK 16
74 #define USBASP_FUNC_GETCAPABILITIES 127
75 /* ------------------------------------------------------------------------ */
78 # define ulong unsigned long
81 # define uint unsigned int
85 /* allow compatibility with avrusbboot's bootloaderconfig.h: */
86 #ifdef BOOTLOADER_INIT
87 # define bootLoaderInit() BOOTLOADER_INIT
88 # define bootLoaderExit()
90 #ifdef BOOTLOADER_CONDITION
91 # define bootLoaderCondition() BOOTLOADER_CONDITION
94 /* device compatibility: */
95 #ifndef GICR /* ATMega*8 don't have GICR, use MCUCR instead */
99 /* ------------------------------------------------------------------------ */
101 #if (FLASHEND) > 0xffff /* we need long addressing */
102 # define CURRENT_ADDRESS currentAddress.l
103 # define addr_t ulong
105 # define CURRENT_ADDRESS currentAddress.w[0]
109 typedef union longConverter
{
111 uint w
[sizeof(addr_t
)/2];
112 uchar b
[sizeof(addr_t
)];
116 #if (BOOTLOADER_CAN_EXIT)
117 # if (BOOTLOADER_LOOPCYCLES_TIMEOUT)
118 # if (BOOTLOADER_LOOPCYCLES_TIMEOUT < 256)
119 # if ((HAVE_UNPRECISEWAIT))
120 volatile register uint8_t timeout_remaining
__asm__("r2");
122 static volatile uint8_t timeout_remaining
;
125 static volatile uint16_t timeout_remaining
;
129 # define stayinloader_initialValue 0xfe
130 # if ((HAVE_UNPRECISEWAIT))
131 /* here we have to assume we need to optimize for every byte */
132 volatile register uint8_t stayinloader
__asm__("r17");
134 static volatile uint8_t stayinloader
;
138 static longConverter_t currentAddress
; /* in bytes */
139 static uchar bytesRemaining
;
140 static uchar isLastPage
;
141 #if HAVE_EEPROM_PAGED_ACCESS
142 static uchar currentRequest
;
144 static const uchar currentRequest
= 0;
147 static const uchar signatureBytes
[4] = {
148 #ifdef SIGNATURE_BYTES
150 #elif defined (__AVR_ATmega8535__)
152 #elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__)
154 #elif defined (__AVR_ATmega16__)
156 #elif defined (__AVR_ATmega32__)
158 #elif defined (__AVR_ATmega48__) || defined (__AVR_ATmega48A__) || defined (__AVR_ATmega48P__)
159 #error ATmega48 does not support bootloaders!
161 #elif defined (__AVR_ATmega48PA__)
162 #error ATmega48 does not support bootloaders!
164 #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega88A__) || defined (__AVR_ATmega88P__)
166 #elif defined (__AVR_ATmega88PA__)
168 #elif defined (__AVR_ATmega162__)
170 #elif defined (__AVR_ATmega164A__)
172 #elif defined (__AVR_ATmega164P__) || defined (__AVR_ATmega164PA__)
174 #elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168P__)
176 #elif defined (__AVR_ATmega168PA__)
178 #elif defined (__AVR_ATmega324A__)
180 #elif defined (__AVR_ATmega324P__)
182 #elif defined (__AVR_ATmega324PA__)
184 #elif defined (__AVR_ATmega328__)
186 #elif defined (__AVR_ATmega328P__)
188 #elif defined (__AVR_ATmega640__)
190 #elif defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__)
192 #elif defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__)
194 #elif defined (__AVR_ATmega128__)
196 #elif defined (__AVR_ATmega1280__)
198 #elif defined (__AVR_ATmega1281__)
200 #elif defined (__AVR_ATmega1284__)
202 #elif defined (__AVR_ATmega1284P__)
204 #elif defined (__AVR_ATmega2560__)
206 #elif defined (__AVR_ATmega2561__)
209 # if (defined(SIGNATURE_0) && defined(SIGNATURE_1) && defined(SIGNATURE_2))
210 # warning "Device signature is not known - using AVR Libc suggestion..."
211 SIGNATURE_0
, SIGNATURE_1
, SIGNATURE_2
, 0
213 # error "Device signature is not known, please edit main.c!"
218 /* ------------------------------------------------------------------------ */
220 #if (HAVE_BOOTLOADERENTRY_FROMSOFTWARE)
221 void __attribute__ ((section(".init3"),naked
,used
,no_instrument_function
)) __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND(void);
222 void __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND(void) {
224 "in %[mcucsrval] , %[mcucsrio]\n\t"
225 "ldi r29 , %[ramendhi]\n\t"
226 "ldi r28 , %[ramendlo]\n\t"
227 #if (FLASHEND>131071)
228 "ld %[result] , Y+\n\t"
229 "cpi %[result] , %[bootaddrhi]\n\t"
230 "brne __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_mismatch%=\n\t"
232 "ld %[result] , Y+\n\t"
233 "cpi %[result] , %[bootaddrme]\n\t"
234 "ld %[result] , Y+\n\t"
235 "breq __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_done%=\n\t"
237 "__BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_mismatch%=:\n\t"
238 "ldi %[result] , 0xff\n\t"
240 "__BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_done%=:\n\t"
241 : [result
] "=a" (__BOOTLOADERENTRY_FROMSOFTWARE__bootup_RAMEND_doesmatch
),
242 [mcucsrval
] "=a" (__BOOTLOADERENTRY_FROMSOFTWARE__bootup_MCUCSR
)
243 : [mcucsrio
] "I" (_SFR_IO_ADDR(MCUCSR
)),
244 #if (FLASHEND>131071)
245 [ramendhi
] "M" (((RAMEND
- 2) >> 8) & 0xff),
246 [ramendlo
] "M" (((RAMEND
- 2) >> 0) & 0xff),
247 [bootaddrhi
] "M" (((__BOOTLOADERENTRY_FROMSOFTWARE__EXPECTEDADDRESS
) >>16) & 0xff),
249 [ramendhi
] "M" (((RAMEND
- 1) >> 8) & 0xff),
250 [ramendlo
] "M" (((RAMEND
- 1) >> 0) & 0xff),
252 [bootaddrme
] "M" (((__BOOTLOADERENTRY_FROMSOFTWARE__EXPECTEDADDRESS
) >> 8) & 0xff)
258 #if (USE_BOOTUP_CLEARRAM)
260 * Under normal circumstances, RESET will not clear contents of RAM.
261 * As always, if you want it done - do it yourself...
263 void __attribute__ ((section(".init3"),naked
,used
,no_instrument_function
)) __func_clearram(void);
264 void __func_clearram(void) {
265 extern size_t __bss_end
;
268 #if (!(HAVE_BOOTLOADERENTRY_FROMSOFTWARE))
269 "ldi r29, %[ramendhi]\n\t"
270 "ldi r28, %[ramendlo]\n\t"
272 "__clearramloop%=:\n\t"
273 "st -Y , __zero_reg__\n\t"
274 "cp r28, %A[bssend]\n\t"
275 "cpc r29, %B[bssend]\n\t"
276 "brne __clearramloop%=\n\t"
278 : [ramendhi
] "M" (((RAMEND
+1)>>8) & 0xff),
279 [ramendlo
] "M" (((RAMEND
+1)>>0) & 0xff),
280 [bssend
] "r" (&__bss_end
)
286 #if (!USE_EXCESSIVE_ASSEMBLER) || (!(defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__)))
287 static void (*nullVector
)(void) __attribute__((__noreturn__
));
290 #if (USE_EXCESSIVE_ASSEMBLER) && (defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__))
291 static void __attribute__((naked
,__noreturn__
)) leaveBootloader(void);
292 static void leaveBootloader(void) {
295 "sbi %[usbddr], %[usbminus]\n\t"
296 "cbi %[port], %[bit]\n\t"
297 "out %[usbintrenab], __zero_reg__\n\t"
298 "out %[usbintrcfg], __zero_reg__\n\t"
299 "ldi r31, %[ivce]\n\t"
300 "out %[mygicr], r31\n\t"
301 "out %[mygicr], __zero_reg__\n\t"
302 "rjmp nullVector\n\t"
304 : [port
] "I" (_SFR_IO_ADDR(PIN_PORT(JUMPER_PORT
))),
305 [bit
] "I" (PIN(JUMPER_PORT
, JUMPER_BIT
)),
306 [usbintrenab
] "I" (_SFR_IO_ADDR(USB_INTR_ENABLE
)),
307 [usbintrcfg
] "I" (_SFR_IO_ADDR(USB_INTR_CFG
)),
308 [usbddr
] "I" (_SFR_IO_ADDR(USBDDR
)),
309 [usbminus
] "I" (USBMINUS
),
310 [mygicr
] "I" (_SFR_IO_ADDR(GICR
)),
315 static void __attribute__((__noreturn__
)) leaveBootloader(void);
316 static void leaveBootloader(void) {
319 usbDeviceDisconnect();
322 USB_INTR_CFG
= 0; /* also reset config bits */
323 GICR
= (1 << IVCE
); /* enable change of interrupt vectors */
324 GICR
= (0 << IVSEL
); /* move interrupts to application flash section */
327 * There seems to be another funny compiler Bug.
328 * When gcc is using "eicall" opcode it forgets to modify EIND.
329 * On devices with large flash memory there are some target address bits
330 * missing. In this case some zero bits...
332 #if (defined(EIND) && ((FLASHEND)>131071))
335 /* We must go through a global function pointer variable instead of writing
336 * ((void (*)(void))0)();
337 * because the compiler optimizes a constant 0 to "rcall 0" which is not
338 * handled correctly by the assembler.
344 /* ------------------------------------------------------------------------ */
347 uchar
usbFunctionSetup_USBASP_FUNC_TRANSMIT(usbRequest_t
*rq
) {
350 address
.bytes
[1] = rq
->wValue
.bytes
[1];
351 address
.bytes
[0] = rq
->wIndex
.bytes
[0];
353 if(rq
->wValue
.bytes
[0] == 0x30){ /* read signature */
354 rval
= rq
->wIndex
.bytes
[0] & 3;
355 rval
= signatureBytes
[rval
];
356 #if HAVE_READ_LOCK_FUSE
357 #if defined (__AVR_ATmega8535__) || \
358 defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || \
359 defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__)
360 }else if(rq
->wValue
.bytes
[0] == 0x58 && rq
->wValue
.bytes
[1] == 0x00){ /* read lock bits */
361 rval
= boot_lock_fuse_bits_get(GET_LOCK_BITS
);
362 }else if(rq
->wValue
.bytes
[0] == 0x50 && rq
->wValue
.bytes
[1] == 0x00){ /* read lfuse bits */
363 rval
= boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS
);
364 }else if(rq
->wValue
.bytes
[0] == 0x58 && rq
->wValue
.bytes
[1] == 0x08){ /* read hfuse bits */
365 rval
= boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS
);
367 #elif defined (__AVR_ATmega48__) || defined (__AVR_ATmega48A__) || defined (__AVR_ATmega48P__) || defined (__AVR_ATmega48PA__) || \
368 defined (__AVR_ATmega88__) || defined (__AVR_ATmega88A__) || defined (__AVR_ATmega88P__) || defined (__AVR_ATmega88PA__) || \
369 defined (__AVR_ATmega162__) || \
370 defined (__AVR_ATmega164A__) || defined (__AVR_ATmega164P__) || \
371 defined (__AVR_ATmega168__) || defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168P__) || defined (__AVR_ATmega168PA__) || \
372 defined (__AVR_ATmega324A__) || defined (__AVR_ATmega324P__) || \
373 defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__) || \
374 defined (__AVR_ATmega640__) || \
375 defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__) || \
376 defined (__AVR_ATmega128__) || \
377 defined (__AVR_ATmega1280__) || \
378 defined (__AVR_ATmega1281__) || \
379 defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__) || \
380 defined (__AVR_ATmega2560__) || \
381 defined (__AVR_ATmega2561__)
382 }else if(rq
->wValue
.bytes
[0] == 0x58 && rq
->wValue
.bytes
[1] == 0x00){ /* read lock bits */
383 rval
= boot_lock_fuse_bits_get(GET_LOCK_BITS
);
384 }else if(rq
->wValue
.bytes
[0] == 0x50 && rq
->wValue
.bytes
[1] == 0x00){ /* read lfuse bits */
385 rval
= boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS
);
386 }else if(rq
->wValue
.bytes
[0] == 0x58 && rq
->wValue
.bytes
[1] == 0x08){ /* read hfuse bits */
387 rval
= boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS
);
388 }else if(rq
->wValue
.bytes
[0] == 0x50 && rq
->wValue
.bytes
[1] == 0x08){ /* read efuse bits */
389 rval
= boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS
);
391 #warning "HAVE_READ_LOCK_FUSE is activated but MCU unknown -> will not support this feature"
394 #if HAVE_FLASH_BYTE_READACCESS
395 }else if(rq
->wValue
.bytes
[0] == 0x20){ /* read FLASH low byte */
396 #if ((FLASHEND) > 65535)
397 rval
= pgm_read_byte_far((((addr_t
)address
.word
)<<1)+0);
399 rval
= pgm_read_byte((((addr_t
)address
.word
)<<1)+0);
401 }else if(rq
->wValue
.bytes
[0] == 0x28){ /* read FLASH high byte */
402 #if ((FLASHEND) > 65535)
403 rval
= pgm_read_byte_far((((addr_t
)address
.word
)<<1)+1);
405 rval
= pgm_read_byte((((addr_t
)address
.word
)<<1)+1);
408 #if HAVE_EEPROM_BYTE_ACCESS
409 }else if(rq
->wValue
.bytes
[0] == 0xa0){ /* read EEPROM byte */
410 rval
= eeprom_read_byte((void *)address
.word
);
411 }else if(rq
->wValue
.bytes
[0] == 0xc0){ /* write EEPROM byte */
412 eeprom_write_byte((void *)address
.word
, rq
->wIndex
.bytes
[1]);
415 }else if(rq
->wValue
.bytes
[0] == 0xac && rq
->wValue
.bytes
[1] == 0x80){ /* chip erase */
417 #if HAVE_BLB11_SOFTW_LOCKBIT
418 for(addr
= 0; addr
< (addr_t
)(BOOTLOADER_PAGEADDR
) ; addr
+= SPM_PAGESIZE
) {
420 for(addr
= 0; addr
<= (addr_t
)(FLASHEND
) ; addr
+= SPM_PAGESIZE
) {
422 /* wait and erase page */
424 # ifndef NO_FLASH_WRITE
425 boot_spm_busy_wait();
427 boot_page_erase(addr
);
432 #if ((HAVE_BOOTLOADER_HIDDENEXITCOMMAND) && (BOOTLOADER_CAN_EXIT))
433 # if ((HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0xac) && \
434 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x20) && (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x28) && \
435 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x40) && (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x48) && \
436 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x4c) && \
437 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0xa0) && \
438 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0xc0) && \
439 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x58) && \
440 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x5c) && \
441 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x30) && \
442 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0xac) && \
443 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x50) && (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x58) && \
444 (HAVE_BOOTLOADER_HIDDENEXITCOMMAND != 0x38))
445 }else if(rq
->wValue
.bytes
[0] == (HAVE_BOOTLOADER_HIDDENEXITCOMMAND
)){ /* cause a bootLoaderExit at disconnect */
446 stayinloader
= 0xf1; /* we need to be connected - so assume it */
450 /* ignore all others, return default value == 0 */
457 usbMsgLen_t
usbFunctionSetup(uchar data
[8])
459 usbRequest_t
*rq
= (void *)data
;
461 static uchar replyBuffer
[4];
463 usbMsgPtr
= (usbMsgPtr_t
)replyBuffer
;
464 if(rq
->bRequest
== USBASP_FUNC_TRANSMIT
){ /* emulate parts of ISP protocol */
465 replyBuffer
[3] = usbFunctionSetup_USBASP_FUNC_TRANSMIT(rq
);
466 len
= (usbMsgLen_t
)4;
467 }else if((rq
->bRequest
== USBASP_FUNC_ENABLEPROG
) || (rq
->bRequest
== USBASP_FUNC_SETISPSCK
)){
468 /* replyBuffer[0] = 0; is never touched and thus always 0 which means success */
469 len
= (usbMsgLen_t
)1;
470 }else if(rq
->bRequest
>= USBASP_FUNC_READFLASH
&& rq
->bRequest
<= USBASP_FUNC_SETLONGADDRESS
){
471 currentAddress
.w
[0] = rq
->wValue
.word
;
472 if(rq
->bRequest
== USBASP_FUNC_SETLONGADDRESS
){
473 #if (FLASHEND) > 0xffff
474 currentAddress
.w
[1] = rq
->wIndex
.word
;
477 bytesRemaining
= rq
->wLength
.bytes
[0];
478 /* if(rq->bRequest == USBASP_FUNC_WRITEFLASH) only evaluated during writeFlash anyway */
479 isLastPage
= rq
->wIndex
.bytes
[1] & 0x02;
480 #if HAVE_EEPROM_PAGED_ACCESS
481 currentRequest
= rq
->bRequest
;
483 len
= USB_NO_MSG
; /* hand over to usbFunctionRead() / usbFunctionWrite() */
486 }else if(rq
->bRequest
== USBASP_FUNC_DISCONNECT
){
488 #if BOOTLOADER_CAN_EXIT
489 # ifdef CONFIG_HAVE__BOOTLOADER_ABORTTIMEOUTONACT
490 /* let the main loop know for ever that here was activity */
491 stayinloader
&= (0xfc);
493 stayinloader
&= (0xfe);
497 /* ignore: others, but could be USBASP_FUNC_CONNECT */
498 #if BOOTLOADER_CAN_EXIT
499 stayinloader
|= (0x01);
505 #if (USE_EXCESSIVE_ASSEMBLER) && ((!HAVE_CHIP_ERASE) || (HAVE_ONDEMAND_PAGEERASE)) && (SPM_PAGESIZE <= 256) && (((BOOTLOADER_PAGEADDR>>0)&0xff) == 0)
506 uchar
usbFunctionWrite(uchar
*data
, uchar len
)
510 DBG1(0x31, (void *)¤tAddress
.l
, 4);
511 if(len
> bytesRemaining
)
512 len
= bytesRemaining
;
513 bytesRemaining
-= len
;
514 isLast
= bytesRemaining
== 0;
515 if(currentRequest
>= USBASP_FUNC_READEEPROM
){
517 for(i
= 0; i
< len
; i
++){
518 eeprom_write_byte((void *)(currentAddress
.w
[0]++), *data
++);
524 "usbFunctionWrite_flashloop:\n\t"
526 "brlo usbFunctionWrite_finished\n\t"
528 #if HAVE_BLB11_SOFTW_LOCKBIT
529 "cpi r31, %[blsaddrhi]\n\t" /* accelerated BLB11_SOFTW_LOCKBIT check */
530 "brsh usbFunctionWrite_finished\n\t"
531 // "brlo usbFunctionWrite_addrunlock_ok\n\t"
532 // "brne usbFunctionWrite_finished\n\t"
533 // "cpi r30, %[blsaddrlo]\n\t"
534 // "brlo usbFunctionWrite_addrunlock_ok\n\t"
535 // "rjmp usbFunctionWrite_finished\n\t"
536 // "usbFunctionWrite_addrunlock_ok:\n\t"
538 "rcall usbFunctionWrite_waitA\n\t"
539 "cli\n\t" /* r0 or r1 may be __zero_reg__ and may become dangerous nonzero within interrupts */
543 "ldi r18, %[pagfillval]\n\t"
544 "rcall usbFunctionWrite_saveflash\n\t" /* page fill */
547 "subi r18, 0xfe\n\t" /* add with 2 */
548 "andi r18, %[pagemask]\n\t"
549 "breq usbFunctionWrite_pageisfull\n\t"
551 "breq usbFunctionWrite_skippageisfull\n\t"
552 "tst %[isLastPage]\n\t"
553 "breq usbFunctionWrite_skippageisfull\n\t"
555 "brne usbFunctionWrite_skippageisfull\n\t"
557 "usbFunctionWrite_pageisfull:\n\t" /* start writing the page */
558 "ldi r18, %[pageraseval]\n\t"
559 "rcall usbFunctionWrite_saveflash\n\t" /* page erase */
560 "rcall usbFunctionWrite_waitA\n\t"
562 "ldi r18, %[pagwriteval]\n\t"
563 "rcall usbFunctionWrite_saveflash\n\t" /* page write */
564 "rcall usbFunctionWrite_waitA\n\t"
566 "in __tmp_reg__, %[spmcr]\n\t"
567 "sbrs __tmp_reg__, %[rwwsbbit]\n\t"
568 "rjmp usbFunctionWrite_skippageisfull\n\t"
569 "ldi r18, %[rwwenrval]\n\t"
570 "rcall usbFunctionWrite_saveflash\n\t" /* reenable rww*/
571 // "rcall usbFunctionWrite_waitA\n\t"
574 "usbFunctionWrite_skippageisfull:\n\t"
576 "rjmp usbFunctionWrite_flashloop\n\t"
578 "usbFunctionWrite_saveflash:\n\t"
580 "out %[spmcr], r18\n\t"
582 "clr __zero_reg__\n\t" /* if r0 or r1 is __zero_reg__ it may have become inconsisten while page-fill */
586 "usbFunctionWrite_waitA:\n\t"
587 "in __tmp_reg__, %[spmcr]\n\t"
588 "sbrc __tmp_reg__, %[spmenbit]\n\t"
589 "rjmp usbFunctionWrite_waitA\n\t"
592 "usbFunctionWrite_finished:\n\t"
593 : [addr
] "+z" (currentAddress
.l
)
595 : [spmenbit
] "I" (SPMEN
),
596 [rwwsbbit
] "I" (RWWSB
),
597 [spmcr
] "I" (_SFR_IO_ADDR(__SPM_REG
)),
598 [pagfillval
] "M" ((1<<SPMEN
)),
599 [pageraseval
] "M" ((1<<PGERS
) | (1<<SPMEN
)),
600 [pagwriteval
] "M" ((1<<PGWRT
) | (1<<SPMEN
)),
601 [rwwenrval
] "M" ((1<<RWWSRE
) | (1<<SPMEN
)),
602 [pagemask
] "M" (SPM_PAGESIZE
-1),
603 #if HAVE_BLB11_SOFTW_LOCKBIT
604 [blsaddrhi
] "M" ((uint8_t)((BOOTLOADER_PAGEADDR
>>8)&0xff)),
605 // [blsaddrlo] "M" ((uint8_t)((BOOTLOADER_PAGEADDR>>0)&0xff)),
607 [islast
] "r" (isLast
),
608 [isLastPage
] "r" (isLastPage
),
618 uchar
usbFunctionWrite(uchar
*data
, uchar len
)
622 DBG1(0x31, (void *)¤tAddress
.l
, 4);
623 if(len
> bytesRemaining
)
624 len
= bytesRemaining
;
625 bytesRemaining
-= len
;
626 isLast
= bytesRemaining
== 0;
627 for(i
= 0; i
< len
;) {
628 if(currentRequest
>= USBASP_FUNC_READEEPROM
){
629 eeprom_write_byte((void *)(currentAddress
.w
[0]++), *data
++);
632 #if HAVE_BLB11_SOFTW_LOCKBIT
633 if (CURRENT_ADDRESS
>= (addr_t
)(BOOTLOADER_PAGEADDR
)) {
640 boot_page_fill(CURRENT_ADDRESS
, *(short *)data
);
642 CURRENT_ADDRESS
+= 2;
644 /* write page when we cross page boundary or we have the last partial page */
645 if((currentAddress
.w
[0] & (SPM_PAGESIZE
- 1)) == 0 || (isLast
&& i
>= len
&& isLastPage
)){
646 #if (!HAVE_CHIP_ERASE) || (HAVE_ONDEMAND_PAGEERASE)
648 # ifndef NO_FLASH_WRITE
650 boot_page_erase(CURRENT_ADDRESS
- 2); /* erase page */
652 boot_spm_busy_wait(); /* wait until page is erased */
656 #ifndef NO_FLASH_WRITE
658 boot_page_write(CURRENT_ADDRESS
- 2);
660 boot_spm_busy_wait();
667 DBG1(0x35, (void *)¤tAddress
.l
, 4);
673 uchar
usbFunctionRead(uchar
*data
, uchar len
)
677 if(len
> bytesRemaining
)
678 len
= bytesRemaining
;
679 bytesRemaining
-= len
;
680 for(i
= 0; i
< len
; i
++){
681 if(currentRequest
>= USBASP_FUNC_READEEPROM
){
682 *data
= eeprom_read_byte((void *)currentAddress
.w
[0]);
684 #if ((FLASHEND) > 65535)
685 *data
= pgm_read_byte_far(CURRENT_ADDRESS
);
687 *data
= pgm_read_byte(CURRENT_ADDRESS
);
696 /* ------------------------------------------------------------------------ */
698 #if HAVE_UNPRECISEWAIT
699 static void _mywait(uint8_t waitloopcnt
) {
701 /*we really don't care what value Z has...
702 * ...if we loop 65536/F_CPU more or less...
703 * ...unimportant - just save some opcodes
705 "_mywait_sleeploop%=: \n\t"
708 "brne _mywait_sleeploop%= \n\t"
716 static void initForUsbConnectivity(void)
719 /* enforce USB re-enumerate: */
720 usbDeviceDisconnect(); /* do this while interrupts are disabled */
721 #if HAVE_UNPRECISEWAIT
722 /* (0.25s*F_CPU)/(4 cycles per loop) ~ (65536*waitloopcnt)
723 * F_CPU/(16*65536) ~ waitloopcnt
724 * F_CPU / 1048576 ~ waitloopcnt
726 _mywait(1 + (F_CPU
/1048576));
728 _delay_ms(260); /* fake USB disconnect for > 250 ms */
734 int __attribute__((__noreturn__
)) main(void)
736 #if ((BOOTLOADER_LOOPCYCLES_TIMEOUT) && (BOOTLOADER_CAN_EXIT))
737 uint16_t __loopscycles
;
738 timeout_remaining
= BOOTLOADER_LOOPCYCLES_TIMEOUT
;
744 #ifndef NO_FLASH_WRITE
745 GICR
= (1 << IVCE
); /* enable change of interrupt vectors */
746 GICR
= (1 << IVSEL
); /* move interrupts to boot flash section */
748 #if (HAVE_BOOTLOADER_ADDITIONALMSDEVICEWAIT>0)
749 # if HAVE_UNPRECISEWAIT
750 _mywait(1+((HAVE_BOOTLOADER_ADDITIONALMSDEVICEWAIT
*F_CPU
)/262144000));
752 _delay_ms(HAVE_BOOTLOADER_ADDITIONALMSDEVICEWAIT
);
755 if(bootLoaderCondition()){
756 #if (BOOTLOADER_CAN_EXIT)
757 # if (USE_EXCESSIVE_ASSEMBLER)
759 "ldi %[sil], %[normval]\n\t"
760 # if ((defined(CONFIG_HAVE__BOOTLOADER_ABORTTIMEOUTONACT)) && (!(BOOTLOADER_IGNOREPROGBUTTON)) && (BOOTLOADER_LOOPCYCLES_TIMEOUT))
761 "sbis %[pin], %[bit]\n\t"
762 "subi %[sil], 0x02\n\t"
764 : [sil
] "=d" (stayinloader
)
765 : [normval
] "M" (stayinloader_initialValue
)
766 # if (!(BOOTLOADER_IGNOREPROGBUTTON))
768 [pin
] "I" (_SFR_IO_ADDR(PIN_PIN(JUMPER_PORT
))),
769 [bit
] "I" (PIN(JUMPER_PORT
, JUMPER_BIT
))
773 # if ((defined(CONFIG_HAVE__BOOTLOADER_ABORTTIMEOUTONACT)) && (!(BOOTLOADER_IGNOREPROGBUTTON)) && (BOOTLOADER_LOOPCYCLES_TIMEOUT))
774 if (bootLoaderConditionSimple()) {
775 stayinloader
= stayinloader_initialValue
- 0x02;
778 stayinloader
= stayinloader_initialValue
;
782 # if (defined(MCUSR) && defined(WDRF))
784 * Fix issue 6: (special thanks to coldtobi)
786 * The WDRF bit in the MCUSR needs to be cleared first,
787 * otherwise it is not possible to disable the watchdog
789 MCUSR
&= ~(_BV(WDRF
));
791 wdt_disable(); /* main app may have enabled watchdog */
793 MCUCSR
= 0; /* clear all reset flags for next time */
794 initForUsbConnectivity();
796 #if ((BOOTLOADER_LOOPCYCLES_TIMEOUT) && (BOOTLOADER_CAN_EXIT))
797 # ifdef CONFIG_HAVE__BOOTLOADER_ABORTTIMEOUTONACT
798 if (stayinloader
!= 0x0e) {
799 /* can be reached, since high-nibble is decreased every cycle... */
801 if (stayinloader
& 0x01) {
803 timeout_remaining
= BOOTLOADER_LOOPCYCLES_TIMEOUT
;
806 if (!(__loopscycles
)) {
807 if(timeout_remaining
) timeout_remaining
--;
808 else stayinloader
&=0xf1;
813 #if BOOTLOADER_CAN_EXIT
814 #if BOOTLOADER_IGNOREPROGBUTTON
816 * remove the high nibble as it would be subtracted due to:
817 * "(!bootLoaderConditionSimple())"
819 #if USE_EXCESSIVE_ASSEMBLER
821 "andi %[sil], 0x0f\n\t"
822 : [sil
] "+d" (stayinloader
)
826 stayinloader
&= 0x0f;
829 #if USE_EXCESSIVE_ASSEMBLER
831 "cpi %[sil], 0x10\n\t"
832 "brlo main_stayinloader_smaller\n\t"
833 "sbic %[pin], %[bit]\n\t"
834 "subi %[sil], 0x10\n\t"
835 "rjmp main_stayinloader_finished\n\t"
837 "main_stayinloader_smaller:\n\t"
838 "cpi %[sil], 0x2\n\t"
839 "brlo main_stayinloader_finished\n\t"
840 "sbis %[pin], %[bit]\n\t"
841 "subi %[sil], 0x2\n\t"
843 "main_stayinloader_finished:\n\t"
844 : [sil
] "+d" (stayinloader
)
845 : [pin
] "I" (_SFR_IO_ADDR(PIN_PIN(JUMPER_PORT
))),
846 [bit
] "I" (PIN(JUMPER_PORT
, JUMPER_BIT
))
849 if (stayinloader
>= 0x10) {
850 if (!bootLoaderConditionSimple()) {
854 if (bootLoaderConditionSimple()) {
855 if (stayinloader
> 1) stayinloader
-=2;
862 #if BOOTLOADER_CAN_EXIT
863 }while (stayinloader
); /* main event loop, if BOOTLOADER_CAN_EXIT*/
865 }while (1); /* main event loop */
871 /* ------------------------------------------------------------------------ */