ATMEGA4809 UART Bootloader随机损坏致设备变砖问题求助
ATMEGA UART Bootloader随机变砖,0x00E0-0x00FF地址段被异常覆盖
基于Microchip的AN2634 Bootloader文档开发了一款简单的UART Bootloader,使用FT232 USB-UART与ATMEGA通信。Bootloader正常工作时符合预期,但随机出现设备无法启动的情况:设备变砖后既无法进入Bootloader,也无法运行应用程序,必须通过UPDI接口重新编程才能恢复。此问题无特定规律,但均发生在设备USB线缆重启后。读取故障后的程序内存发现,0x00E0至0x00FF地址段的字节被覆盖,类似页面被擦除并重写,但我并未下达写入指令。
已尝试以下操作,但均无效果:
- Bootloader启动时添加延迟
- 开机立即将除LED外的所有引脚设为输入
- 修改熔丝值
- 将
NVMCTRL_BOOTLOCK_bm调用移至最开始(此操作导致Bootloader无法跳转至应用程序)
使用第三方Bootloader(optiboot)测试设备无异常,因此问题必然出在我的Bootloader代码中,恳请提供技术帮助。
#define F_CPU_RESET (20E6/6) #include <avr/io.h> #include <assert.h> #include <stdbool.h> /* Baud rate configuration */ #define BOOT_BAUD (115200) /* Memory configuration * BOOTEND_FUSE * 256 must be above Bootloader Program Memory Usage, * this is 194 bytes at optimization level -O3, so BOOTEND_FUSE = 0x01 */ #define BOOTEND_FUSE (0x02) #define BOOT_SIZE (BOOTEND_FUSE * 0x100) #define MAPPED_APPLICATION_START (MAPPED_PROGMEM_START + BOOT_SIZE) #define MAPPED_APPLICATION_SIZE (MAPPED_PROGMEM_SIZE - BOOT_SIZE) /* Fuse configuration * BOOTEND sets the size (end) of the boot section in blocks of 256 bytes. * APPEND = 0x00 defines the section from BOOTEND*256 to end of Flash as application code. * Remaining fuses have default configuration. */ FUSES = { .OSCCFG = FREQSEL_20MHZ_gc, .SYSCFG0 = 0xC8, .SYSCFG1 = SUT_0MS_gc, .APPEND = 0x00, .BOOTEND = BOOTEND_FUSE }; /* Define application pointer type */ typedef void (*const app_t)(void); //uint8_t EEMEM user_byte = 0; /* Interface function prototypes */ static bool is_bootloader_requested(void); static void init_uart(void); static uint8_t uart_receive(void); static void uart_send(uint8_t byte); static void init_status_led(void); static void toggle_status_led(void); static void initPins(void); static inline void wait_50_ms(void); /* * Main boot function * Put in the constructors section (.ctors) to save Flash. * Naked attribute used since function prologue and epilogue is unused */ __attribute__((naked)) __attribute__((section(".ctors"))) void boot(void) { /* Initialize system for AVR GCC support, expects r1 = 0 */ asm volatile("clr r1"); initPins(); //this is a lot more than 50ms, but that's ok wait_50_ms(); /* Check if entering application or continuing to bootloader */ if(!is_bootloader_requested()) { /* Enable Boot Section Lock */ NVMCTRL.CTRLB = NVMCTRL_BOOTLOCK_bm; /* Go to application, located immediately after boot section */ app_t app = (app_t)(BOOT_SIZE / sizeof(app_t)); app(); } /* Initialize communication interface and LED */ init_uart(); init_status_led(); VPORTB.OUT |= PIN5_bm; /* * Start programming at start for application section * Subtract MAPPED_PROGMEM_START in condition to handle overflow on large flash sizes */ uint8_t *app_ptr = (uint8_t *)MAPPED_APPLICATION_START; while(app_ptr - MAPPED_PROGMEM_START <= (uint8_t *)PROGMEM_END) { /* Receive and echo data before loading to memory */ uint8_t rx_data = uart_receive(); uart_send(rx_data); /* Incremental load to page buffer before writing to Flash */ *app_ptr = rx_data; app_ptr++; if(!((uint16_t)app_ptr % MAPPED_PROGMEM_PAGE_SIZE)) { /* Page boundary reached, Commit page to Flash */ _PROTECTED_WRITE_SPM(NVMCTRL.CTRLA, NVMCTRL_CMD_PAGEERASEWRITE_gc); while(NVMCTRL.STATUS & NVMCTRL_FBUSY_bm); toggle_status_led(); } } //change USERROW back to 0xff, so we go into app after upcoming reboot USERROW.USERROW31 = 0xff; _PROTECTED_WRITE_SPM(NVMCTRL.CTRLA, NVMCTRL_CMD_PAGEERASEWRITE_gc); while(NVMCTRL.STATUS & NVMCTRL_EEBUSY_bm); //turn off led, just in case it's still on after update VPORTB.OUT &= ~PIN5_bm; // /* Issue system reset */ _PROTECTED_WRITE(RSTCTRL.SWRR, RSTCTRL_SWRE_bm); } /* * Boot access request function */ static bool is_bootloader_requested(void) { if(USERROW.USERROW31 == 0x55) { return true; } return false; } /* * Communication interface functions */ static void init_uart(void) { /* Configure UART */ USART3.CTRLB = USART_RXEN_bm | USART_TXEN_bm; /* From datasheet: * Baud rate compensated with factory stored frequency error * Asynchronous communication without Auto-baud (Sync Field) * 20MHz Clock, 3V */ int32_t baud_reg_val = (F_CPU_RESET * 64) / (BOOT_BAUD * 16); // ideal BAUD register value assert(baud_reg_val >= 0x4A); // Verify legal min BAUD register value with max neg comp int8_t sigrow_val = SIGROW.OSC20ERR5V; // read signed error baud_reg_val *= (1024 + sigrow_val); // sum resolution + error baud_reg_val += 512; // compensate for rounding error baud_reg_val /= 1024; // divide by resolution USART3.BAUD = (int16_t) baud_reg_val; // set adjusted baud rate /* Set TxD (PB2) as output */ VPORTB.DIR |= PIN0_bm; } static uint8_t uart_receive(void) { /* Poll for data received */ while(!(USART3.STATUS & USART_RXCIF_bm)); return USART3.RXDATAL; } static void uart_send(uint8_t byte) { /* Data will be sent when TXDATA is written */ USART3.TXDATAL = byte; } static void init_status_led(void) { /* Set LED0 (PB4) as output */ VPORTB.DIR |= PIN5_bm; } static void toggle_status_led(void) { /* Toggle LED0 (PB4) */ VPORTB.OUT ^= PIN5_bm; } static inline void wait_50_ms(void) { for(uint32_t count = 0; count < 500000; count++){ asm volatile ("nop"); } } static void initPins(void){ VPORTA.DIR = 0x00; VPORTB.DIR = 0x20; VPORTC.DIR = 0x00; VPORTD.DIR = 0x00; VPORTE.DIR = 0x00; VPORTF.DIR = 0x00; }
内容的提问来源于stack exchange,提问作者mikerakesh
相关产品推荐
相关产品推荐

