X-Git-Url: http://git.linex4red.de/pub/USBaspLoader.git/blobdiff_plain/91ee04321867a93a8e37636bedf581f09ca082a0..8a827b1fd2ddcca5d27e2a03fe80d8c2e706515e:/firmware/main.c diff --git a/firmware/main.c b/firmware/main.c index 9358b5e..e40c0b5 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -3,11 +3,10 @@ * Author: Christian Starkjohann * Author: Stephan Baerwolf * Creation Date: 2007-12-08 - * Modification Date: 2012-11-10 + * Modification Date: 2013-03-31 * Tabsize: 4 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH * License: GNU GPL v2 (see License.txt) - * This Revision: $Id: main.c 786 2010-05-30 20:41:40Z cs $ */ #include "spminterface.h" /* must be included as first! */ @@ -42,8 +41,6 @@ -static void leaveBootloader() __attribute__((__noreturn__)); - #include "bootloaderconfig.h" #include "usbdrv/usbdrv.c" @@ -133,6 +130,8 @@ static const uchar signatureBytes[4] = { SIGNATURE_BYTES #elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__) 0x1e, 0x93, 0x07, 0 +#elif defined (__AVR_ATmega16__) + 0x1e, 0x94, 0x03, 0 #elif defined (__AVR_ATmega32__) 0x1e, 0x95, 0x02, 0 #elif defined (__AVR_ATmega48__) || defined (__AVR_ATmega48A__) || defined (__AVR_ATmega48P__) @@ -147,7 +146,7 @@ static const uchar signatureBytes[4] = { 0x1e, 0x93, 0x0F, 0 #elif defined (__AVR_ATmega164A__) 0x1e, 0x94, 0x0f, 0 -#elif defined (__AVR_ATmega164P__) +#elif defined (__AVR_ATmega164P__) || defined (__AVR_ATmega164PA__) 0x1e, 0x94, 0x0a, 0 #elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168P__) 0x1e, 0x94, 0x06, 0 @@ -163,27 +162,95 @@ static const uchar signatureBytes[4] = { 0x1e, 0x95, 0x14, 0 #elif defined (__AVR_ATmega328P__) 0x1e, 0x95, 0x0f, 0 +#elif defined (__AVR_ATmega640__) + 0x1e, 0x96, 0x08, 0 #elif defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) 0x1e, 0x96, 0x09, 0 #elif defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__) 0x1e, 0x96, 0x0a, 0 #elif defined (__AVR_ATmega128__) 0x1e, 0x97, 0x02, 0 +#elif defined (__AVR_ATmega1280__) + 0x1e, 0x97, 0x03, 0 +#elif defined (__AVR_ATmega1281__) + 0x1e, 0x97, 0x04, 0 #elif defined (__AVR_ATmega1284__) 0x1e, 0x97, 0x06, 0 #elif defined (__AVR_ATmega1284P__) 0x1e, 0x97, 0x05, 0 +#elif defined (__AVR_ATmega2560__) + 0x1e, 0x98, 0x01, 0 +#elif defined (__AVR_ATmega2561__) + 0x1e, 0x98, 0x02, 0 #else -# error "Device signature is not known, please edit main.c!" +# if (defined(SIGNATURE_0) && defined(SIGNATURE_1) && defined(SIGNATURE_2)) +# warning "Device signature is not known - using AVR Libc suggestion..." + SIGNATURE_0, SIGNATURE_1, SIGNATURE_2, 0 +# else +# error "Device signature is not known, please edit main.c!" +# endif #endif }; /* ------------------------------------------------------------------------ */ +#if (USE_BOOTUP_CLEARRAM) +/* +* Under normal circumstances, RESET will not clear contents of RAM. +* As always, if you want it done - do it yourself... +*/ +void __attribute__ ((naked)) __attribute__ ((section (".init3"))) __clearram(void); +void __clearram(void) { + extern size_t __bss_end; + asm volatile ( + "__clearram:\n\t" + "ldi r29, %[ramendhi]\n\t" + "ldi r28, %[ramendlo]\n\t" + "__clearramloop%=:\n\t" + "st -Y , __zero_reg__\n\t" + "cp r28, %A[bssend]\n\t" + "cpc r29, %B[bssend]\n\t" + "brne __clearramloop%=\n\t" + : + : [ramendhi] "M" (((RAMEND+1)>>8) & 0xff), + [ramendlo] "M" (((RAMEND+1)>>0) & 0xff), + [bssend] "r" (&__bss_end) + : "memory" + ); +} +#endif + +#if (!USE_EXCESSIVE_ASSEMBLER) || (!(defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__))) static void (*nullVector)(void) __attribute__((__noreturn__)); +#endif -static void leaveBootloader() +static void __attribute__((__noreturn__)) leaveBootloader() { +#if (USE_EXCESSIVE_ASSEMBLER) && (defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__)) +asm volatile ( + "cli\n\t" + "clr r30\n\t" + "sbi %[usbddr], %[usbminus]\n\t" + "cbi %[port], %[bit]\n\t" + "out %[usbintrenab], r30\n\t" + "out %[usbintrcfg], r30\n\t" + "ldi r31, %[ivce]\n\t" + "out %[mygicr], r31\n\t" + "out %[mygicr], r30\n\t" + "clr r31\n\t" + "icall\n\t" + : + : [port] "I" (_SFR_IO_ADDR(PIN_PORT(JUMPER_PORT))), + [bit] "I" (PIN(JUMPER_PORT, JUMPER_BIT)), + [usbintrenab] "I" (_SFR_IO_ADDR(USB_INTR_ENABLE)), + [usbintrcfg] "I" (_SFR_IO_ADDR(USB_INTR_CFG)), + [usbddr] "I" (_SFR_IO_ADDR(USBDDR)), + [usbminus] "I" (USBMINUS), + [mygicr] "I" (_SFR_IO_ADDR(GICR)), + [ivce] "I" (1<131071)) + EIND=0; +#endif /* We must go through a global function pointer variable instead of writing * ((void (*)(void))0)(); * because the compiler optimizes a constant 0 to "rcall 0" which is not * handled correctly by the assembler. */ nullVector(); +#endif } /* ------------------------------------------------------------------------ */ @@ -214,7 +291,7 @@ uchar usbFunctionSetup_USBASP_FUNC_TRANSMIT(usbRequest_t *rq) { rval = rq->wIndex.bytes[0] & 3; rval = signatureBytes[rval]; #if HAVE_READ_LOCK_FUSE -#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega32__) +#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__) }else if(rq->wValue.bytes[0] == 0x58 && rq->wValue.bytes[1] == 0x00){ /* read lock bits */ rval = boot_lock_fuse_bits_get(GET_LOCK_BITS); }else if(rq->wValue.bytes[0] == 0x50 && rq->wValue.bytes[1] == 0x00){ /* read lfuse bits */ @@ -228,9 +305,14 @@ defined (__AVR_ATmega164A__) || defined (__AVR_ATmega164P__) || \ defined (__AVR_ATmega168__) || defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168P__) || defined (__AVR_ATmega168PA__) || \ defined (__AVR_ATmega324A__) || defined (__AVR_ATmega324P__) || \ defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__) || \ +defined (__AVR_ATmega640__) || \ defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__) || \ defined (__AVR_ATmega128__) || \ -defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__) +defined (__AVR_ATmega1280__) || \ +defined (__AVR_ATmega1281__) || \ +defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__) || \ +defined (__AVR_ATmega2560__) || \ +defined (__AVR_ATmega2561__) }else if(rq->wValue.bytes[0] == 0x58 && rq->wValue.bytes[1] == 0x00){ /* read lock bits */ rval = boot_lock_fuse_bits_get(GET_LOCK_BITS); }else if(rq->wValue.bytes[0] == 0x50 && rq->wValue.bytes[1] == 0x00){ /* read lfuse bits */ @@ -295,7 +377,7 @@ usbRequest_t *rq = (void *)data; uchar len = 0; static uchar replyBuffer[4]; - usbMsgPtr = replyBuffer; + usbMsgPtr = (usbMsgPtr_t)replyBuffer; if(rq->bRequest == USBASP_FUNC_TRANSMIT){ /* emulate parts of ISP protocol */ replyBuffer[3] = usbFunctionSetup_USBASP_FUNC_TRANSMIT(rq); len = 4; @@ -332,6 +414,119 @@ static uchar replyBuffer[4]; return len; } +#if (USE_EXCESSIVE_ASSEMBLER) && ((!HAVE_CHIP_ERASE) || (HAVE_ONDEMAND_PAGEERASE)) && (SPM_PAGESIZE <= 256) && (((BOOTLOADER_PAGEADDR>>0)&0xff) == 0) +uchar usbFunctionWrite(uchar *data, uchar len) +{ +uchar isLast; + + DBG1(0x31, (void *)¤tAddress.l, 4); + if(len > bytesRemaining) + len = bytesRemaining; + bytesRemaining -= len; + isLast = bytesRemaining == 0; + if(currentRequest >= USBASP_FUNC_READEEPROM){ + uchar i; + for(i = 0; i < len; i++){ + eeprom_write_byte((void *)(currentAddress.w[0]++), *data++); + } + }else{ + asm volatile ( + "sbrc %[len], 0\n\t" + "inc %[len]\n\t" +"usbFunctionWrite_flashloop:\n\t" + "subi %[len], 2\n\t" + "brlo usbFunctionWrite_finished\n\t" + +#if HAVE_BLB11_SOFTW_LOCKBIT + "cpi r31, %[blsaddrhi]\n\t" /* accelerated BLB11_SOFTW_LOCKBIT check */ + "brsh usbFunctionWrite_finished\n\t" +// "brlo usbFunctionWrite_addrunlock_ok\n\t" +// "brne usbFunctionWrite_finished\n\t" +// "cpi r30, %[blsaddrlo]\n\t" +// "brlo usbFunctionWrite_addrunlock_ok\n\t" +// "rjmp usbFunctionWrite_finished\n\t" +// "usbFunctionWrite_addrunlock_ok:\n\t" +#endif + "rcall usbFunctionWrite_waitA\n\t" + "cli\n\t" /* r0 or r1 may be __zero_reg__ and may become dangerous nonzero within interrupts */ + "ld r0, X+\n\t" + "ld r1, X+\n\t" + + "ldi r18, %[pagfillval]\n\t" + "rcall usbFunctionWrite_saveflash\n\t" /* page fill */ + + "mov r18, r30\n\t" + "subi r18, 0xfe\n\t" /* add with 2 */ + "andi r18, %[pagemask]\n\t" + "breq usbFunctionWrite_pageisfull\n\t" + "tst %[islast]\n\t" + "breq usbFunctionWrite_skippageisfull\n\t" + "tst %[isLastPage]\n\t" + "breq usbFunctionWrite_skippageisfull\n\t" + "cpi %[len], 0\n\t" + "brne usbFunctionWrite_skippageisfull\n\t" + +"usbFunctionWrite_pageisfull:\n\t" /* start writing the page */ + "ldi r18, %[pageraseval]\n\t" + "rcall usbFunctionWrite_saveflash\n\t" /* page erase */ + "rcall usbFunctionWrite_waitA\n\t" + + "ldi r18, %[pagwriteval]\n\t" + "rcall usbFunctionWrite_saveflash\n\t" /* page write */ + "rcall usbFunctionWrite_waitA\n\t" + + "in __tmp_reg__, %[spmcr]\n\t" + "sbrs __tmp_reg__, %[rwwsbbit]\n\t" + "rjmp usbFunctionWrite_skippageisfull\n\t" + "ldi r18, %[rwwenrval]\n\t" + "rcall usbFunctionWrite_saveflash\n\t" /* reenable rww*/ +// "rcall usbFunctionWrite_waitA\n\t" + + +"usbFunctionWrite_skippageisfull:\n\t" + "adiw r30, 0x2\n\t" + "rjmp usbFunctionWrite_flashloop\n\t" + +"usbFunctionWrite_saveflash:\n\t" + "cli\n\t" + "out %[spmcr], r18\n\t" + "spm\n\t" + "clr __zero_reg__\n\t" /* if r0 or r1 is __zero_reg__ it may have become inconsisten while page-fill */ + "sei\n\t" + "ret\n\t" + +"usbFunctionWrite_waitA:\n\t" + "in __tmp_reg__, %[spmcr]\n\t" + "sbrc __tmp_reg__, %[spmenbit]\n\t" + "rjmp usbFunctionWrite_waitA\n\t" + "ret\n\t" + +"usbFunctionWrite_finished:\n\t" + : [addr] "+z" (currentAddress.l) + + : [spmenbit] "I" (SPMEN), + [rwwsbbit] "I" (RWWSB), + [spmcr] "I" (_SFR_IO_ADDR(__SPM_REG)), + [pagfillval] "M" ((1<>8)&0xff)), +// [blsaddrlo] "M" ((uint8_t)((BOOTLOADER_PAGEADDR>>0)&0xff)), +#endif + [islast] "r" (isLast), + [isLastPage] "r" (isLastPage), + [len] "d" (len), + [dataptr] "x" (data) + + : "r0", "r1", "r18" + ); + } + return isLast; +} +#else uchar usbFunctionWrite(uchar *data, uchar len) { uchar i,isLast; @@ -385,6 +580,7 @@ uchar i,isLast; } return isLast; } +#endif uchar usbFunctionRead(uchar *data, uchar len) { @@ -444,7 +640,7 @@ static void initForUsbConnectivity(void) sei(); } -int __attribute__((noreturn)) main(void) +int __attribute__((__noreturn__)) main(void) { /* initialize */ bootLoaderInit(); @@ -456,12 +652,41 @@ int __attribute__((noreturn)) main(void) #endif if(bootLoaderCondition()){ #if NEED_WATCHDOG +# if (defined(MCUSR) && defined(WDRF)) + /* + * Fix issue 6: (special thanks to coldtobi) + * + * The WDRF bit in the MCUSR needs to be cleared first, + * otherwise it is not possible to disable the watchdog + */ + MCUSR &= ~(_BV(WDRF)); +# endif wdt_disable(); /* main app may have enabled watchdog */ #endif initForUsbConnectivity(); do{ usbPoll(); #if BOOTLOADER_CAN_EXIT +#if USE_EXCESSIVE_ASSEMBLER +asm volatile ( + "cpi %[sil], 0x10\n\t" + "brlo main_stayinloader_smaller\n\t" + "sbic %[pin], %[bit]\n\t" + "subi %[sil], 0x10\n\t" + "rjmp main_stayinloader_finished\n\t" + + "main_stayinloader_smaller:\n\t" + "cpi %[sil], 0x2\n\t" + "brlo main_stayinloader_finished\n\t" + "sbis %[pin], %[bit]\n\t" + "subi %[sil], 0x2\n\t" + + "main_stayinloader_finished:\n\t" + : [sil] "+d" (stayinloader) + : [pin] "I" (_SFR_IO_ADDR(PIN_PIN(JUMPER_PORT))), + [bit] "I" (PIN(JUMPER_PORT, JUMPER_BIT)) +); +#else if (stayinloader >= 0x10) { if (!bootLoaderCondition()) { stayinloader-=0x10; @@ -472,6 +697,7 @@ int __attribute__((noreturn)) main(void) } } #endif +#endif #if BOOTLOADER_CAN_EXIT }while (stayinloader); /* main event loop, if BOOTLOADER_CAN_EXIT*/