123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724 |
- /**********************************************************/
- /* -Wl,-section-start=bootloader=0x1fc00 */
- /* Optiboot bootloader for Arduino */
- /* */
- /* http://optiboot.googlecode.com */
- /* */
- /* Arduino-maintained version : See README.TXT */
- /* http://code.google.com/p/arduino/ */
- /* */
- /* 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) */
- /* */
- /* Alpha test */
- /* ATmega1280 based devices (Arduino Mega) */
- /* */
- /* Work in progress: */
- /* ATmega644P based devices (Sanguino) */
- /* 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. */
- /* */
- /**********************************************************/
-
- /**********************************************************/
- /* 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: */
- /* */
- /* 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 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 <inttypes.h>
- #include <avr/io.h>
- #include <avr/pgmspace.h>
-
- // <avr/boot.h> uses sts instructions, but this version uses out instructions
- // This saves cycles and program memory.
- #include "boot.h"
-
-
- // We don't use <avr/wdt.h> 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 115200L // 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
-
- #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__ ((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();
- static inline void flash_led(uint8_t);
- uint8_t getLen();
- static inline void watchdogReset();
- void watchdogConfig(uint8_t x);
- #ifdef SOFT_UART
- void uartDelay() __attribute__ ((naked));
- #endif
- 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_ATmega644P__)
- #define RAMSTART (0x100)
- #define NRWWSTART (0xE000)
- #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
-
- /* 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;
- register uint8_t length;
-
- // 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;
- if (!(ch & _BV(EXTRF))) appStart();
-
- #if LED_START_FLASHES > 0
- // Set up Timer 1 for timeout counter
- TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
- #endif
- #ifndef SOFT_UART
- #ifdef __AVR_ATmega8__
- UCSRA = _BV(U2X); //Double speed mode USART
- UCSRB = _BV(RXEN) | _BV(TXEN); // enable Rx & Tx
- UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); // config USART; 8N1
- UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
- #else
- UCSR0A = _BV(U2X0); //Double speed mode USART0
- UCSR0B = _BV(RXEN0) | _BV(TXEN0);
- UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
- UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
- #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) {
- unsigned char which = getch();
- verifySpace();
- if (which == 0x82) {
- /*
- * Send optiboot version as "minor SW version"
- */
- putch(OPTIBOOT_MINVER);
- } else if (which == 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;
-
- 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
- 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
- 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;
- __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) {
- // 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();
- }
- else {
- // This covers the response to commands like STK_ENTER_PROGMODE
- verifySpace();
- }
- putch(STK_OK);
- }
- }
-
- void putch(char ch) {
- #ifndef SOFT_UART
- while (!(UCSR0A & _BV(UDRE0)));
- UDR0 = 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(!(UCSR0A & _BV(RXC0)))
- ;
- if (!(UCSR0A & _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 = UDR0;
- #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) {
- 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"
- );
- }
|