/*************************************************************************** * Copyright (C) 11/2019 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 #define VERSION_STRING "TWIBOOT v2.1" #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; /* ************************************************************************* * write_flash_page * ************************************************************************* */ 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(); } /* write_flash_page */ #if (EEPROM_SUPPORT) /* ************************************************************************* * read_eeprom_byte * ************************************************************************* */ 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 /* (EEPROM_SUPPORT) */ default: data = 0xFF; break; } TWDR = data; TWCR |= (1< IDLE */ case 0xA0: /* prev. SLA+R, data sent, NACK returned -> IDLE */ case 0xC0: LED_RT_OFF(); TWCR |= (1< reset hardware */ case 0xF8: TWCR |= (1< 1) { boot_timeout--; } else if (boot_timeout == 1) { /* trigger app-boot */ cmd = CMD_BOOT_APPLICATION; } } /* TIMER0_OVF_vect */ static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000; /* * For newer devices 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__) /* ************************************************************************* * disable_wdt_timer * ************************************************************************* */ void disable_wdt_timer(void) __attribute__((naked, section(".init3"))); void disable_wdt_timer(void) { MCUSR = 0; WDTCSR = (1<