STM32串口Bootloader实现方案(含Ymodem协议与Flash操作)

一、系统架构设计

+---------------------+       +---------------------+
|  串口Bootloader     |       |      应用程序(APP)    |
|---------------------|       |---------------------|
| - 接收Ymodem协议数据 |<------| - 用户业务逻辑      |
| - Flash擦写控制     |       | - 中断向量表偏移    |
| - 升级标志管理      |       | - 跳转入口地址      |
+---------------------+       +---------------------+

二、硬件配置

  1. 芯片选型

    • 推荐STM32F103系列(Flash≥256KB,如F103ZET6)

    • 时钟配置:外部8MHz晶振,PLL倍频至72MHz

  2. 外设配置

    // USART1配置(115200波特率)
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    HAL_UART_Init(&huart1);
    
  3. Flash分区方案

    区域 起始地址 大小 功能
    Bootloader 0x08000000 16KB 接收固件+校验
    APP 0x08004000 240KB 用户程序
    参数区 0x08030000 8KB 存储版本/校验值

三、核心代码实现

1. Ymodem协议接收
#define BUFFER_SIZE 2048
uint8_t rx_buffer[BUFFER_SIZE];
volatile uint32_t rx_count = 0;

void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE)) {
        uint8_t data = USART_ReceiveData(USART1);
        if (rx_count < BUFFER_SIZE) {
            rx_buffer[rx_count++] = data;
        }
    }
}

// Ymodem数据包解析
void parse_ymodem_packet() {
    if (rx_buffer[0] == SOH) {
        uint8_t packet_num = rx_buffer[1];
        uint8_t packet_num_inv = rx_buffer[2];
        if (packet_num_inv != ~packet_num) return; // 校验失败
        
        // 写入Flash
        Flash_Write(0x08004000 + packet_num*128, &rx_buffer[3], 128);
        rx_count = 0;
    }
}
2. Flash操作函数
void Flash_Erase(uint32_t addr) {
    FLASH_Unlock();
    FLASH_ErasePage(addr);
    FLASH_Lock();
}

void Flash_Write(uint32_t addr, uint8_t* data, uint16_t len) {
    FLASH_Unlock();
    for (int i=0; i<len; i+=2) {
        uint16_t word = (data[i]<<8) | data[i+1];
        FLASH_ProgramWord(addr+i, word);
    }
    FLASH_Lock();
}
3. 应用程序跳转
typedef void (*app_func)(void);
void Jump_To_App() {
    // 关闭中断
    __disable_irq();
    
    // 设置栈顶指针
    __set_MSP(*(uint32_t*)0x08004000);
    
    // 获取复位向量
    app_func jump = (app_func)*(uint32_t*)(0x08004000 + 4);
    
    // 跳转执行
    jump();
}

四、工程配置要点

  1. MDK工程设置

    • 设置APP起始地址:0x08004000

    • 生成BIN文件:

      fromelf --bin -o app.bin app.axf
      
  2. 启动文件修改

    ; startup_stm32f10x_hd.s
    .word _estack          ; 栈顶地址
    .word Reset_Handler    ; 重置处理函数
    .word NMI_Handler      ; NMI中断
    .word HardFault_Handler; 硬错误处理
    

参考代码 实现stm32串口bootloader www.youwenfan.com/contentcnr/101718.html

五、调试与验证

  1. 串口调试技巧

    // 打印调试信息
    printf("Flash写入地址: 0x%08X\r\n", addr);
    
  2. 错误处理机制

    • CRC校验:对接收的每个数据包计算CRC16

    • 重传机制:超时未收到ACK则重传数据包

  3. 验证流程

    1. 按下BOOT按键进入Bootloader
    2. 串口发送Ymodem命令
    3. 接收完整BIN文件(显示进度条)
    4. 校验Flash数据完整性
    5. 跳转到APP执行
    

六、安全增强方案

  1. 双重校验机制

    • Bootloader CRC32校验

    • APP SHA-256签名验证

  2. 防降级攻击

    // 比较当前版本与备份版本
    if (current_version < backup_version) {
        Jump_To_Backup_App();
    }
    
  3. 密钥存储

    • 使用STM32的OTP区域存储加密密钥

    • 通过安全启动链验证


七、常见问题解决

问题现象 解决方案
串口接收数据乱码 检查波特率设置与硬件流控
Flash写入失败 确保擦除地址对齐扇区边界
程序跳转后复位 检查中断向量表偏移设置
校验失败 添加CRC16校验代码
posted @ 2026-03-06 16:33  yes_go  阅读(21)  评论(0)    收藏  举报