这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【转载】STM32的IAP在线升级实现——从Bootloader到App跳转的完

共1条 1/1 1 跳转至页

【转载】STM32的IAP在线升级实现——从Bootloader到App跳转的完整实践----from阿淼

工程师
2026-10-19 18:16:16     打赏

最近群里好几个兄弟在问IAP怎么搞,说什么”跳转过去就跑飞了”、“升级完断言错误”之类的话。我自己在项目里也踩过不少坑,今天抽空把完整的实现思路整理一下,希望能帮到正在做这个的朋友。

先说下背景:我这次用的是STM32F103RCT6,Flash容量256K,RAM 64K。项目需求是通过UART升级固件,升级完后自动跳转到App运行。

一、Flash分区规划

这是第一步,也是最容易出问题的地方。我的分区方案是这样的:

• Bootloader区:0x08000000 ~ 0x08007FFF(32K)

• App区:0x08008000 ~ 0x0803FFFF(224K)

• 参数存储区:0x08040000 ~ 0x08040FFF(4K,用来存校准参数、版本信息等)

注意STM32F1的Flash是按页操作的,每页2K。所以32K的Bootloader区刚好是16页。App区224K = 112页。分区的时候一定要对齐页边界,不然擦除的时候会出问题。这个我吃过亏,之前没对齐,擦除的时候把Bootloader的代码也给擦了,板子直接变砖,花了一下午才恢复过来。

二、Bootloader代码框架

Bootloader做的事情其实就三件:

1. 初始化系统(时钟、串口、DMA等)

2. 检查是否需要升级(看某个标志位或者超时)

3. 如果需要升级,通过串口把新固件收进来写到App区域;不需要就跳转到App

关键代码贴一下:

typedef void (*pFunction)(void);

void JumpToApp(uint32_t app_addr)
{
    uint32_t jump_addr;
    pFunction jump_to_application;

    // 检查App区起始地址的Stack Pointer是否合法
    // STM32的SP存放在Flash起始地址,MSP必须指向SRAM区域
    if(((*(__IO uint32_t*)app_addr) & 0xFF000000) == 0x20000000)
    {
        // 关闭所有中断
        __disable_irq();

        // 重置SysTick
        SysTick->CTRL = 0;
        SysTick->LOAD = 0;
        SysTick->VAL = 0;

        // 设置向量表偏移 —— 这步最关键
        SCB->VTOR = app_addr;

        // 初始化主堆栈
        __set_MSP(*(__IO uint32_t*)app_addr);

        // 获取复位中断服务程序地址
        jump_addr = *(__IO uint32_t*)(app_addr + 4);

        // 跳转
        jump_to_application = (pFunction)jump_addr;
        jump_to_application();
    }
}

这里有个大坑:向量表偏移!STM32启动后默认从0x08000000开始取向量表,如果你把App的向量表放在0x08008000,跳转过去之后中断会找不到服务程序,直接HardFault。所以必须在跳转前设置SCB->VTOR寄存器。

三、App端的配置

App的启动文件里要做两件事:

1. 在main函数最开头设置向量表偏移:

SCB->VTOR = FLASH_BASE | 0x08008000;  // 向量表偏移量

2. Linker脚本(.ld文件)也要改,确保App的代码和数据都放在0x08008000之后。Keil里就是在Options->Flash里改Start和Size。

四、通信协议设计

我用的协议比较简单,适合串口升级的场景:

• 帧头(2B) + 命令字(1B) + 长度(2B) + 数据(N) + 校验和(1B)

• 升级流程:上位机先发升级请求 -> Bootloader回复ACK -> 上位机开始发数据块 -> Bootloader每收到一页擦除并写入 -> 全部写完校验CRC -> 校验通过设置标志位并跳转

五、结语

1. 调试的时候一定要开J-Link的Flash编程校验,不然写进去不对debug起来要命。Keil里Options->Debug->Flash Download里勾选”Verify”就行。

2. Bootloader代码尽量精简,别往里塞太多东西。万一升级失败你就砖了,代码越小越安全。

3. 建议加个”安全启动”机制:App启动后先跑个自检,不通过就自动回退到旧版本。这个在量产产品里很重要。

4. 升级过程中断电恢复是个问题,我在参数区做了个状态标记,重启后检查状态决定是否继续升级。不然万一写到一半断电,下次启动就找不到App了。

5. 串口波特率别设太高,115200比较稳。我之前设到921600结果有丢包,调了半天才发现是电平转换芯片限速了。

来源: 整理文章为传播相关技术,网络版权归原作者所有,如有侵权,请联系删除。


共1条 1/1 1 跳转至页

回复

匿名不能发帖!请先 [ 登陆 注册 ]