/***************************************************************************** * * AVRPROG compatible boot-loader * Version : 0.83 (Apr. 2008) * Compiler : avr-gcc 4.1.2 / avr-libc 1.4.6 * size : depends on features and startup ( minmal features < 512 words) * by : Martin Thomas, Kaiserslautern, Germany * eversmith@heizung-thomas.de * Additional code and improvements contributed by: * - Uwe Bonnes * - Bjoern Riemer * - Olaf Rempel * * License : Copyright (c) 2006-2008 M. Thomas, U. Bonnes, O. Rempel * Free to use. You have to mention the copyright * owners in source-code and documentation of derived * work. No warranty! (Yes, you can insert the BSD * license here) * * Tested with ATmega8, ATmega16, ATmega162, ATmega32, ATmega324P, * ATmega644, ATmega644P, ATmega128, AT90CAN128 * * - Initial versions have been based on the Butterfly bootloader-code * by Atmel Corporation (Authors: BBrandal, PKastnes, ARodland, LHM) * **************************************************************************** * * See the makefile and readme.txt for information on how to adapt * the linker-settings to the selected Boot Size (BOOTSIZE=xxxx) and * the MCU-type. Other configurations futher down in this file. * * With BOOT_SIMPLE, minimal features and discarded int-vectors * this bootloader has should fit into a a 512 word (1024, 0x400 bytes) * bootloader-section. * ****************************************************************************/ /* TODOs: - check lock-bits set - __bad_interrupt still linked even with modified linker-scripts which needs a default-handler, "wasted": 3 words for AVR5 (>8kB), 2 words for AVR4 - Check watchdog-disable-function in avr-libc. */ // tabsize: 4 /* MCU frequency */ #ifndef F_CPU // #define F_CPU 7372800 #define F_CPU (7372800/2) #endif /* UART Baudrate */ // #define BAUDRATE 9600 // #define BAUDRATE 19200 #define BAUDRATE 115200 /* use "Double Speed Operation" */ //#define UART_DOUBLESPEED /* use second UART on mega128 / can128 / mega162 / mega324p / mega644p */ //#define UART_USE_SECOND /* Device-Type: For AVRProg the BOOT-option is prefered which is the "correct" value for a bootloader. avrdude may only detect the part-code for ISP */ #define DEVTYPE DEVTYPE_BOOT // #define DEVTYPE DEVTYPE_ISP /* * Pin "STARTPIN" on port "STARTPORT" in this port has to grounded * (active low) to start the bootloader */ #define BLPORT PORTC #define BLDDR DDRC #define BLPIN PINC #define BLPNUM PINC7 /* * Define if Watchdog-Timer should be disable at startup */ #define DISABLE_WDT_AT_STARTUP /* * Watchdog-reset is issued at exit * define the timeout-value here (see avr-libc manual) */ #define EXIT_WDT_TIME WDTO_250MS /* * Select startup-mode * SIMPLE-Mode - Jump to bootloader main BL-loop if key is * pressed (Pin grounded) "during" reset or jump to the * application if the pin is not grounded. The internal * pull-up resistor is enabled during the startup and * gets disabled before the application is started. * POWERSAVE-Mode - Startup is separated in two loops * which makes power-saving a little easier if no firmware * is on the chip. Needs more memory * BOOTICE-Mode - to flash the JTAGICE upgrade.ebn file. * No startup-sequence in this mode. Jump directly to the * parser-loop on reset * F_CPU in BOOTICEMODE must be 7372800 Hz to be compatible * with the org. JTAGICE-Firmware * WAIT-mode waits 1 sec for the defined character if nothing * is recived then the user prog is started. */ #define START_SIMPLE //#define START_WAIT //#define START_POWERSAVE //#define START_BOOTICE /* character to start the bootloader in mode START_WAIT */ #define START_WAIT_UARTCHAR 'S' /* wait-time for START_WAIT mode ( t = WAIT_TIME * 10ms ) */ #define WAIT_VALUE 100 /* here: 100*10ms = 1000ms = 1sec */ /* * enable/disable readout of fuse and lock-bits * (AVRPROG has to detect the AVR correctly by device-code * to show the correct information). */ //#define ENABLEREADFUSELOCK /* enable/disable write of lock-bits * WARNING: lock-bits can not be reseted by bootloader (as far as I know) * Only protection no unprotection, "chip erase" from bootloader only * clears the flash but does no real "chip erase" (this is not possible * with a bootloader as far as I know) * Keep this undefined! */ //#define WRITELOCKBITS /* * define the following if the bootloader should not output * itself at flash read (will fake an empty boot-section) */ #define READ_PROTECT_BOOTLOADER #define VERSION_HIGH '0' #define VERSION_LOW '8' #define GET_LOCK_BITS 0x0001 #define GET_LOW_FUSE_BITS 0x0000 #define GET_HIGH_FUSE_BITS 0x0003 #define GET_EXTENDED_FUSE_BITS 0x0002 #include #include #include #include #include #include #include #include #include "chipdef.h" uint8_t gBuffer[SPM_PAGESIZE]; #if defined(BOOTLOADERHASNOVECTORS) #warning "This Bootloader does not link interrupt vectors - see makefile" /* make the linker happy - it wants to see __vector_default */ // void __vector_default(void) { ; } void __vector_default(void) { ; } #endif static void sendchar(uint8_t data) { while (!(UART_STATUS & (1< addr) { boot_page_erase(addr); // Perform page erase boot_spm_busy_wait(); // Wait until the memory is erased. addr += SPM_PAGESIZE; } boot_rww_enable(); } static inline void recvBuffer(pagebuf_t size) { pagebuf_t cnt; uint8_t *tmp = gBuffer; for (cnt = 0; cnt < sizeof(gBuffer); cnt++) { *tmp++ = (cnt < size) ? recvchar() : 0xFF; } } static inline uint16_t writeFlashPage(uint16_t waddr, pagebuf_t size) { uint32_t pagestart = (uint32_t)waddr<<1; uint32_t baddr = pagestart; uint16_t data; uint8_t *tmp = gBuffer; do { data = *tmp++; data |= *tmp++ << 8; boot_page_fill(baddr, data); // call asm routine. baddr += 2; // Select next word in memory size -= 2; // Reduce number of bytes to write by two } while (size); // Loop until all bytes written boot_page_write(pagestart); boot_spm_busy_wait(); boot_rww_enable(); // Re-enable the RWW section return baddr>>1; } static inline uint16_t writeEEpromPage(uint16_t address, pagebuf_t size) { uint8_t *tmp = gBuffer; do { eeprom_write_byte( (uint8_t*)address, *tmp++ ); address++; // Select next byte size--; // Decreas number of bytes to write } while (size); // Loop until all bytes written // eeprom_busy_wait(); return address; } static inline uint16_t readFlashPage(uint16_t waddr, pagebuf_t size) { uint32_t baddr = (uint32_t)waddr<<1; uint16_t data; do { #ifndef READ_PROTECT_BOOTLOADER #warning "Bootloader not read-protected" #if defined(RAMPZ) data = pgm_read_word_far(baddr); #else data = pgm_read_word_near(baddr); #endif #else // don't read bootloader if ( baddr < APP_END ) { #if defined(RAMPZ) data = pgm_read_word_far(baddr); #else data = pgm_read_word_near(baddr); #endif } else { data = 0xFFFF; // fake empty } #endif sendchar(data); // send LSB sendchar((data >> 8)); // send MSB baddr += 2; // Select next word in memory size -= 2; // Subtract two bytes from number of bytes to read } while (size); // Repeat until block has been read return baddr>>1; } static inline uint16_t readEEpromPage(uint16_t address, pagebuf_t size) { do { sendchar( eeprom_read_byte( (uint8_t*)address ) ); address++; size--; // Decrease number of bytes to read } while (size); // Repeat until block has been read return address; } #if defined(ENABLEREADFUSELOCK) static uint8_t read_fuse_lock(uint16_t addr) { uint8_t mode = (1<>8) & 0xFF; UART_BAUD_LOW = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF); #ifdef UART_DOUBLESPEED UART_STATUS = ( 1<= WAIT_VALUE) { BLPORT &= ~(1<> 8) & 0xFF); // Report buffer size in bytes sendchar(sizeof(gBuffer) & 0xFF); // Start buffer load } else if (val == 'B') { pagebuf_t size; size = recvchar() << 8; // Load high byte of buffersize size |= recvchar(); // Load low byte of buffersize val = recvchar(); // Load memory type ('E' or 'F') recvBuffer(size); if (device == DEVTYPE) { if (val == 'F') { address = writeFlashPage(address, size); } else if (val == 'E') { address = writeEEpromPage(address, size); } sendchar('\r'); } else { sendchar(0); } // Block read } else if (val == 'g') { pagebuf_t size; size = recvchar() << 8; // Load high byte of buffersize size |= recvchar(); // Load low byte of buffersize val = recvchar(); // Get memtype if (val == 'F') { address = readFlashPage(address, size); } else if (val == 'E') { address = readEEpromPage(address, size); } // Chip erase } else if (val == 'e') { if (device == DEVTYPE) { eraseFlash(); } sendchar('\r'); // Exit upgrade } else if (val == 'E') { wdt_enable(EXIT_WDT_TIME); // Enable Watchdog Timer to give reset sendchar('\r'); #ifdef WRITELOCKBITS #warning "Extension 'WriteLockBits' enabled" // TODO: does not work reliably // write lockbits } else if (val == 'l') { if (device == DEVTYPE) { // write_lock_bits(recvchar()); boot_lock_bits_set(recvchar()); // boot.h takes care of mask boot_spm_busy_wait(); } sendchar('\r'); #endif // Enter programming mode } else if (val == 'P') { sendchar('\r'); // Leave programming mode } else if (val == 'L') { sendchar('\r'); // return programmer type } else if (val == 'p') { sendchar('S'); // always serial programmer #ifdef ENABLEREADFUSELOCK #warning "Extension 'ReadFuseLock' enabled" // read "low" fuse bits } else if (val == 'F') { sendchar(read_fuse_lock(GET_LOW_FUSE_BITS)); // read lock bits } else if (val == 'r') { sendchar(read_fuse_lock(GET_LOCK_BITS)); // read high fuse bits } else if (val == 'N') { sendchar(read_fuse_lock(GET_HIGH_FUSE_BITS)); // read extended fuse bits } else if (val == 'Q') { sendchar(read_fuse_lock(GET_EXTENDED_FUSE_BITS)); #endif // Return device type } else if (val == 't') { sendchar(DEVTYPE); sendchar(0); // clear and set LED ignored } else if ((val == 'x') || (val == 'y')) { recvchar(); sendchar('\r'); // set device } else if (val == 'T') { device = recvchar(); sendchar('\r'); // Return software identifier } else if (val == 'S') { send_boot(); // Return Software Version } else if (val == 'V') { sendchar(VERSION_HIGH); sendchar(VERSION_LOW); // Return Signature Bytes (it seems that // AVRProg expects the "Atmel-byte" 0x1E last // but shows it first in the dialog-window) } else if (val == 's') { sendchar(SIG_BYTE3); sendchar(SIG_BYTE2); sendchar(SIG_BYTE1); /* ESC */ } else if(val != 0x1b) { sendchar('?'); } } return 0; }