/ bootloaders / optiboot / optiboot.c
optiboot.c
  1  /**********************************************************/
  2  /* Optiboot bootloader for Arduino                        */
  3  /*                                                        */
  4  /* http://optiboot.googlecode.com                         */
  5  /*                                                        */
  6  /* Arduino-maintained version : See README.TXT            */
  7  /* http://code.google.com/p/arduino/                      */
  8  /*                                                        */
  9  /* Heavily optimised bootloader that is faster and        */
 10  /* smaller than the Arduino standard bootloader           */
 11  /*                                                        */
 12  /* Enhancements:                                          */
 13  /*   Fits in 512 bytes, saving 1.5K of code space         */
 14  /*   Background page erasing speeds up programming        */
 15  /*   Higher baud rate speeds up programming               */
 16  /*   Written almost entirely in C                         */
 17  /*   Customisable timeout with accurate timeconstant      */
 18  /*   Optional virtual UART. No hardware UART required.    */
 19  /*   Optional virtual boot partition for devices without. */
 20  /*                                                        */
 21  /* What you lose:                                         */
 22  /*   Implements a skeleton STK500 protocol which is       */
 23  /*     missing several features including EEPROM          */
 24  /*     programming and non-page-aligned writes            */
 25  /*   High baud rate breaks compatibility with standard    */
 26  /*     Arduino flash settings                             */
 27  /*                                                        */
 28  /* Fully supported:                                       */
 29  /*   ATmega168 based devices  (Diecimila etc)             */
 30  /*   ATmega328P based devices (Duemilanove etc)           */
 31  /*                                                        */
 32  /* Alpha test                                             */
 33  /*   ATmega1280 based devices (Arduino Mega)              */
 34  /*                                                        */
 35  /* Work in progress:                                      */
 36  /*   ATmega644P based devices (Sanguino)                  */
 37  /*   ATtiny84 based devices (Luminet)                     */
 38  /*                                                        */
 39  /* Does not support:                                      */
 40  /*   USB based devices (eg. Teensy)                       */
 41  /*                                                        */
 42  /* Assumptions:                                           */
 43  /*   The code makes several assumptions that reduce the   */
 44  /*   code size. They are all true after a hardware reset, */
 45  /*   but may not be true if the bootloader is called by   */
 46  /*   other means or on other hardware.                    */
 47  /*     No interrupts can occur                            */
 48  /*     UART and Timer 1 are set to their reset state      */
 49  /*     SP points to RAMEND                                */
 50  /*                                                        */
 51  /* Code builds on code, libraries and optimisations from: */
 52  /*   stk500boot.c          by Jason P. Kyle               */
 53  /*   Arduino bootloader    http://www.arduino.cc          */
 54  /*   Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
 55  /*   avr-libc project      http://nongnu.org/avr-libc     */
 56  /*   Adaboot               http://www.ladyada.net/library/arduino/bootloader.html */
 57  /*   AVR305                Atmel Application Note         */
 58  /*                                                        */
 59  /* This program is free software; you can redistribute it */
 60  /* and/or modify it under the terms of the GNU General    */
 61  /* Public License as published by the Free Software       */
 62  /* Foundation; either version 2 of the License, or        */
 63  /* (at your option) any later version.                    */
 64  /*                                                        */
 65  /* This program is distributed in the hope that it will   */
 66  /* be useful, but WITHOUT ANY WARRANTY; without even the  */
 67  /* implied warranty of MERCHANTABILITY or FITNESS FOR A   */
 68  /* PARTICULAR PURPOSE.  See the GNU General Public        */
 69  /* License for more details.                              */
 70  /*                                                        */
 71  /* You should have received a copy of the GNU General     */
 72  /* Public License along with this program; if not, write  */
 73  /* to the Free Software Foundation, Inc.,                 */
 74  /* 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
 75  /*                                                        */
 76  /* Licence can be viewed at                               */
 77  /* http://www.fsf.org/licenses/gpl.txt                    */
 78  /*                                                        */
 79  /**********************************************************/
 80  
 81  
 82  /**********************************************************/
 83  /*                                                        */
 84  /* Optional defines:                                      */
 85  /*                                                        */
 86  /**********************************************************/
 87  /*                                                        */
 88  /* BIG_BOOT:                                              */
 89  /* Build a 1k bootloader, not 512 bytes. This turns on    */
 90  /* extra functionality.                                   */
 91  /*                                                        */
 92  /* BAUD_RATE:                                             */
 93  /* Set bootloader baud rate.                              */
 94  /*                                                        */
 95  /* LUDICROUS_SPEED:                                       */
 96  /* 230400 baud :-)                                        */
 97  /*                                                        */
 98  /* SOFT_UART:                                             */
 99  /* Use AVR305 soft-UART instead of hardware UART.         */
