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

STM32平台下Delta固件升级的调度与新固件构建方案咨询

STM32 差分OTA固件升级实现方案

1. 前置Flash分区规划

这是整个方案的运行基础,需按STM32的Flash页大小对齐划分:

  • Bootloader区:占Flash前16~32KB,固定不擦除,负责补丁校验、固件重组、跳转逻辑
  • 旧固件区:存放当前正在运行的完整基准固件,也就是生成差分补丁的比对基准
  • 补丁存储区:存放接收到的jDiff生成的补丁包,大小按固件最大差值的1.2倍预留即可,比如256KB的固件预留64KB补丁区足够覆盖绝大多数场景
  • 新固件暂存区:存放重组完成的新固件,校验通过后再覆盖旧固件区,避免升级中途掉电变砖
    如果Flash空间极度紧张,也可以取消单独的新固件暂存区,用原地升级逻辑,将旧固件的不变段先备份到SRAM/备份Flash再写入新内容,但掉电风险较高,不推荐

2. 补丁调度逻辑实现

所有调度逻辑放在Bootloader中实现,上电后按顺序执行:

  • 上电先启动Bootloader,读取补丁存储区的专属标志位,判断是否存在完整的待处理补丁
  • 无待升级补丁时,直接跳转到旧固件区运行正常业务
  • 有待升级补丁时,先校验补丁包完整性(比如提前写入的CRC32校验值),校验失败直接清空补丁标志、跳转旧固件;校验通过则进入固件重组流程

3. 新固件重组逻辑(适配jDiff补丁包)

首先在Windows端导出jDiff补丁包的格式规则,jDiff的标准输出包含三个核心信息块:不变段偏移、新增段内容、替换段偏移+内容,STM32端只需实现对应解析逻辑即可,参考伪代码如下:

typedef struct {
    uint32_t patch_total_len;
    uint32_t old_fw_crc;
    uint32_t new_fw_crc;
    uint32_t new_fw_size;
} patch_header_t;

#define OP_COPY 0x01 // 不变段,从旧固件拷贝
#define OP_INSERT 0x02 // 新增/替换段,从补丁包取内容

void patch_reconstruct(uint32_t old_fw_addr, uint32_t patch_addr, uint32_t new_fw_addr) {
    // 读取补丁头信息
    patch_header_t header = *(patch_header_t *)patch_addr;
    // 校验当前旧固件是否和补丁匹配,避免刷错
    if(crc32((uint8_t *)old_fw_addr, OLD_FW_SIZE) != header.old_fw_crc) {
        return;
    }
    uint32_t patch_offset = sizeof(patch_header_t);
    uint32_t new_fw_offset = 0;
    while(patch_offset < header.patch_total_len) {
        uint8_t op_type = *(uint8_t *)(patch_addr + patch_offset);
        patch_offset += 1;
        if(op_type == OP_COPY) {
            uint32_t old_offset = *(uint32_t *)(patch_addr + patch_offset);
            uint32_t len = *(uint32_t *)(patch_addr + patch_offset + 4);
            memcpy((void *)(new_fw_addr + new_fw_offset), (void *)(old_fw_addr + old_offset), len);
            new_fw_offset += len;
            patch_offset += 8;
        } else if(op_type == OP_INSERT) {
            uint32_t len = *(uint32_t *)(patch_addr + patch_offset);
            memcpy((void *)(new_fw_addr + new_fw_offset), (void *)(patch_addr + patch_offset + 4), len);
            new_fw_offset += len;
            patch_offset += 4 + len;
        }
    }
    // 重组完成后校验新固件是否正确
    if(crc32((uint8_t *)new_fw_addr, header.new_fw_size) == header.new_fw_crc) {
        set_patch_success_flag(); // 标记重组成功
    }
}

4. 升级后跳转逻辑

重组校验通过后可选择两种升级模式:

  • 覆盖升级:将新固件暂存区的内容逐页擦除写入旧固件区,写完后清空补丁标志,直接跳转旧固件地址运行
  • 免覆盖切换:将中断向量表重定向到新固件暂存区地址,直接跳转到新固件运行,下次启动再判断是否需要覆盖旧固件

注意事项

  • 所有Flash擦写操作都要加步骤标志位,中途掉电后下次上电可继续执行对应步骤,避免变砖
  • 补丁包传输时分包加校验,每包128/256字节,收一包校验一包,错包直接重传,避免整包传输完成才发现错误
  • Bootloader区域要加写保护,避免误擦除导致只能用烧录器救砖

内容的提问来源于stack exchange,提问作者Amin-nano-sys

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 19:24:04