/*************************************************************************** * Copyright (C) 07/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 #define F_CPU 8000000 #include /* * atmega88: * Fuse E: 0xfa (512 words bootloader) * Fuse H: 0xdd (2.7V BOD) * Fuse L: 0xc2 (8Mhz internal RC-Osz.) */ /* 25ms @8MHz */ #define TIMER_RELOAD (0xFF - 195) /* 40 * 25ms */ #define TIMEOUT 40 #define LED_RT (1<= APP_END) 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(); } static uint8_t read_eeprom_byte(void) { EEARL = addr; EEARH = (addr >> 8); EECR |= (1<> 8); EEDR = val; addr++; EECR |= (1< receive data and ACK */ case 0x60: bcnt = 0; PORTB |= LED_RT; 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 */ data = CMD_BOOT_APPLICATION; ack = (0< send data */ case 0xA8: bcnt = 0; PORTB |= LED_RT; /* 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_SIGNATURE: data = signature[bcnt++]; bcnt %= sizeof(signature); break; case CMD_READ_FLASH: data = pgm_read_byte_near(addr++); break; case CMD_READ_EEPROM: data = read_eeprom_byte(); break; 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) = 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 */ void disable_wdt_timer(void) __attribute__((naked, section(".init3"))); void disable_wdt_timer(void) { MCUSR = 0; WDTCSR = (1<