100  /*                                                        */
101  /* LED_START_FLASHES:                                     */
102  /* Number of LED flashes on bootup.                       */
103  /*                                                        */
104  /* LED_DATA_FLASH:                                        */
105  /* Flash LED when transferring data. For boards without   */
106  /* TX or RX LEDs, or for people who like blinky lights.   */
107  /*                                                        */
108  /* SUPPORT_EEPROM:                                        */
109  /* Support reading and writing from EEPROM. This is not   */
110  /* used by Arduino, so off by default.                    */
111  /*                                                        */
112  /* TIMEOUT_MS:                                            */
113  /* Bootloader timeout period, in milliseconds.            */
114  /* 500,1000,2000,4000,8000 supported.                     */
115  /*                                                        */
116  /**********************************************************/
117  
118  /**********************************************************/
119  /* Version Numbers!                                       */
120  /*                                                        */
121  /* Arduino Optiboot now includes this Version number in   */
122  /* the source and object code.                            */
123  /*                                                        */
124  /* Version 3 was released as zip from the optiboot        */
125  /*  repository and was distributed with Arduino 0022.     */
126  /* Version 4 starts with the arduino repository commit    */
127  /*  that brought the arduino repository up-to-date with   */
128  /* the optiboot source tree changes since v3.             */
129  /*                                                        */
130  /**********************************************************/
131  
132  /**********************************************************/
133  /* Edit History:					  */
134  /*							  */
135  /* 4.4 WestfW: add initialization of address to keep      */
136  /*             the compiler happy.  Change SC'ed targets. */
137  /*             Return the SW version via READ PARAM       */
138  /* 4.3 WestfW: catch framing errors in getch(), so that   */
139  /*             AVRISP works without HW kludges.           */
140  /*  http://code.google.com/p/arduino/issues/detail?id=368n*/
141  /* 4.2 WestfW: reduce code size, fix timeouts, change     */
142  /*             verifySpace to use WDT instead of appstart */
143  /* 4.1 WestfW: put version number in binary.		  */
144  /**********************************************************/
145  
146  #define OPTIBOOT_MAJVER 4
147  #define OPTIBOOT_MINVER 4
148  
149  #define MAKESTR(a) #a
150  #define MAKEVER(a, b) MAKESTR(a*256+b)
151  
152  asm("  .section .version\n"
153      "optiboot_version:  .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n"
154      "  .section .text\n");
155  
156  #include <inttypes.h>
157  #include <avr/io.h>
158  #include <avr/pgmspace.h>
159  
160  // <avr/boot.h> uses sts instructions, but this version uses out instructions
161  // This saves cycles and program memory.
162  #include "boot.h"
163  
164  
165  // We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
166  
167  #include "pin_defs.h"
168  #include "stk500.h"
169  
170  #ifndef LED_START_FLASHES
171  #define LED_START_FLASHES 0
172  #endif
173  
174  #ifdef LUDICROUS_SPEED
175  #define BAUD_RATE 230400L
176  #endif
177  
178  /* set the UART baud rate defaults */
179  #ifndef BAUD_RATE
180  #if F_CPU >= 8000000L
181  #define BAUD_RATE   115200L // Highest rate Avrdude win32 will support
182  #elsif F_CPU >= 1000000L
183  #define BAUD_RATE   9600L   // 19200 also supported, but with significant error
184  #elsif F_CPU >= 128000L
185  #define BAUD_RATE   4800L   // Good for 128kHz internal RC
186  #else
187  #define BAUD_RATE 1200L     // Good even at 32768Hz
188  #endif
189  #endif
190  
191  /* Switch in soft UART for hard baud rates */
192  #if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz
193  #ifndef SOFT_UART
194  #define SOFT_UART
195  #endif
196  #endif
197  
198  /* Watchdog settings */
199  #define WATCHDOG_OFF    (0)
200  #define WATCHDOG_16MS   (_BV(WDE))
201  #define WATCHDOG_32MS   (_BV(WDP0) | _BV(WDE))
202  #define WATCHDOG_64MS   (_BV(WDP1) | _BV(WDE))
203  #define WATCHDOG_125MS  (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
204  #define WATCHDOG_250MS  (_BV(WDP2) | _BV(WDE))
205  #define WATCHDOG_500MS  (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
206  #define WATCHDOG_1S     (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
207  #define WATCHDOG_2S     (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
208  #ifndef __AVR_ATmega8__
209  #define WATCHDOG_4S     (_BV(WDP3) | _BV(WDE))
210  #define WATCHDOG_8S     (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
211  #endif
212  
213  /* Function Prototypes */
214  /* The main function is in init9, which removes the interrupt vector table */
215  /* we don't need. It is also 'naked', which means the compiler does not    */
216  /* generate any entry or exit code itself. */
217  int main(void) __attribute__ ((naked)) __attribute__ ((section (".init9")));
218  void putch(char);
219  uint8_t getch(void);
220  static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */
221  void verifySpace();
222  static inline void flash_led(uint8_t);
223  uint8_t getLen();
224  static inline void watchdogReset();
225  void watchdogConfig(uint8_t x);
226  #ifdef SOFT_UART
227  void uartDelay() __attribute__ ((naked));
228  #endif
229  void appStart() __attribute__ ((naked));
230  
231  #if defined(__AVR_ATmega168__)
232  #define RAMSTART (0x100)
233  #define NRWWSTART (0x3800)
234  #elif defined(__AVR_ATmega328P__)
235  #define RAMSTART (0x100)
236  #define NRWWSTART (0x7000)
237  #elif defined (__AVR_ATmega644P__)
238  #define RAMSTART (0x100)
239  #define NRWWSTART (0xE000)
240  #elif defined(__AVR_ATtiny84__)
241  #define RAMSTART (0x100)
242  #define NRWWSTART (0x0000)
243  #elif defined(__AVR_ATmega1280__)
244  #define RAMSTART (0x200)
245  #define NRWWSTART (0xE000)
246  #elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
247  #define RAMSTART (0x100)
248  #define NRWWSTART (0x1800)
249  #endif
250  
251  /* C zero initialises all global variables. However, that requires */
252  /* These definitions are NOT zero initialised, but that doesn't matter */
253  /* This allows us to drop the zero init code, saving us memory */
254  #define buff    ((uint8_t*)(RAMSTART))
255  #ifdef VIRTUAL_BOOT_PARTITION
256  #define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4))
257  #define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6))
258  #endif
259  
260  /* main program starts here */
261  int main(void) {
262    uint8_t ch;
263  
264    /*
265     * Making these local and in registers prevents the need for initializing
266     * them, and also saves space because code no longer stores to memory.
267     * (initializing address keeps the compiler happy, but isn't really
268     *  necessary, and uses 4 bytes of flash.)
269     */
270    register uint16_t address = 0;
271    register uint8_t  length;
272  
273    // After the zero init loop, this is the first code to run.
274    //
275    // This code makes the following assumptions:
276    //  No interrupts will execute
277    //  SP points to RAMEND
278    //  r1 contains zero
279    //
280    // If not, uncomment the following instructions:
281    // cli();
282    asm volatile ("clr __zero_reg__");
283  #ifdef __AVR_ATmega8__
284    SP=RAMEND;  // This is done by hardware reset
285  #endif
286  
287    // Adaboot no-wait mod
288    ch = MCUSR;
289    MCUSR = 0;
290    if (!(ch & _BV(EXTRF))) appStart();
291  
292  #if LED_START_FLASHES > 0
293    // Set up Timer 1 for timeout counter
294    TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
295  #endif
296  #ifndef SOFT_UART
297  #ifdef __AVR_ATmega8__
298    UCSRA = _BV(U2X); //Double speed mode USART
299    UCSRB = _BV(RXEN) | _BV(TXEN);  // enable Rx & Tx
300    UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0);  // config USART; 8N1
301    UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
302  #else
303    UCSR0A = _BV(U2X0); //Double speed mode USART0
304    UCSR0B = _BV(RXEN0) | _BV(TXEN0);
305    UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
306    UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
307  #endif
308  #endif
309  
310    // Set up watchdog to trigger after 500ms
311    watchdogConfig(WATCHDOG_1S);
312  
313    /* Set LED pin as output */
314    LED_DDR |= _BV(LED);
315  
316  #ifdef SOFT_UART
317    /* Set TX pin as output */
318    UART_DDR |= _BV(UART_TX_BIT);
319  #endif
320  
321  #if LED_START_FLASHES > 0
322    /* Flash onboard LED to signal entering of bootloader */
323    flash_led(LED_START_FLASHES * 2);
324  #endif
325  
326    /* Forever loop */
327    for (;;) {
328      /* get character from UART */
329      ch = getch();
330  
331      if(ch == STK_GET_PARAMETER) {
332        unsigned char which = getch();
333        verifySpace();
334        if (which == 0x82) {
335  	/*
336  	 * Send optiboot version as "minor SW version"
337  	 */
338  	putch(OPTIBOOT_MINVER);
339        } else if (which == 0x81) {
340  	  putch(OPTIBOOT_MAJVER);
341        } else {
342  	/*
343  	 * GET PARAMETER returns a generic 0x03 reply for
344           * other parameters - enough to keep Avrdude happy
345  	 */
346  	putch(0x03);
347        }
348      }
349      else if(ch == STK_SET_DEVICE) {
350        // SET DEVICE is ignored
351        getNch(20);
352      }
353      else if(ch == STK_SET_DEVICE_EXT) {
354        // SET DEVICE EXT is ignored
355        getNch(5);
356      }
357      else if(ch == STK_LOAD_ADDRESS) {
358        // LOAD ADDRESS
359        uint16_t newAddress;
360        newAddress = getch();
361        newAddress = (newAddress & 0xff) | (getch() << 8);
362  #ifdef RAMPZ
363        // Transfer top bit to RAMPZ
364        RAMPZ = (newAddress & 0x8000) ? 1 : 0;
365  #endif
366        newAddress += newAddress; // Convert from word address to byte address
367        address = newAddress;
368        verifySpace();
369      }
370      else if(ch == STK_UNIVERSAL) {
371        // UNIVERSAL command is ignored
372        getNch(4);
373        putch(0x00);
374      }
375      /* Write memory, length is big endian and is in bytes */
376      else if(ch == STK_PROG_PAGE) {
377        // PROGRAM PAGE - we support flash programming only, not EEPROM
378        uint8_t *bufPtr;
379        uint16_t addrPtr;
380  
381        getch();			/* getlen() */
382        length = getch();
383        getch();
384  
385        // If we are in RWW section, immediately start page erase
386        if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
387  
388        // While that is going on, read in page contents
389        bufPtr = buff;
390        do *bufPtr++ = getch();
391        while (--length);
392  
393        // If we are in NRWW section, page erase has to be delayed until now.
394        // Todo: Take RAMPZ into account
395        if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
396  
397        // Read command terminator, start reply
398        verifySpace();
399  
400        // If only a partial page is to be programmed, the erase might not be complete.
401        // So check that here
402        boot_spm_busy_wait();
403  
404  #ifdef VIRTUAL_BOOT_PARTITION
405        if ((uint16_t)(void*)address == 0) {
406          // This is the reset vector page. We need to live-patch the code so the
407          // bootloader runs.
408          //
409          // Move RESET vector to WDT vector
410          uint16_t vect = buff[0] | (buff[1]<<8);
411          rstVect = vect;
412          wdtVect = buff[8] | (buff[9]<<8);
413          vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
414          buff[8] = vect & 0xff;
415          buff[9] = vect >> 8;
416  
417          // Add jump to bootloader at RESET vector
418          buff[0] = 0x7f;
419          buff[1] = 0xce; // rjmp 0x1d00 instruction
420        }
421  #endif
422  
423        // Copy buffer into programming buffer
424        bufPtr = buff;
425        addrPtr = (uint16_t)(void*)address;
426        ch = SPM_PAGESIZE / 2;
427        do {
428          uint16_t a;
429          a = *bufPtr++;
430          a |= (*bufPtr++) << 8;
431          __boot_page_fill_short((uint16_t)(void*)addrPtr,a);
432          addrPtr += 2;
433        } while (--ch);
434  
435        // Write from programming buffer
436        __boot_page_write_short((uint16_t)(void*)address);
437        boot_spm_busy_wait();
438  
439  #if defined(RWWSRE)
440        // Reenable read access to flash
441        boot_rww_enable();
442  #endif
443  
444      }
445      /* Read memory block mode, length is big endian.  */
446      else if(ch == STK_READ_PAGE) {
447        // READ PAGE - we only read flash
448        getch();			/* getlen() */
449        length = getch();
450        getch();
451  
452        verifySpace();
453  #ifdef VIRTUAL_BOOT_PARTITION
454        do {
455          // Undo vector patch in bottom page so verify passes
456          if (address == 0)       ch=rstVect & 0xff;
457          else if (address == 1)  ch=rstVect >> 8;
458          else if (address == 8)  ch=wdtVect & 0xff;
459          else if (address == 9) ch=wdtVect >> 8;
460          else ch = pgm_read_byte_near(address);
461          address++;
462          putch(ch);
463        } while (--length);
464  #else
465  #ifdef __AVR_ATmega1280__
466  //      do putch(pgm_read_byte_near(address++));
467  //      while (--length);
468        do {
469          uint8_t result;
470          __asm__ ("elpm %0,Z\n":"=r"(result):"z"(address));
471          putch(result);
472          address++;
473        }
474        while (--length);
475  #else
476        do putch(pgm_read_byte_near(address++));
477        while (--length);
478  #endif
479  #endif
480      }
481  
482      /* Get device signature bytes  */
483      else if(ch == STK_READ_SIGN) {
484        // READ SIGN - return what Avrdude wants to hear
485        verifySpace();
486        putch(SIGNATURE_0);
487        putch(SIGNATURE_1);
488        putch(SIGNATURE_2);
489      }
490      else if (ch == 'Q') {
491        // Adaboot no-wait mod
492        watchdogConfig(WATCHDOG_16MS);
493        verifySpace();
494      }
495      else {
496        // This covers the response to commands like STK_ENTER_PROGMODE
497        verifySpace();
498      }
499      putch(STK_OK);
500    }
501  }
502  
503  void putch(char ch) {
504  #ifndef SOFT_UART
505    while (!(UCSR0A & _BV(UDRE0)));
506    UDR0 = ch;
507  #else
508    __asm__ __volatile__ (
509      "   com %[ch]\n" // ones complement, carry set
510      "   sec\n"
511      "1: brcc 2f\n"
512      "   cbi %[uartPort],%[uartBit]\n"
513      "   rjmp 3f\n"
514      "2: sbi %[uartPort],%[uartBit]\n"
515      "   nop\n"
516      "3: rcall uartDelay\n"
517      "   rcall uartDelay\n"
518      "   lsr %[ch]\n"
519      "   dec %[bitcnt]\n"
520      "   brne 1b\n"
521      :
522      :
523        [bitcnt] "d" (10),
524        [ch] "r" (ch),
525        [uartPort] "I" (_SFR_IO_ADDR(UART_PORT)),
526        [uartBit] "I" (UART_TX_BIT)
527      :
528        "r25"
529    );
530  #endif
531  }
532  
533  uint8_t getch(void) {
534    uint8_t ch;
535  
536  #ifdef LED_DATA_FLASH
537  #ifdef __AVR_ATmega8__
538    LED_PORT ^= _BV(LED);
539  #else
540    LED_PIN |= _BV(LED);
541  #endif
542  #endif
543  
544  #ifdef SOFT_UART
545    __asm__ __volatile__ (
546      "1: sbic  %[uartPin],%[uartBit]\n"  // Wait for start edge
547      "   rjmp  1b\n"
548      "   rcall uartDelay\n"          // Get to middle of start bit
549      "2: rcall uartDelay\n"              // Wait 1 bit period
550      "   rcall uartDelay\n"              // Wait 1 bit period
551      "   clc\n"
552      "   sbic  %[uartPin],%[uartBit]\n"
553      "   sec\n"
554      "   dec   %[bitCnt]\n"
555      "   breq  3f\n"
556      "   ror   %[ch]\n"
557      "   rjmp  2b\n"
558      "3:\n"
559      :
560        [ch] "=r" (ch)
561      :
562        [bitCnt] "d" (9),
563        [uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
564        [uartBit] "I" (UART_RX_BIT)
565      :
566        "r25"
567  );
568  #else
569    while(!(UCSR0A & _BV(RXC0)))
570      ;
571    if (!(UCSR0A & _BV(FE0))) {
572        /*
573         * A Framing Error indicates (probably) that something is talking
574         * to us at the wrong bit rate.  Assume that this is because it
575         * expects to be talking to the application, and DON'T reset the
576         * watchdog.  This should cause the bootloader to abort and run
577         * the application "soon", if it keeps happening.  (Note that we
578         * don't care that an invalid char is returned...)
579         */
580      watchdogReset();
581    }
582    
583    ch = UDR0;
584  #endif
585  
586  #ifdef LED_DATA_FLASH
587  #ifdef __AVR_ATmega8__
588    LED_PORT ^= _BV(LED);
589  #else
590    LED_PIN |= _BV(LED);
591  #endif
592  #endif
593  
594    return ch;
595  }
596  
597  #ifdef SOFT_UART
598  // AVR350 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
599  // Adding 3 to numerator simulates nearest rounding for more accurate baud rates
600  #define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
601  #if UART_B_VALUE > 255
602  #error Baud rate too slow for soft UART
603  #endif
604  
605  void uartDelay() {
606    __asm__ __volatile__ (
607      "ldi r25,%[count]\n"
608      "1:dec r25\n"
609      "brne 1b\n"
610      "ret\n"
611      ::[count] "M" (UART_B_VALUE)
612    );
613  }
614  #endif
615  
616  void getNch(uint8_t count) {
617    do getch(); while (--count);
618    verifySpace();
619  }
620  
621  void verifySpace() {
622    if (getch() != CRC_EOP) {
623      watchdogConfig(WATCHDOG_16MS);    // shorten WD timeout
624      while (1)			      // and busy-loop so that WD causes
625        ;				      //  a reset and app start.
626    }
627    putch(STK_INSYNC);
628  }
629  
630  #if LED_START_FLASHES > 0
631  void flash_led(uint8_t count) {
632    do {
633      TCNT1 = -(F_CPU/(1024*16));
634      TIFR1 = _BV(TOV1);
635      while(!(TIFR1 & _BV(TOV1)));
636  #ifdef __AVR_ATmega8__
637      LED_PORT ^= _BV(LED);
638  #else
639      LED_PIN |= _BV(LED);
640  #endif
641      watchdogReset();
642    } while (--count);
643  }
644  #endif
645  
646  // Watchdog functions. These are only safe with interrupts turned off.
647  void watchdogReset() {
648    __asm__ __volatile__ (
649      "wdr\n"
650    );
651  }
652  
653  void watchdogConfig(uint8_t x) {
654    WDTCSR = _BV(WDCE) | _BV(WDE);
655    WDTCSR = x;
656  }
657  
658  void appStart() {
659    watchdogConfig(WATCHDOG_OFF);
660    __asm__ __volatile__ (
661  #ifdef VIRTUAL_BOOT_PARTITION
662      // Jump to WDT vector
663      "ldi r30,4\n"
664      "clr r31\n"
665  #else
666      // Jump to RST vector
667      "clr r30\n"
668      "clr r31\n"
669  #endif
670      "ijmp\n"
671    );
672  }