You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 02:37:05