IAP实验原理

Tutorial: 卓越工程师 Category: 嵌入式 Published: 2026-10-23 11:05:29 Views: 0 Likes: 0 Comments: 0

194.2.2 IAP实验原理

本课讲解固件升级概念、Flash 布局和流程图,没有现场新增业务代码;具体源码从第 195 课开始逐段分析。

一、固件升级方式

1.1 ICP、ISP 与 IAP

原笔记中的“RCP、RSP、IP”是语音识别错误。本课实际比较的是 ICP、ISP、IAP:

方式全称执行升级的是谁常用入口典型用途
ICPIn-Circuit Programming,在电路编程PC 上位机 + 调试/烧录器SWD/JTAG开发、生产首次烧录、故障恢复
ISPIn-System Programming,在系统编程芯片厂商固化在 System Memory 中的系统 BootloaderBOOT 引脚选择 System Memory,再用其支持的串口等接口没有用户 Bootloader 时现场烧录
IAPIn-Application Programming,在应用编程用户自己放在主 Flash 中的程序由应用命令、按键、网络消息等触发产品安装后更新用户固件
1.1.1 ICP

课程使用 ST-Link 通过 SWD 烧写,属于 ICP。它的特点是:

  • 不依赖目标板上已有的 APP 是否能运行;
  • 可以整片擦除、写入 Bootloader、参数和初始 APP;
  • 通常需要接触调试接口和专用工具,不适合终端用户远程更新。
1.1.2 ISP

STM32F103 的 System Memory 中有 ST 出厂固化的系统 Bootloader。通过 BOOT 配置让 MCU 从 System Memory 启动后,可以使用芯片支持的通信接口下载代码。以本系列常见的 USART ISP 为例,基本过程是:

  1. 选择 System Memory 启动模式;
  2. 复位,让 ROM/System Memory Bootloader 运行;
  3. 上位机按 ST Bootloader 协议擦写主 Flash;
  4. 恢复从 Main Flash 启动并再次复位。

它和本课程自定义 Bootloader 的区别是:出厂 Bootloader 位于受保护的 System Memory,协议和可用接口由具体芯片型号决定;课程 Bootloader 位于用户主 Flash,功能由开发者决定。

1.1.3 IAP

IAP 指 MCU 在现场通过自身运行的软件改写内部 Flash。通信接口可以是 USART、CAN、USB、以太网或无线链路;接口只负责把新固件送到设备,最终仍要由 MCU 程序执行校验、擦除和编程。

“In-Application”不等于升级期间业务永不停机。本课程的 APP 收到升级命令后会复位,Bootloader 接管并覆盖 APP,完成后再跳转新 APP,因此正常业务在升级期间会中断。IAP 的真正优势是无需外接调试器,也无需用户手动切换到芯片的系统 Bootloader。

ST 的 AN2557说明了 STM32F10x IAP 的基本原则:IAP 程序可通过 USART 等协议重编程内部 Flash,用户 APP 必须使用独立的加载地址并重定位中断向量表。

1.2 IAP 编程

1.2.1 IAP 的组成

一个最小 IAP 系统至少包含:

  1. Bootloader:复位后最先运行,决定升级还是启动 APP,并负责接收、校验和写入固件。
  2. APP:完成产品业务,同时提供升级触发入口。
  3. 持久化状态:在复位后仍能保留的升级标志、版本号等信息,本课程放在内部 Flash 参数页。
  4. 传输协议:本课程用 USART2 + YMODEM。
  5. Flash 分区约定:Bootloader、参数和 APP 不能相互覆盖。
  6. 跳转约定:APP 的链接地址、向量表地址与 Bootloader 的跳转地址必须完全一致。
1.2.2 OTA 技术

OTA 是 Over-The-Air,即通过无线链路分发更新。它描述的是固件如何从远端到达设备,不是 IAP 的同义词:

  • Wi-Fi、蜂窝网络、蓝牙等负责下载,属于 OTA 传输环节;
  • 设备本地校验镜像并改写 Flash,属于 IAP/Bootloader 环节;
  • 有些系统先把新镜像存入外部 Flash,重启后再由 Bootloader 安装;有些双槽系统直接写入非活动分区。

手机升级是更复杂的 OTA 系统,通常还包含签名验证、增量包、恢复分区、回滚和防降级,不能简化成“把文件写入 Flash 再重启”全部细节都相同。

1.2.3 两类 Bootloader
类型存储位置谁提供本课是否使用
STM32 系统 Bootloader芯片 System MemoryST 在出厂时固化ISP 时可能使用,本实验的 IAP 不靠它运行
用户 Bootloader主 Flash 的 0x08000000 起始区域开发者编译、烧写是,本课程升级核心

自定义 Bootloader 本质也是普通 MCU 程序,只是职责特殊、地址固定且应尽量稳定。课程说“Bootloader 永远不变”应理解为产品策略上通常不随普通 APP 一起更新,并非技术上绝对不能升级。量产系统若需要更新 Bootloader,必须设计更严格的保护和恢复链路。

1.2.4 固件分布

配套 .ioc 确认芯片是 STM32F103ZET6,ST 资料确认该型号具有 512 KiB Flash。当前工程的实际分区为:

0x08000000  ┌──────────────────────────────┐
            │ Bootloader                  │ 0x6000 = 24 KiB
0x08006000  ├──────────────────────────────┤
            │ 参数保留区                  │ 0x2000 = 8 KiB
            │ 当前结构位于起始处,仅 12 B │
0x08008000  ├──────────────────────────────┤
            │ APP                         │ 0x78000 = 480 KiB
