Files

copied
Last update 5 years 11 months
Filesbranchesbootloader
..
bootloader.cc
makefile
bootloader.cc
// Copyright 2013 Olivier Gillet. // // 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, either version 3 of the License, or // (at your option) any later version. // 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, see <http://www.gnu.org/licenses/>. // // ----------------------------------------------------------------------------- // // Simple FSK bootloader #include <avr/boot.h> #include <avr/pgmspace.h> #include <avr/delay.h> #include "avrlib/gpio.h" #include "avrlib/serial.h" #include "avrlib/watchdog_timer.h" #include "avr_audio_bootloader/fsk/decoder.h" using namespace avrlib; using namespace avr_audio_bootloader; Gpio<PortD, 1> led_1_a; Gpio<PortD, 2> led_1_k; Gpio<PortB, 1> led_2_a; Gpio<PortB, 0> led_2_k; Gpio<PortD, 4> in_1; Gpio<PortC, 3> switch_1; Decoder decoder; uint16_t page = 0; uint8_t rx_buffer[SPM_PAGESIZE + 4]; int main(void) __attribute__ ((naked)) __attribute__ ((section (".init9"))); inline void Init() { cli(); switch_1.set_mode(DIGITAL_INPUT); switch_1.High(); led_1_a.set_mode(DIGITAL_OUTPUT); led_1_k.set_mode(DIGITAL_OUTPUT); led_2_a.set_mode(DIGITAL_OUTPUT); led_2_k.set_mode(DIGITAL_OUTPUT); in_1.set_mode(DIGITAL_INPUT); in_1.High(); } void WriteBufferToFlash() { uint16_t i; const uint8_t* p = rx_buffer; eeprom_busy_wait(); boot_page_erase(page); boot_spm_busy_wait(); for (i = 0; i < SPM_PAGESIZE; i += 2) { uint16_t w = *p++; w |= (*p++) << 8; boot_page_fill(page + i, w); } boot_page_write(page); boot_spm_busy_wait(); boot_rww_enable(); } void FlashLeds(bool error) { for (uint8_t i = 0; i < 8; ++i) { _delay_ms(20); if (error) { led_1_a.High(); led_1_k.Low(); } else { led_1_a.Low(); led_1_k.High(); } _delay_ms(20); led_1_a.Low(); led_1_k.Low(); } } uint32_t crc32 (uint32_t crc, uint8_t* buffer, uint8_t length) { crc = crc ^ ~0UL; for (uint8_t i = 0; i < length; ++i) { crc = crc ^ *buffer++; for (uint8_t j = 0; j < 8; j++) { if (crc & 1) { crc = (crc >> 1) ^ 0xEDB88320; } else { crc = crc >> 1; } } } crc = crc ^ ~0UL; return crc; } inline void LoaderLoop() { uint8_t page_byte = 0; decoder.Init(); decoder.Sync(); decoder.set_packet_destination(rx_buffer); page = 0; TCCR2A = 0; TCCR2B = 2; while (1) { // Sample the clock input at 15625 Hz and feed to the FSK decoder. if (TCNT2 >= (8000000 / 8 / 15625 - 1)) { TCNT2 = 0; led_2_a.set_value(page_byte & 1); led_2_k.set_value(!(page_byte & 1)); switch (decoder.PushSample(in_1.value())) { case DECODER_STATE_ERROR_SYNC: FlashLeds(true); decoder.Sync(); break; case DECODER_STATE_END_OF_TRANSMISSION: return; break; case DECODER_STATE_PACKET_RECEIVED: { #ifdef DO_NOT_CHECK_CRC uint32_t crc = 0; uint32_t expected_crc = 0; #else uint32_t crc = crc32(0, rx_buffer, SPM_PAGESIZE); uint32_t expected_crc = \ (static_cast<uint32_t>(rx_buffer[SPM_PAGESIZE + 0]) << 24) | \ (static_cast<uint32_t>(rx_buffer[SPM_PAGESIZE + 1]) << 16) | \ (static_cast<uint32_t>(rx_buffer[SPM_PAGESIZE + 2]) << 8) | \ (static_cast<uint32_t>(rx_buffer[SPM_PAGESIZE + 3]) << 0); #endif // DO_NOT_CHECK_CRC if (crc == expected_crc) { WriteBufferToFlash(); page += SPM_PAGESIZE; ++page_byte; } else { FlashLeds(true); } } decoder.Sync(); break; default: break; } } } } int main(void) { ResetWatchdog(); Init(); if (!switch_1.value()) { FlashLeds(false); LoaderLoop(); FlashLeds(false); } void (*main_entry_point)(void) = 0x0000; main_entry_point(); }
Report a bug