/*************************************************************************** * Copyright (C) 08/2010 by Olaf Rempel * * razzor@kopf-tisch.de * * * * 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; version 2 of the License, * * * * 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. * ***************************************************************************/ #include #include #include #include /* * atmega8: * Fuse H: 0xda (512 words bootloader) * Fuse L: 0x84 (8Mhz internal RC-Osz., 2.7V BOD) * * atmega88: * Fuse E: 0xfa (512 words bootloader) * Fuse H: 0xdd (2.7V BOD) * Fuse L: 0xc2 (8Mhz internal RC-Osz.) * * atmega168: * Fuse E: 0xfa (512 words bootloader) * Fuse H: 0xdd (2.7V BOD) * Fuse L: 0xc2 (8Mhz internal RC-Osz.) * * atmega328p: * Fuse E: 0xfd (2.7V BOD) * Fuse H: 0xdc (512 words bootloader) * Fuse L: 0xc2 (8Mhz internal RC-Osz.) */ #if defined (__AVR_ATmega8__) #define VERSION_STRING "TWIBOOT m8v2.1" #define SIGNATURE_BYTES 0x1E, 0x93, 0x07 #elif defined (__AVR_ATmega88__) #define VERSION_STRING "TWIBOOT m88v2.1" #define SIGNATURE_BYTES 0x1E, 0x93, 0x0A #elif defined (__AVR_ATmega168__) #define VERSION_STRING "TWIBOOT m168v2.1" #define SIGNATURE_BYTES 0x1E, 0x94, 0x06 #elif defined (__AVR_ATmega328P__) #define VERSION_STRING "TWIBOOTm328pv2.1" #define SIGNATURE_BYTES 0x1E, 0x95, 0x0F #else #error MCU not supported #endif #define EEPROM_SUPPORT 1 #define LED_SUPPORT 1 /* 25ms @8MHz */ #define TIMER_RELOAD (0xFF - 195) /* 40 * 25ms */ #define TIMEOUT 40 #if LED_SUPPORT #define LED_INIT() DDRB = ((1<> 8) & 0xFF, BOOTLOADER_START & 0xFF, #if (EEPROM_SUPPORT) ((E2END +1) >> 8 & 0xFF), (E2END +1) & 0xFF #else 0x00, 0x00 #endif }; /* wait 40 * 25ms = 1s */ static uint8_t boot_timeout = TIMEOUT; volatile static uint8_t cmd = CMD_WAIT; /* flash buffer */ static uint8_t buf[SPM_PAGESIZE]; static uint16_t addr; static void write_flash_page(void) { uint16_t pagestart = addr; uint8_t size = SPM_PAGESIZE; uint8_t *p = buf; if (pagestart >= BOOTLOADER_START) return; boot_page_erase(pagestart); boot_spm_busy_wait(); do { uint16_t data = *p++; data |= *p++ << 8; boot_page_fill(addr, data); addr += 2; size -= 2; } while (size); boot_page_write(pagestart); boot_spm_busy_wait(); boot_rww_enable(); } #if (EEPROM_SUPPORT) static uint8_t read_eeprom_byte(void) { EEARL = addr; EEARH = (addr >> 8); EECR |= (1<> 8); EEDR = val; addr++; #if defined (__AVR_ATmega8__) EECR |= (1< receive data and ACK */ case 0x60: bcnt = 0; LED_RT_ON(); TWCR |= (1< receive data and ACK */ case 0x80: data = TWDR; switch (bcnt) { case 0: switch (data) { case CMD_SWITCH_APPLICATION: case CMD_WRITE_MEMORY: bcnt++; /* no break */ case CMD_WAIT: /* abort countdown */ boot_timeout = 0; break; default: /* boot app now */ cmd = CMD_BOOT_APPLICATION; ack = (0< send data */ case 0xA8: bcnt = 0; LED_RT_ON(); /* prev. SLA+R, data sent, ACK returned -> send data */ case 0xB8: switch (cmd) { case CMD_READ_VERSION: data = info[bcnt++]; bcnt %= sizeof(info); break; case CMD_READ_CHIPINFO: data = chipinfo[bcnt++]; bcnt %= sizeof(chipinfo); break; case CMD_READ_FLASH: data = pgm_read_byte_near(addr++); break; #if (EEPROM_SUPPORT) case CMD_READ_EEPROM: data = read_eeprom_byte(); break; #endif default: data = 0xFF; break; } TWDR = data; TWCR |= (1< reset hardware */ case 0xF8: TWCR |= (1< 1) boot_timeout--; /* trigger app-boot */ else if (boot_timeout == 1) cmd = CMD_BOOT_APPLICATION; } static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000; /* * For newer devices (mega88) the watchdog timer remains active even after a * system reset. So disable it as soon as possible. * automagically called on startup */ #if defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || defined (__AVR_ATmega328P__) void disable_wdt_timer(void) __attribute__((naked, section(".init3"))); void disable_wdt_timer(void) { MCUSR = 0; WDTCSR = (1<