0x08080000  └──────────────────────────────┘  上边界,不属于 Flash

地址计算如下:

[ 0x08006000-0x08000000=0x6000=24576\ B=24\ KiB ]

[ 0x08008000-0x08006000=0x2000=8192\ B=8\ KiB ]

[ 0x08080000-0x08008000=0x78000=491520\ B=480\ KiB ]

原笔记“中间 2 KiB”的说法不够准确:STM32F103ZE 的单个 Flash 页是 2 KiB,当前参数写回确实只擦写起始的一页;但从参数起始地址到 APP 起始地址之间实际保留了 8 KiB。

各工程的链接设置也与分区对应:

  • Bootloader scatter 文件:IROM1 = 0x08000000,最大 0x6000;
  • APP scatter 文件:IROM1 = 0x08008000,最大 0x78000;
  • APP 的 SCB->VTOR = 0x08008000,让中断向量指向 APP 自己的向量表。
1.2.5 升级流程
1.2.5.1 Bootloader 工作流程

复位后 Bootloader 执行:

硬件初始化
   ↓
读取并校验参数区(magic + checksum)
   ↓
读取 ota_flag
   ├─ 0:检查 APP 栈顶 → 设置 MSP → 跳到 APP Reset_Handler
   ├─ 1:USART2/YMODEM 接收固件 → 擦写 APP 区 → 清 ota_flag → 跳 APP
   └─ 错误:进入课程源码的错误处理/重启路径

升级标志不能在开始接收前就清零。若传输失败或中途掉电,保留 ota_flag=1 可以让下次复位继续停留在 Bootloader 等待恢复。只有接收函数返回成功后,课程代码才清零标志。

1.2.5.2 APP 工作流程

APP 的主要职责仍是实际业务。升级入口只是附加功能:

  1. USART1 中断逐字节收取控制帧;
  2. 解析到合法升级命令后,把 RAM 标志置 1;
  3. 主循环把 Flash 参数区的 ota_flag 改为 1;
  4. 等待日志发送完成后触发系统复位;
  5. 复位后 Bootloader 读到标志并进入升级。

APP 不直接覆盖自身代码,是因为正在同一 Flash 区域执行的程序不适合一边运行一边擦除自己;把更新工作交给独立 Bootloader,边界更清晰,也保留了恢复入口。

1.3 Flash 读写

STM32 Flash 不能像 RAM 那样任意覆盖:

  • 擦除把一整页恢复为 1,即通常读到 0xFF;
  • 编程只能按器件支持的粒度把位从 1 改为 0;
  • 若要把已为 0 的位恢复为 1,必须先擦除所在页;
  • 写入前要解锁 Flash,操作后重新上锁;
  • 所有地址和长度都必须落在允许的 APP/参数区域内。

课程参数更新函数的实际策略是:先把 12 字节配置读入 RAM,修改 ota_flag 和 checksum,再擦除 0x08006000 起始的 2 KiB 页,最后按 32 位字写回 12 字节。

固件接收端则按 2 KiB 页缓冲、擦除、写入并回读比较。回读验证很重要,但它只能验证“本次读回的字节是否和 RAM 缓冲一致”,还应结合完整镜像长度、整包哈希或签名判断镜像是否完整可信。

1.4 YMODEM 协议

YMODEM 建立在 XMODEM/CRC 的分包、序号、确认和重传机制之上。与裸串口连续发送整个 BIN 相比,它提供:

  • 0 号包中的文件名和文件大小;
  • 数据包序号及其反码,用于发现包号错误;
  • 每包 CRC-16,用于检测传输错误;
  • ACK/NAK 确认与超时重传;
  • EOT 结束过程。

接收端持续发送字符 C(0x43)是在请求 CRC-16 模式。课程源码同时定义了 128 字节 SOH 包和 1024 字节 STX 包,但其 Flash 缓冲逻辑是课程基于 ST 示例修改的实现,应以实际互操作测试为准。

YMODEM CRC 解决的是链路传输出错问题,不提供身份认证。攻击者若能替换固件并重新计算 CRC,协议本身无法识别,因此远程产品还要验证数字签名或消息认证码。

1.5 可靠升级还缺什么

本课单槽覆盖流程适合学习,但量产设计至少还应考虑:

  • 镜像合法性:检查首地址 MSP、Reset_Handler 范围、固件长度和目标型号;
  • 完整性:对完整镜像计算 CRC32 或哈希,而不仅是逐包 CRC;
  • 真实性:用公钥签名验证固件来自可信发布者;
  • 掉电恢复:A/B 双槽、外部 Flash 暂存,或明确的可重试恢复模式;
  • 版本策略:升级、防回滚、兼容性和参数迁移;
  • 边界保护:永远不允许接收长度覆盖 Bootloader、参数区或 Flash 末端;
  • 看门狗与超时:不能因为 PC 未发送文件而永久卡死,也不能在擦写关键页时误复位;
  • 日志与结果确认:区分接收成功、Flash 写成功、整包校验成功和 APP 启动成功。

可进一步参考 ST 的 AN4657 IAP 应用笔记及 STM32F103ZE 产品页。

二、学习检查

完成本课后,应能清楚回答:

  1. ICP、ISP、IAP 的执行主体和启动入口分别是什么?
  2. OTA 为什么不是 IAP 的同义词?
  3. 出厂 System Memory Bootloader 与课程自定义 Bootloader 有何区别?
  4. 为什么 APP 既要链接到 0x08008000,又要重定位 VTOR?
  5. 参数区为什么不能只用 RAM 变量保存升级标志?
  6. 为什么 YMODEM CRC 不能代替固件数字签名?