/***************************************************************************** * * Minimal Bootloader for Atmega644(p/a) * * * Based on: * * AVRPROG compatible boot-loader * Version : 0.85 (Dec. 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) * ******************************************************************************/ /* MCU frequency */ #ifndef F_CPU #define F_CPU 8000000 #endif /* UART Baudrate */ #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 PORTD #define BLDDR DDRD #define BLPIN PIND #define BLPNUM PIND0 /* * Watchdog-reset is issued at exit * define the timeout-value here (see avr-libc manual) */ #define EXIT_WDT_TIME WDTO_250MS void __vector_default(void) { ; } /* * 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' #ifdef UART_DOUBLESPEED // #define UART_CALC_BAUDRATE(baudRate) (((F_CPU*10UL) / ((baudRate) *8UL) +5)/10 -1) #define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 4UL)) / ((uint32_t)(baudRate) * 8UL) - 1) #else // #define UART_CALC_BAUDRATE(baudRate) (((F_CPU*10UL) / ((baudRate)*16UL) +5)/10 -1) #define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 8UL)) / ((uint32_t)(baudRate) * 16UL) - 1) #endif #include #include #include #include #include //#include //#include #include "chipdef.h" uint8_t gBuffer[SPM_PAGESIZE]; static void sendchar(uint8_t data) { while (!(UART_STATUS & (1 << UART_TXREADY))) ; UART_DATA = data; } static uint8_t recvchar(void) { while (!(UART_STATUS & (1 << UART_RXREADY))) ; return UART_DATA; } static inline void eraseFlash(void) { // erase only main section (bootloader protection) uint32_t addr = 0; while (APP_END > 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; if (baddr < APP_END) { 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 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 void send_boot(void) { sendchar('A'); sendchar('V'); sendchar('R'); sendchar('B'); sendchar('O'); sendchar('O'); sendchar('T'); } static void (*jump_to_app)(void) = 0x0000; int main(void) { bootloader_wdt_off(); uint16_t address = 0; uint8_t device = 0, val; BLDDR &= ~(1 << BLPNUM); // set as Input BLPORT |= (1 << BLPNUM); // Enable pullup UART_STATUS = (1 << UART_DOUBLE); UART_BAUD_HIGH = 0; UART_BAUD_LOW = 25; UART_CTRL = UART_CTRL_DATA; UART_CTRL2 = UART_CTRL2_DATA; if (BLPIN & (1 << BLPNUM)) { // jump to main app if pin is not grounded and GPIOR2 is zero jump_to_app(); // Jump to application sector } for (;;) { val = recvchar(); // Autoincrement? if (val == 'a') { sendchar('Y'); // Autoincrement is quicker //write address } else if (val == 'A') { address = recvchar(); //read address 8 MSB address = (address << 8) | recvchar(); sendchar('\r'); // Buffer load support } else if (val == 'b') { sendchar('Y'); // Report buffer load supported sendchar((sizeof(gBuffer) >> 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); } 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); } // 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'); // 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 // 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; }