Skip to content

LV060-IAP升级完整流程 ​

一、 为什么还要单独写一篇 ​

前面几篇把零件都拆过了:收帧状态机在 LV045,go 命令与跳转在 LV050,两种镜像的工程配置在 LV030 / LV035。但把 app.img 从串口发进去、到 APP 跑起来,这条链路横跨三个执行位置——USART1 中断、主循环、跳转时的硬件状态切换,任何一篇单独看都只剩半条链路。

常见的三类疑问恰好都落在接缝上:

  • 头收完之后,什么时候算这一帧收完?
  • 校验到底校的是 Flash 里的镜像,还是 SRAM 里的镜像?
  • 同样是 go,为什么 Flash 目标直接跳,SRAM 目标要先搬一次?

本篇只负责把链路串直,细节仍以各篇为准。

二、 端到端链路 ​

以 PC 通过串口发送一份 app.img 为例,一次升级的全部动作如下:

IAP 升级的完整流程

这条链路不是一条直线,图上能看到三件事:

  • 一处上下文分界:iap_rx_poll() 返回 IAP_EVT_FRAME_OK 的那一刻。之前一切都在中断里,只做"把字节装进帧",不校验、不落盘、不打印;之后一切都在主循环里,依次是校验、落盘、回执、等命令、跳转;
  • 一个失败回路:尾部不符、CRC32 不符、或者 3 s 超时,都走同一条退路——丢弃整帧、回到 SCAN 重新对齐,命令行照常可用,不必重启;
  • 一个决定去处的判断:帧头声明的目标地址只有两个合法值,0x08020000 走左路(就地执行),0x20007000 走右路(先落暂存区,go sram 时才搬进内部 RAM)。两路最后汇到同一个跳转动作。

三、 阶段与代码的对照 ​

阶段执行者对应代码结束条件
等命令主循环iap_service_task()收到字节流
对齐帧头中断iap_rx_byte() → IAP_ST_SCAN8 字节滑窗命中 IAPBIN02
读头部中断IAP_ST_HEADER再收 12 字节,得到 N / CRC32 / 目标地址
收载荷中断IAP_ST_PAYLOAD收满 N 字节,逐字节写进外部 SRAM
比对尾部中断IAP_ST_TRAILER8 字节与 IAPEOF02 逐字节相等
帧级校验主循环iap_rx_poll() → IAP_ST_VERIFY载荷 CRC32 与头部声明值相等,上报 FRAME_OK
落盘主循环iap_install_image()擦除 + 编程 + 回读 CRC 全部通过
回执主循环svc_on_frame_ok()打印 send 'go flash' 或 send 'go sram',不自动跳转
跳转主循环cmd_go() → iap_load_app()向量表合法则交出控制权,不返回

四、 三个接缝上的疑问 ​

1. "收完"是双条件,不是收够字节 ​

只按长度判断是不够的:长度字段本身也可能被噪声改写。所以一帧收完要求两件事同时成立:

  • IAP_ST_PAYLOAD 收满头部声明的 N 字节;
  • 紧接着的 8 字节与 IAPEOF02 逐字节相等。

尾部不一致不会去"猜"哪里少了字节,而是直接丢掉整帧、回到 SCAN。另外收帧中途字节间隔超过 IAP_RX_TIMEOUT_MS(3 s)也会判超时复位,避免主机中途取消后设备卡在半帧上。

2. CRC32 校的是 SRAM 里的载荷,不是 Flash ​

按发生顺序,一共三层校验,对象各不相同:

层校验对象位置失败结果
帧级 CRC32外部 SRAM 载荷缓冲里刚收完的 N 字节iap_rx_poll()IAP_ERR_CRC,整帧丢弃,不碰 Flash
落盘回读Flash 里刚写进去的内容iap_write_appbin() / iap_write_sram()IAP_WR_ERR_VERIFY,留在 Bootloader
向量表检查目标地址处的前 8 字节iap_app_is_valid()iap_load_app() 返回 -1,不跳转

也就是说:协议层的完整性由帧级 CRC 保证,介质层的正确性由回读保证。前者防传输错误,后者防擦写错误,两者不能互相替代。

3. go 的分叉只在"要不要搬运" ​

go 是普通文本命令,走命令表,与帧协议没有关系;它只决定"从哪儿开始执行":

命令目标基址动作
go flash0x08020000向量表检查通过后直接跳转,落盘位置就是运行位置
go sram0x20007000先 iap_load_sram_app() 从暂存区 0x08040000 拷 24 KB 进内部 SRAM,回读 CRC 通过再跳
go(不带参数)最近一次装好的镜像同上,按该镜像的类型选路径

SRAM 目标多一次搬运,是因为帧头声明的 0x20007000 是运行位置,而 Flash 里只有暂存位置。这样设计的好处是掉电后镜像还在暂存区,重新上电直接 go sram 就能跑,不必重发帧。

五、 失败一律回到命令行 ​

链路上任何一步失败——超时、尾部不符、CRC 不符、擦写失败、向量表不合法——都不会复位,也不会锁死:状态机回到 SCAN,主循环回到命令行,直接重发即可。这一点是设计目标,不是巧合:升级本来就要面对不可靠的串口和随时可能断电的现场。

六、 与其它各篇的分工 ​

  • 收帧状态机的逐状态细节:LV045《IAP 串口接收与帧处理》
  • 帧格式与 app.img 的打包:LV040《image 镜像文件打包原理与生成》
  • Flash 分区与擦写实现:LV050《IAP 跳转与向量表原理》
  • 两种镜像的工程配置:LV030《FLASH APP 设计》、LV035《SRAM APP 设计》
  • 升级过程中的喂狗:LV055《看门狗问题与解决方案》