/**********************************************************/ /* Optiboot bootloader for Arduino */ /* */ /* http://optiboot.googlecode.com */ /* */ /* Arduino-maintained version : See README.TXT */ /* http://code.google.com/p/arduino/ */ /* It is the intent that changes not relevant to the */ /* Arduino production envionment get moved from the */ /* optiboot project to the arduino project in "lumps." */ /* */ /* Heavily optimised bootloader that is faster and */ /* smaller than the Arduino standard bootloader */ /* */ /* Enhancements: */ /* Fits in 512 bytes, saving 1.5K of code space */ /* Background page erasing speeds up programming */ /* Higher baud rate speeds up programming */ /* Written almost entirely in C */ /* Customisable timeout with accurate timeconstant */ /* Optional virtual UART. No hardware UART required. */ /* Optional virtual boot partition for devices without. */ /* */ /* What you lose: */ /* Implements a skeleton STK500 protocol which is */ /* missing several features including EEPROM */ /* programming and non-page-aligned writes */ /* High baud rate breaks compatibility with standard */ /* Arduino flash settings */ /* */ /* Fully supported: */ /* ATmega168 based devices (Diecimila etc) */ /* ATmega328P based devices (Duemilanove etc) */ /* */ /* Beta test (believed working.) */ /* ATmega8 based devices (Arduino legacy) */ /* ATmega328 non-picopower devices */ /* ATmega644P based devices (Sanguino) */ /* ATmega1284P based devices */ /* */ /* Alpha test */ /* ATmega1280 based devices (Arduino Mega) */ /* */ /* Work in progress: */ /* ATtiny84 based devices (Luminet) */ /* */ /* Does not support: */ /* USB based devices (eg. Teensy) */ /* */ /* Assumptions: */ /* The code makes several assumptions that reduce the */ /* code size. They are all true after a hardware reset, */ /* but may not be true if the bootloader is called by */ /* other means or on other hardware. */ /* No interrupts can occur */ /* UART and Timer 1 are set to their reset state */ /* SP points to RAMEND */ /* */ /* Code builds on code, libraries and optimisations from: */ /* stk500boot.c by Jason P. Kyle */ /* Arduino bootloader http://arduino.cc */ /* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */ /* avr-libc project http://nongnu.org/avr-libc */ /* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */ /* AVR305 Atmel Application Note */ /* */ /* This program is free software; you can redistribute it */ /* and/or modify it under the terms of the GNU General */ /* Public License as published by the Free Software */ /* Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will */ /* be useful, but WITHOUT ANY WARRANTY; without even the */ /* implied warranty of MERCHANTABILITY or FITNESS FOR A */ /* PARTICULAR PURPOSE. See the GNU General Public */ /* License for more details. */ /* */ /* You should have received a copy of the GNU General */ /* Public License along with this program; if not, write */ /* to the Free Software Foundation, Inc., */ /* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /* Licence can be viewed at */ /* http://www.fsf.org/licenses/gpl.txt */ /* */ /**********************************************************/ /**********************************************************/ /* */ /* Optional defines: */ /* */ /**********************************************************/ /* */ /* BIG_BOOT: */ /* Build a 1k bootloader, not 512 bytes. This turns on */ /* extra functionality. */ /* */ /* BAUD_RATE: */ /* Set bootloader baud rate. */ /* */ /* LUDICROUS_SPEED: */ /* 230400 baud :-) */ /* */ /* SOFT_UART: */ /* Use AVR305 soft-UART instead of hardware UART. */ /* */ /* LED_START_FLASHES: */ /* Number of LED flashes on bootup. */ /* */ /* LED_DATA_FLASH: */ /* Flash LED when transferring data. For boards without */ /* TX or RX LEDs, or for people who like blinky lights. */ /* */ /* SUPPORT_EEPROM: */ /* Support reading and writing from EEPROM. This is not */ /* used by Arduino, so off by default. */ /* */ /* TIMEOUT_MS: */ /* Bootloader timeout period, in milliseconds. */ /* 500,1000,2000,4000,8000 supported. */ /* */ /* UART: */ /* UART number (0..n) for devices with more than */ /* one hardware uart (644P, 1284P, etc) */ /* */ /**********************************************************/ /**********************************************************/ /* Version Numbers! */ /* */ /* Arduino Optiboot now includes this Version number in */ /* the source and object code. */ /* */ /* Version 3 was released as zip from the optiboot */ /* repository and was distributed with Arduino 0022. */ /* Version 4 starts with the arduino repository commit */ /* that brought the arduino repository up-to-date with */ /* the optiboot source tree changes since v3. */ /* */ /**********************************************************/ /**********************************************************/ /* Edit History: */ /* */ /* Nov 2012 */ /* Specific version for 9x voice module */ /* by Mike Blandford */ /* Mar 2012 */ /* 4.5 WestfW: add infrastructure for non-zero UARTS. */ /* 4.5 WestfW: fix SIGNATURE_2 for m644 (bad in avr-libc) */ /* Jan 2012: */ /* 4.5 WestfW: fix NRWW value for m1284. */ /* 4.4 WestfW: use attribute OS_main instead of naked for */ /* main(). This allows optimizations that we */ /* count on, which are prohibited in naked */ /* functions due to PR42240. (keeps us less */ /* than 512 bytes when compiler is gcc4.5 */ /* (code from 4.3.2 remains the same.) */ /* 4.4 WestfW and Maniacbug: Add m1284 support. This */ /* does not change the 328 binary, so the */ /* version number didn't change either. (?) */ /* June 2011: */ /* 4.4 WestfW: remove automatic soft_uart detect (didn't */ /* know what it was doing or why.) Added a */ /* check of the calculated BRG value instead. */ /* Version stays 4.4; existing binaries are */ /* not changed. */ /* 4.4 WestfW: add initialization of address to keep */ /* the compiler happy. Change SC'ed targets. */ /* Return the SW version via READ PARAM */ /* 4.3 WestfW: catch framing errors in getch(), so that */ /* AVRISP works without HW kludges. */ /* http://code.google.com/p/arduino/issues/detail?id=368n*/ /* 4.2 WestfW: reduce code size, fix timeouts, change */ /* verifySpace to use WDT instead of appstart */ /* 4.1 WestfW: put version number in binary. */ /**********************************************************/ #define OPTIBOOT_MAJVER 4 #define OPTIBOOT_MINVER 5 #define MULTI_CALLED 1 #define MAKESTR(a) #a #define MAKEVER(a, b) MAKESTR(a*256+b) //asm(" .section .version\n" // "optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n" // " .section .text\n"); #include #include #include // uses sts instructions, but this version uses out instructions // This saves cycles and program memory. #include "boot.h" // We don't use as those routines have interrupt overhead we don't need. #include "pin_defs.h" #include "stk500.h" #ifndef LED_START_FLASHES #define LED_START_FLASHES 0 #endif #ifdef LUDICROUS_SPEED #define BAUD_RATE 230400L #endif /* set the UART baud rate defaults */ #ifndef BAUD_RATE #if F_CPU >= 8000000L #define BAUD_RATE 38400L // Highest rate Avrdude win32 will support #elsif F_CPU >= 1000000L #define BAUD_RATE 9600L // 19200 also supported, but with significant error #elsif F_CPU >= 128000L #define BAUD_RATE 4800L // Good for 128kHz internal RC #else #define BAUD_RATE 1200L // Good even at 32768Hz #endif #endif #ifndef UART #define UART 0 #endif #if 0 /* Switch in soft UART for hard baud rates */ /* * I don't understand what this was supposed to accomplish, where the * constant "280" came from, or why automatically (and perhaps unexpectedly) * switching to a soft uart is a good thing, so I'm undoing this in favor * of a range check using the same calc used to config the BRG... */ #if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz #ifndef SOFT_UART #define SOFT_UART #endif #endif #else // 0 #if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250 #error Unachievable baud rate (too slow) BAUD_RATE #endif // baud rate slow check #if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3 #error Unachievable baud rate (too fast) BAUD_RATE #endif // baud rate fastn check #endif /* Watchdog settings */ #define WATCHDOG_OFF (0) #define WATCHDOG_16MS (_BV(WDE)) #define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE)) #define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE)) #define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE)) #define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE)) #define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE)) #define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE)) #define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE)) #ifndef __AVR_ATmega8__ #define WATCHDOG_4S (_BV(WDP3) | _BV(WDE)) #define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE)) #endif /* Function Prototypes */ /* The main function is in init9, which removes the interrupt vector table */ /* we don't need. It is also 'naked', which means the compiler does not */ /* generate any entry or exit code itself. */ int main(void) __attribute__ ((OS_main)) __attribute__ ((noreturn)) __attribute__ ((section (".init9"))); void putch(char); uint8_t getch(void); static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */ void verifySpace(); #if LED_START_FLASHES > 0 static inline void flash_led(uint8_t); #endif uint8_t getLen(); //static inline void watchdogReset(); void watchdogConfig(uint8_t x); #ifdef SOFT_UART void uartDelay() __attribute__ ((naked)); #endif static void appStart() ; // __attribute__ ((naked)); /* * NRWW memory * Addresses below NRWW (Non-Read-While-Write) can be programmed while * continuing to run code from flash, slightly speeding up programming * time. Beware that Atmel data sheets specify this as a WORD address, * while optiboot will be comparing against a 16-bit byte address. This * means that on a part with 128kB of memory, the upper part of the lower * 64k will get NRWW processing as well, even though it doesn't need it. * That's OK. In fact, you can disable the overlapping processing for * a part entirely by setting NRWWSTART to zero. This reduces code * space a bit, at the expense of being slightly slower, overall. * * RAMSTART should be self-explanatory. It's bigger on parts with a * lot of peripheral registers. */ #if defined(__AVR_ATmega168__) #define RAMSTART (0x100) #define NRWWSTART (0x3800) #elif defined(__AVR_ATmega328P__) #define RAMSTART (0x100) #define NRWWSTART (0x7000) #elif defined(__AVR_ATmega328__) #define RAMSTART (0x100) #define NRWWSTART (0x7000) #elif defined (__AVR_ATmega644P__) #define RAMSTART (0x100) #define NRWWSTART (0xE000) // correct for a bug in avr-libc #undef SIGNATURE_2 #define SIGNATURE_2 0x0A #elif defined (__AVR_ATmega1284P__) #define RAMSTART (0x100) #define NRWWSTART (0xE000) #elif defined(__AVR_ATtiny84__) #define RAMSTART (0x100) #define NRWWSTART (0x0000) #elif defined(__AVR_ATmega1280__) #define RAMSTART (0x200) #define NRWWSTART (0xE000) #elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) #define RAMSTART (0x100) #define NRWWSTART (0x1800) #endif /* C zero initialises all global variables. However, that requires */ /* These definitions are NOT zero initialised, but that doesn't matter */ /* This allows us to drop the zero init code, saving us memory */ #define buff ((uint8_t*)(RAMSTART)) #ifdef VIRTUAL_BOOT_PARTITION #define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4)) #define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6)) #endif /* * Handle devices with up to 4 uarts (eg m1280.) Rather inelegantly. * Note that mega8 still needs special handling, because ubrr is handled * differently. */ #if UART == 0 # define UART_SRA UCSR0A # define UART_SRB UCSR0B # define UART_SRC UCSR0C # define UART_SRL UBRR0L # define UART_UDR UDR0 #elif UART == 1 # define UART_SRA UCSR1A # define UART_SRB UCSR1B # define UART_SRC UCSR1C # define UART_SRL UBRR1L # define UART_UDR UDR1 #elif UART == 2 # define UART_SRA UCSR2A # define UART_SRB UCSR2B # define UART_SRC UCSR2C # define UART_SRL UBRR2L # define UART_UDR UDR2 #elif UART == 3 # define UART_SRA UCSR3A # define UART_SRB UCSR3B # define UART_SRC UCSR3C # define UART_SRL UBRR3L # define UART_UDR UDR3 #endif /* main program starts here */ int main(void) { uint8_t ch; /* * Making these local and in registers prevents the need for initializing * them, and also saves space because code no longer stores to memory. * (initializing address keeps the compiler happy, but isn't really * necessary, and uses 4 bytes of flash.) */ register uint16_t address = 0; // After the zero init loop, this is the first code to run. // // This code makes the following assumptions: // No interrupts will execute // SP points to RAMEND // r1 contains zero // // If not, uncomment the following instructions: // cli(); asm volatile ("clr __zero_reg__"); #ifdef __AVR_ATmega8__ SP=RAMEND; // This is done by hardware reset #endif // Adaboot no-wait mod ch = MCUSR; MCUSR = 0; // Here, if power on, wait 0.5 secs, then check for // serial Rx signal low, if so, stay in bootloader // else go to application PORTD = 0xFF ; PORTB = 0x3C ; PORTC = 1 ; if (ch & (_BV(PORF) | (_BV(EXTRF)) ) ) { #ifdef MULTI_CALLED #if F_CPU == 12000000L TCNT1H = 256 - 8 ; #else #if F_CPU == 16000000L TCNT1H = 256 - 6 ; #else TCNT1H = 256 - 127 ; #endif TCNT1L = 0 ; #endif #else #if F_CPU == 12000000L TCNT1 = 65535-5859 ; #else #if F_CPU == 16000000L TCNT1 = 65535-7813 ; #else TCNT1 = 65535-32767 ; #endif #endif #endif TCCR1B = _BV(CS12) | _BV(CS10); // div 1024 TIFR1 = _BV(TOV1); while(!(TIFR1 & _BV(TOV1))) ; TCCR1B = 0 ; // Stop timer uint8_t x ; x = PINB & 0x3C ; x |= PINC & 1 ; if ( x != 0x1D ) { appStart() ; // Power on, go to voice application // if loaded } } #if LED_START_FLASHES > 0 // Set up Timer 1 for timeout counter TCCR1B = _BV(CS12) | _BV(CS10); // div 1024 #endif #ifndef SOFT_UART UART_SRA = _BV(U2X0); //Double speed mode USART0 UART_SRB = _BV(RXEN0) | _BV(TXEN0); UART_SRC = _BV(UCSZ00) | _BV(UCSZ01); // UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); // Baudrate of 57600 #if F_CPU == 12000000L UART_SRL = 25 ; #else #if F_CPU == 16000000L UART_SRL = 33 ; #else #ERROR Baud rate not available #endif #endif #endif // Set up watchdog to trigger after 500ms // watchdogConfig(WATCHDOG_1S); /* Set LED pin as output */ LED_DDR |= _BV(LED); #ifdef SOFT_UART /* Set TX pin as output */ UART_DDR |= _BV(UART_TX_BIT); #endif #if LED_START_FLASHES > 0 /* Flash onboard LED to signal entering of bootloader */ flash_led(LED_START_FLASHES * 2); #endif /* Forever loop */ for (;;) { /* get character from UART */ ch = getch(); if(ch == STK_GET_PARAMETER) { GPIOR0 = getch(); verifySpace(); if (GPIOR0 == 0x82) { /* * Send optiboot version as "minor SW version" */ putch(OPTIBOOT_MINVER); } else if (GPIOR0 == 0x81) { putch(OPTIBOOT_MAJVER); } else { /* * GET PARAMETER returns a generic 0x03 reply for * other parameters - enough to keep Avrdude happy */ putch(0x03); } } else if(ch == STK_SET_DEVICE) { // SET DEVICE is ignored getNch(20); } else if(ch == STK_SET_DEVICE_EXT) { // SET DEVICE EXT is ignored getNch(5); } else if(ch == STK_LOAD_ADDRESS) { // LOAD ADDRESS uint16_t newAddress; newAddress = getch() ; newAddress = (newAddress & 0xff) | (getch() << 8); #ifdef RAMPZ // Transfer top bit to RAMPZ RAMPZ = (newAddress & 0x8000) ? 1 : 0; #endif newAddress += newAddress; // Convert from word address to byte address address = newAddress; verifySpace(); } else if(ch == STK_UNIVERSAL) { // UNIVERSAL command is ignored getNch(4); putch(0x00); } /* Write memory, length is big endian and is in bytes */ else if(ch == STK_PROG_PAGE) { // PROGRAM PAGE - we support flash programming only, not EEPROM uint8_t *bufPtr; uint16_t addrPtr; register uint8_t length; getch(); /* getlen() */ length = getch(); getch(); // If we are in RWW section, immediately start page erase if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address); // While that is going on, read in page contents bufPtr = buff; do *bufPtr++ = getch(); while (--length); // If we are in NRWW section, page erase has to be delayed until now. // Todo: Take RAMPZ into account #ifdef MULTI_CALLED if (address < 0x7E00) #endif { if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address); } // Read command terminator, start reply verifySpace(); // If only a partial page is to be programmed, the erase might not be complete. // So check that here #ifdef MULTI_CALLED if (address < 0x7E00) #endif { boot_spm_busy_wait(); #ifdef VIRTUAL_BOOT_PARTITION if ((uint16_t)(void*)address == 0) { // This is the reset vector page. We need to live-patch the code so the // bootloader runs. // // Move RESET vector to WDT vector uint16_t vect = buff[0] | (buff[1]<<8); rstVect = vect; wdtVect = buff[8] | (buff[9]<<8); vect -= 4; // Instruction is a relative jump (rjmp), so recalculate. buff[8] = vect & 0xff; buff[9] = vect >> 8; // Add jump to bootloader at RESET vector buff[0] = 0x7f; buff[1] = 0xce; // rjmp 0x1d00 instruction } #endif // Copy buffer into programming buffer bufPtr = buff; addrPtr = (uint16_t)(void*)address; ch = SPM_PAGESIZE / 2; do { uint16_t a; // a = *bufPtr++; // a |= (*bufPtr++) << 8; a = *((uint16_t *)bufPtr) ; bufPtr += 2 ; __boot_page_fill_short((uint16_t)(void*)addrPtr,a); addrPtr += 2; } while (--ch); // Write from programming buffer __boot_page_write_short((uint16_t)(void*)address); boot_spm_busy_wait(); #if defined(RWWSRE) // Reenable read access to flash boot_rww_enable(); #endif } } /* Read memory block mode, length is big endian. */ else if(ch == STK_READ_PAGE) { register uint8_t length; // READ PAGE - we only read flash getch(); /* getlen() */ length = getch(); getch(); verifySpace(); #ifdef VIRTUAL_BOOT_PARTITION do { // Undo vector patch in bottom page so verify passes if (address == 0) ch=rstVect & 0xff; else if (address == 1) ch=rstVect >> 8; else if (address == 8) ch=wdtVect & 0xff; else if (address == 9) ch=wdtVect >> 8; else ch = pgm_read_byte_near(address); address++; putch(ch); } while (--length); #else #ifdef RAMPZ // Since RAMPZ should already be set, we need to use EPLM directly. // do putch(pgm_read_byte_near(address++)); // while (--length); do { uint8_t result; __asm__ ("elpm %0,Z\n":"=r"(result):"z"(address)); putch(result); address++; } while (--length); #else do putch(pgm_read_byte_near(address++)); while (--length); #endif #endif } /* Get device signature bytes */ else if(ch == STK_READ_SIGN) { // READ SIGN - return what Avrdude wants to hear verifySpace(); putch(SIGNATURE_0); putch(SIGNATURE_1); putch(SIGNATURE_2); } else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */ // Adaboot no-wait mod // watchdogConfig(WATCHDOG_16MS); verifySpace(); #ifdef MULTI_CALLED putch(STK_OK); while (!(UART_SRA & _BV(TXC0))); appStart() ; #endif } else { // This covers the response to commands like STK_ENTER_PROGMODE verifySpace(); } putch(STK_OK); } } void putch(char ch) { #ifndef SOFT_UART while (!(UART_SRA & _BV(UDRE0))); UART_UDR = ch; #else __asm__ __volatile__ ( " com %[ch]\n" // ones complement, carry set " sec\n" "1: brcc 2f\n" " cbi %[uartPort],%[uartBit]\n" " rjmp 3f\n" "2: sbi %[uartPort],%[uartBit]\n" " nop\n" "3: rcall uartDelay\n" " rcall uartDelay\n" " lsr %[ch]\n" " dec %[bitcnt]\n" " brne 1b\n" : : [bitcnt] "d" (10), [ch] "r" (ch), [uartPort] "I" (_SFR_IO_ADDR(UART_PORT)), [uartBit] "I" (UART_TX_BIT) : "r25" ); #endif } uint8_t getch(void) { uint8_t ch; #ifdef LED_DATA_FLASH #ifdef __AVR_ATmega8__ LED_PORT ^= _BV(LED); #else LED_PIN |= _BV(LED); #endif #endif #ifdef SOFT_UART __asm__ __volatile__ ( "1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge " rjmp 1b\n" " rcall uartDelay\n" // Get to middle of start bit "2: rcall uartDelay\n" // Wait 1 bit period " rcall uartDelay\n" // Wait 1 bit period " clc\n" " sbic %[uartPin],%[uartBit]\n" " sec\n" " dec %[bitCnt]\n" " breq 3f\n" " ror %[ch]\n" " rjmp 2b\n" "3:\n" : [ch] "=r" (ch) : [bitCnt] "d" (9), [uartPin] "I" (_SFR_IO_ADDR(UART_PIN)), [uartBit] "I" (UART_RX_BIT) : "r25" ); #else while(!(UART_SRA & _BV(RXC0))) // watchdogReset() ; // if (!(UART_SRA & _BV(FE0))) { /* * A Framing Error indicates (probably) that something is talking * to us at the wrong bit rate. Assume that this is because it * expects to be talking to the application, and DON'T reset the * watchdog. This should cause the bootloader to abort and run * the application "soon", if it keeps happening. (Note that we * don't care that an invalid char is returned...) */ // watchdogReset(); // } ch = UART_UDR; #endif #ifdef LED_DATA_FLASH #ifdef __AVR_ATmega8__ LED_PORT ^= _BV(LED); #else LED_PIN |= _BV(LED); #endif #endif return ch; } #ifdef SOFT_UART // AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6) // Adding 3 to numerator simulates nearest rounding for more accurate baud rates #define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6) #if UART_B_VALUE > 255 #error Baud rate too slow for soft UART #endif void uartDelay() { __asm__ __volatile__ ( "ldi r25,%[count]\n" "1:dec r25\n" "brne 1b\n" "ret\n" ::[count] "M" (UART_B_VALUE) ); } #endif void getNch(uint8_t count) { do getch(); while (--count); verifySpace(); } void verifySpace() { if ( getch() != CRC_EOP) { putch(STK_NOSYNC); // watchdogConfig(WATCHDOG_16MS); // shorten WD timeout // // while (1) // and busy-loop so that WD causes // ; // a reset and app start. } putch(STK_INSYNC); } #if LED_START_FLASHES > 0 void flash_led(uint8_t count) { do { TCNT1 = -(F_CPU/(1024*16)); TIFR1 = _BV(TOV1); while(!(TIFR1 & _BV(TOV1))); //#ifdef __AVR_ATmega8__ LED_PORT ^= _BV(LED); //#else // LED_PIN |= _BV(LED); //#endif watchdogReset(); } while (--count); } #endif // Watchdog functions. These are only safe with interrupts turned off. void watchdogReset() { __asm__ __volatile__ ( "wdr\n" ); } void watchdogConfig(uint8_t x) { WDTCSR = _BV(WDCE) | _BV(WDE); WDTCSR = x; } void appStart() { // watchdogConfig(WATCHDOG_OFF); // __asm__ __volatile__ ( //#ifdef VIRTUAL_BOOT_PARTITION // // Jump to WDT vector // "ldi r30,4\n" // "clr r31\n" //#else // // Jump to RST vector // "clr r30\n" // "clr r31\n" //#endif // "ijmp\n" // ); register void (*p)() ; p = 0 ; if ( pgm_read_byte( (uint16_t)p ) != 0xFF ) { (*p)() ; } }