STC单片机在线ISP IAP OTA
Contents
起因
产品一旦装进机壳、发到客户现场,固件总有要改的那天——总不能每次都拆机焊排针接编程器。ISP、IAP、OTA 就是 STC 这类单片机解决“部署之后还能更新固件”的三层手段,一句话概括三者的分工:ISP 解决“怎么把固件写进芯片”,IAP 解决“程序怎么改自己的 Flash”,OTA 解决“没有线怎么把固件传过来”。
ISP
ISP(In-System Programming,在系统编程)。STC 出厂时在芯片内部固化了一段 ISP 监控程序(放在用户不可见的隐藏区):每次冷启动,监控程序先运行,检查串口有没有收到合法的下载命令流——有就进入 ISP 模式接收固件写 Flash,没有就跳到用户程序区执行。这也解释了 STC 下载程序“必须重新上电”的原因:监控程序只在复位后的瞬间值守。
而在线 ISP 靠 IAP_CONTR 寄存器打破了这一点:程序运行中执行 IAP_CONTR=0x60(软复位 + 选择从 ISP 监控区启动),单片机自己复位进 ISP 模式,而不需要冷启动——调试时改一次代码不用反复断电重上,大大减少调试时的麻烦。可配合自定义串口命令(比如收到某个指令才触发跳转),上位机可以直接使用官方提供的 ISP 软件,或者利用官方提供的 Upgrade.exe 自行开发软件。
IAP
IAP(In-Application Programming,在应用编程):让运行中的用户程序能擦写自己的 Flash。这里有个绕不开的矛盾——8051 是直接从 Flash 取指令的,正在运行的扇区一旦被擦除,取指立刻失败、程序跑飞。所以自更新的前提是把“执行代码的区”和“被修改的区”分开,这就是经典双区方案:开发 ISP 程序(引导+更新,负责接收、校验、搬运固件)和 AP 程序(应用业务)两个工程,由 ISP 程序负责 AP 程序的更新和引导。
配置上一般将全部 64K 都设置成 EEPROM,让用户程序空间和 EEPROM 空间完全重合——这样 IAP 命令就能读写包括程序区在内的整个 Flash,实现用户对自己程序空间的修改和控制。本质上 EEPROM 和程序 Flash 是同一块介质,“设置成 EEPROM”只是把擦写权限放开到整个空间而已。

ISP 程序默认在 0 地址——上电最先执行的就是它,校验通过后跳去 AP;AP 程序由于地址不是从 0 开始的,在使用 Keil 开发时需要约束链接器把代码放到正确的地址:在 BL51 Locate 中配置 Code Range(限定代码链接区间),在 Target 中配置 Off-chip Code memory(声明程序空间起点)。两处不一致的后果是中断向量表和绝对调用地址全错——跳过去就是乱跑。
AP 程序跳回 ISP 程序的方法(函数指针指向 0 地址,调用即跳转):
|
|
代码说明
void (*IspProgram)() = ISPPROGRAM;定义一个函数指针并初始化为 0x0,调用IspProgram()时 CPU 把 PC 置 0、从 0 地址重新取指——等效于“跳转到 ISP 程序”;- 这个调用放在串口中断里,收到升级命令的瞬间就跳走。跳过去之后不会返回(ISP 程序要么更新固件要么复位),所以栈不清也无妨,但跳转前应先
EA=0关中断、处理好看门狗(见文末踩坑); - 更省事的等价写法是直接强制转换调用:
((void(*)())0x0000)();,不需要全局指针变量。
OTA
OTA(Over-The-Air,空中升级)= 传输通道 + IAP 写入,本文场景的通道是 LoRa,配合 IAP 功能完成 OTA。要理解 OTA 协议为什么长那样,抓住 LoRa 的两个特点:带宽很低(几百 bps 到几十 kbps,传几十 KB 固件要很久)、无线链路天然丢包。由此推出协议必备的三件事:
- 分包编号:固件切成定长包,逐包确认、丢包重传;
- 断点续传:传一半断电/断链,重新连接后从断点继续,而不是从头再来;
- 先校验后擦写:全部收齐且整包 CRC 通过,才用 IAP 命令擦写 AP 区——写到一半发现包错,AP 区已残缺,设备就变砖了。
流程串起来:节点按包接收固件 → 整包校验通过 → IAP 擦写 AP 区 → 复位,由 0 地址的 ISP 引导程序引导新版本。
踩坑记录与注意事项
- IAP_CONTR 的 0x60 和 0x20 别混:0x60 = 软复位后进 ISP 监控区等待下载;0x20 = 软复位后直接回用户程序区。想“重启”用 0x20,想“进下载模式”用 0x60,写反了现象就是设备一直进监控、或怎么都进不去;
- BL51 Locate 与 Off-chip Code Memory 要一致:一个管链接器放代码的位置,一个声明地址空间布局,配不一致编译能过,跳转后中断全乱(向量表不在预期地址);
- 跳转前清现场:
EA = 0关全局中断、按需喂狗/关看门狗、外设恢复安全态。带着开着的中断跳进新程序,新程序还没初始化中断向量就可能被触发; - ISP 引导区留够裕量:ISP 程序烧进去之后再升级它本身,只能靠冷启动 ISP(拆机重新上电下载),所以引导区宁可多留空间、功能一次做全;
- 全局函数指针的初始化时机:
void (*IspProgram)() = 0x0;是带初值的全局变量,C51 里要等启动代码初始化后才有效;追求绝对稳妥就用((void(*)())0x0000)();直接转换调用; - LoRa OTA 务必先校验后擦写:低带宽链路丢包是常态,边收边写等于拿设备的命赌链路质量;至少要整包 CRC 通过再动 Flash,有余力做双份轮换就更稳。
Author 软件开发大郭
LastMod 2022-05-26