目录程序的升级方式Boot引脚配置组合复位系统复位软件复位低功耗管理复位电源复位内存分配2) 先建立 Flash 内存模型方案一双区划分Bootloader App2.1 分区示意2.2 关键配置2.3 方案一适用场景2.4 方案一风险与对策方案二三区划分Bootloader App1 App23.1 分区示意3.2 升级流程A/B 分区思想3.3 启动标志位3.4 方案二适用场景3.5 与方案一对比实践章节从零配置双区 Bootloader4.1 统一内存映射头文件4.2 编译与烧录顺序4.3 调试技巧常见问题 FAQ系列扩展可选后续文章程序的升级方式ICP连线编程SWD,ST-Link可以直接覆盖写入到Flash。ISP系统内编程通过内置的BootLoader程序从串口UART、USB、CAN、I2C、SPI等接口来更新程序不依赖烧录器。IAP程序内编程是指在程序运行过程中由MCU自己控制擦除和重写内部Flash完成固件升级。触发特定的条件会进入 IAP Boot Loader程序 自己完成程序的升级更新通常 IAP Boot Loader程序在flash的最开始位置优先判断当前是否需要进行更新程序控制升级1传输升级之后的程序到开发板的存储空间2更改 IAP Boot Loader的升级flag3重新上电 让程序执行boot loaderFLASH是按页进行擦除的1小容量和中容量产品页大小都是1K 大容量产品时2K2flash 起始地址都是0x0800 0000Boot引脚配置组合Boot1Boot0启动模式说明X0主闪存存储器从内置Flash启动正常操作模式01系统存储器从系统存储器启动用于串口/USB等ISP编程11内置SRAM从SRAM启动用于调试和特殊应用注X表示无关(0或1都可以)复位系统复位当发生以下任一事件时产生一个系统复位1. NRST引脚上的低电平(外部复位)2. 窗口看门狗计数终止(WWDG复位)3. 独立看门狗计数终止(IWDG复位)4. 软件复位(SW复位)5. 低功耗管理复位软件复位低功耗管理复位电源复位1上电/掉电复位(POR/PDR复位)2从待机模式中返回电源复位将复位除了备份区域外的所有寄存器。备份域复位烧录的文件类型BIN文件是一种二进制文件它包含了纯粹的二进制数据没有任何附加格式或地址信息。1如果烧录bin文件需要指定flash的地址2中断向量表4字节对齐 64字节第一个四字节是RAM起始地址——RAM起始地址栈大小第二个四字节是复位中断——写入flash地址43函数代码指令码4常量字符串5全局变量初始值keil中配置生成bin文件$K\ARM\ARMCC\bin\fromelf.exe --bin --output.\OUTPUT\L.bin !LHEX文件是用ASCII字符表示的文本文件它包含了程序数据以及地址和校验等附加信息。每行以冒号起始后面每两个字母是一个8bit的16进制数系统内boot loader1通过控制boot0和boot1引脚电平位01复位进入到boot loader模式中2使用串口完成数据的烧录 串口参数默认为115200 默认使用偶校验 数据位8 停止位13存储位置特殊0x1FFF F000自定义1区别:程序本身存放的位置不同 flash中 地址是起始位置0x0800 0000程序冲突的问题boot loader程序和执行的Application程序需要存放在不同的位置AB区存放 B区一定要存放在flash起始的位置假设boot loader程序是4KB≈4096 那么A区程序最小的地址可用就是0x0800 1000考虑安全问题可以安排boot loader比较大的空间来使用16K A程序的地址0x0800 40002功能串口挂起等待接收程序数据写道对应的flash当中复位之后一直执行boot loader只能跳转执行到Application。相同开发板栈大小是一样的 栈顶地址可以通用复位中断地址确定的flash地址程序在编译的时候一定要制定好专门的起始Flash位置内存分配1) 我们使用Bootloader的时候有以下几种方法方案一我们将flash分为两个区分别是bootloader、app。通过更改起始地址和app程序的中断向量偏移地址将bootloader和app放在两个区域。如下图所示方案二我们将flash分为三个区分别是bootloader、app1、app22) 先建立 Flash 内存模型以常见 STM32 为例32KB Bootloader 剩余给 App┌─────────────────────────────────────┐ 0x0800_0000│ Bootloader 区 │ 16~32 KB├─────────────────────────────────────┤ 0x0800_8000 (示例)│ Application 区 │ 剩余 Flash├─────────────────────────────────────┤│ 可选参数/标志位区 │└─────────────────────────────────────┘ 0x080F_FFFF要点起始地址链接脚本里FLASH ORIGIN/LENGTH向量表偏移SCB-VTOR App 起始地址Cortex-M跳转Bootloader 校验 App 后设置 SP、PC 并跳转方案一双区划分Bootloader App2.1 分区示意Flash 存储器校验通过后跳转Bootloader0x0800_0000Application0x0800_8000区域起始地址大小作用Bootloader0x0800_000032 KB上电首先运行负责升级/跳转App0x0800_8000224 KB业务固件2.2 关键配置① Bootloader 链接脚本示例MEMORY{FLASH (rx) : ORIGIN 0x08000000, LENGTH 32KRAM (xrw): ORIGIN 0x20000000, LENGTH 64K}② App 链接脚本MEMORY{FLASH (rx) : ORIGIN 0x08008000, LENGTH 224KRAM (xrw): ORIGIN 0x20000000, LENGTH 64K}③ App 启动时设置向量表偏移#define APP_START_ADDR 0x08008000Uvoid app_init(void){SCB-VTOR APP_START_ADDR;__enable_irq();}或在system_stm32xxx.c中#define VECT_TAB_OFFSET 0x8000USCB-VTOR when the app starts④ Bootloader 跳转到 Apptypedef void (*pFunction)(void);void jump_to_app(uint32_t app_addr){uint32_t sp *(volatile uint32_t *)app_addr;uint32_t pc *(volatile uint32_t *)(app_addr 4);pFunction jump (pFunction)pc;__disable_irq();SCB-VTOR app_addr;__set_MSP(sp);jump();}2.3 方案一适用场景简单 OTA只需一个 App 槽位Flash 较小、成本敏感升级策略先擦 App 区再写入失败则 Bootloader 仍可运行2.4 方案一风险与对策风险对策升级中断导致 App 损坏双备份见方案二或外部 Flash 暂存向量表未重定位启动 HardFault地址配置不一致统一维护memory_map.h方案二三区划分Bootloader App1 App23.1 分区示意Flash 三区模型当前运行OTA 写入校验成功切换BootloaderApp1 运行区App2 备份/升级区典型布局256 KB Flash 示例区域地址范围大小角色Bootloader0x0800_000032 KB启动与切换App10x0800_8000112 KB当前运行固件App20x0802_4000112 KB新固件下载区3.2 升级流程A/B 分区思想1. 下载新固件到 App22. 校验 CRC/签名3. 拷贝 App2 → App1或切换启动标志4. 跳转到 App1 运行OTA 服务器BootloaderApp1 运行区App2 下载区3.3 启动标志位在 Flash 或 EEPROM 中保存typedef struct {uint32_t magic; // 0xDEADBEEFuint8_t active_slot; // 0App1, 1App2uint32_t app1_crc;uint32_t app2_crc;} boot_info_t;Bootloader 逻辑读boot_info校验 active slot 的 CRC失败则尝试另一槽位跳转至有效 App3.4 方案二适用场景需要安全 OTA升级失败可回滚产品级 IoT、汽车、工业设备Flash 足够大通常 ≥ 512 KB 更从容3.5 与方案一对比对比项方案一双区方案二三区Flash 占用省空间多占一个 App 槽升级安全性中等高A/B 备份实现复杂度低中高回滚能力弱强典型产品简单 MCU 产品路由器、智能设备实践章节从零配置双区 Bootloader4.1 统一内存映射头文件// memory_map.h#define FLASH_BASE 0x08000000U#define BL_SIZE (32 * 1024)#define APP_START (FLASH_BASE BL_SIZE)#define APP_SIZE (224 * 1024)#define VECT_TAB_OFFSET BL_SIZEBootloader 与 App 工程都#include memory_map.h避免地址写错。4.2 编译与烧录顺序先编译 Bootloader → 烧录到0x0800_0000再编译 App带偏移链接脚本→ 烧录到0x0800_8000上电Bootloader 运行 → 跳转 App4.3 调试技巧用 J-Link / ST-Link 查看 Flash 内容断点打在jump_to_app前检查 SP、PC用readelf -l app.elf确认 Load Address常见问题 FAQQ1App 能直接烧在 0x0800_0000 吗不能。会与 Bootloader 冲突且向量表地址错误。Q2RAM 需要分区吗一般 Bootloader 与 App 共用 RAM跳转前需关闭外设、清中断避免 Bootloader 状态影响 App。Q3三区时 App1、App2 链接脚本一样吗起始地址不同需两套ORIGIN或同一套模板编译时传入不同宏。Q4如何实现回滚升级前把 App1 备份到 App2新固件失败时 Bootloader 从 App2 恢复或切换启动槽。系列扩展《Cortex-M 向量表与 VTOR 深度解析》《OTA 固件签名与 CRC 校验实战》《从双区升级到三区的迁移指南》《STM32 / ESP32 Bootloader 完整工程模板》