烧录协议入门:ISP、IAP、ICP 概念与 Bootloader 工作原理
大家好,欢迎来到第二章。上一章我们聊了串口的基本电气特性和通信协议,算是把“路”铺好了。这一章我们聊聊“车”——也就是烧录协议本身。
很多刚入行的朋友会问:为什么单片机不能像硬盘一样,直接拖文件进去就跑?说白了,单片机没有操作系统帮你管理文件系统,它需要一种特殊的方式把程序“灌”进 Flash 里。而 ISP、IAP、ICP 就是三种最常见的灌法。
2.1 三种烧录方式:ISP、IAP、ICP
这三个缩写长得像,但应用场景完全不同。我刚开始接触时也经常搞混,后来用一张表把它们理清了。
| 方式 | 全称 | 烧录时机 | 是否需要外部硬件 | 典型场景 |
|---|---|---|---|---|
| ICP | In-Circuit Programming | 芯片焊接后、上电前 | 需要专用编程器(如 J-Link、ST-Link) | 工厂批量烧录、研发调试 |
| ISP | In-System Programming | 芯片焊接后、上电后 | 需要串口或 SPI 等通信接口 | 小批量生产、现场升级 |
| IAP | In-Application Programming | 应用程序运行中 | 不需要外部硬件,由用户程序自行完成 | OTA 升级、远程固件更新 |
核心区别一句话总结:
- ICP:外部编程器直接操作 Flash,芯片内部不需要任何软件配合。
- ISP:芯片内部有一段出厂固化的 Bootloader,通过串口接收数据并写入 Flash。
- IAP:用户自己的应用程序里包含一段升级代码,运行时可以擦写 Flash 的其他区域。
我个人习惯把 ICP 比作“硬灌”——编程器直接通过 JTAG/SWD 接口操作 Flash 寄存器,芯片本身不跑任何代码。ISP 则是“软灌”——芯片上电后先跑一段出厂自带的引导程序,它负责从串口收数据。而 IAP 是“自灌”——应用程序自己把自己的一部分给覆盖掉。
2.2 Bootloader 工作原理
Bootloader 这个词,字面意思是“引导加载程序”。它是一段在用户应用程序之前运行的特殊代码。为什么需要它?
嗯,这里要注意:单片机上电后,CPU 会从复位向量指向的地址开始执行。这个地址通常就是 Bootloader 的入口。Bootloader 先检查有没有烧录请求——比如检测某个 GPIO 引脚的电平,或者检查串口是否收到了特定命令。如果没有,它就跳转到用户应用程序的入口;如果有,它就进入烧录模式。
我曾经在一个项目中遇到过这样的坑:Bootloader 和应用程序的 Flash 地址分配没规划好,导致 Bootloader 跳转时跑飞了。后来花了整整两天才定位到问题——原来是中断向量表没有重映射。
Bootloader 的典型工作流程:
- 芯片上电,CPU 从复位向量(通常是 0x00000000 或 0x08000000)开始执行。
- 执行 Bootloader 代码,初始化时钟、串口、GPIO 等外设。
- 检查烧录触发条件(引脚电平、串口命令、Flash 标志位等)。
- 如果触发条件满足,进入烧录模式,等待上位机发送固件数据。
- 接收数据,写入用户应用程序所在的 Flash 区域。
- 烧录完成后,跳转到用户应用程序入口。
- 如果触发条件不满足,直接跳转到用户应用程序。
为什么 Bootloader 要自己初始化外设?因为芯片上电后,外设时钟默认是关闭的。如果不初始化串口,你怎么收数据?
2.3 烧录流程概述
不管用 ISP 还是 IAP,烧录流程的核心步骤是差不多的。我画了一张流程图,把整个链路串起来。
这张图里,我特意把“握手与校验”标成了红色。为什么?因为这是最容易出问题的地方。我记得有一次调试,上位机一直报“芯片 ID 不匹配”,查了半天发现是串口电平不匹配——3.3V 的芯片接了 5V 的 USB 转串口模块,虽然没烧坏,但通信已经不可靠了。
2.4 ISP 与 IAP 的详细对比
很多人觉得 ISP 和 IAP 差不多,都是通过串口烧录。其实它们的实现机制和适用场景差别很大。
| 对比项 | ISP | IAP |
|---|---|---|
| Bootloader 来源 | 芯片出厂时固化在 ROM 中,用户无法修改 | 用户自己编写,存储在 Flash 中,可以更新 |
| 触发方式 | 上电时检测特定引脚电平或串口命令 | 应用程序中通过软件触发(如按键、网络命令) |
| Flash 分区 | Bootloader 和应用程序各占一块,互不干扰 | 需要预留 Bootloader 区域,应用程序可覆盖自身 |
| 升级失败风险 | 较低,Bootloader 不会被破坏 | 较高,如果升级过程中断电,可能变砖 |
| 典型应用 | 工厂烧录、现场通过串口升级 | OTA 远程升级、用户自助升级 |
避坑指南:
我曾经在一个 IAP 项目中犯过一个低级错误:Bootloader 和应用程序都使用了同一个串口中断。结果 Bootloader 跳转到应用程序后,串口中断向量没来得及更新,导致应用程序一开串口就进 HardFault。解决方案是在跳转前关闭所有外设中断,并在应用程序的启动代码中重新初始化中断向量表。
2.5 串口烧录的典型协议帧结构
不管用 ISP 还是 IAP,串口烧录协议通常都采用“帧”的形式来传输数据。一个典型的烧录帧包含以下几个部分:
帧结构示例(以 STM32 的 ISP 协议为例):
+--------+--------+--------+--------+--------+--------+--------+
| 帧头 | 命令码 | 数据长度 | 数据区 | 校验码 | 帧尾 |
| 0x7F | 0x00 | 0x04 | 0x01... | CRC16 | 0xFE |
| 1字节 | 1字节 | 1字节 | N字节 | 2字节 | 1字节 |
+--------+--------+--------+--------+--------+--------+--------+
你想想看,为什么要有帧头和帧尾?说白了就是为了“定界”——串口是流式传输,没有帧的概念。接收端需要靠帧头和帧尾来识别一帧数据的开始和结束。校验码则是为了保证数据在传输过程中没有出错。
我个人习惯在帧头使用 0x7F 这种非 ASCII 字符,这样可以避免和普通文本数据混淆。帧尾用 0xFE,和帧头区分开。当然,不同厂家的协议定义不同,但思路是一样的。
2.6 本章小结
这一章我们理清了 ISP、IAP、ICP 的区别,了解了 Bootloader 的工作原理,也看了烧录的完整流程。这些概念是后续章节的基础——从下一章开始,我们会一步步搭建一个实际的串口烧录工具。
嗯,最后留个思考题:如果你的产品已经量产,客户反馈需要远程升级固件,你会选择 ISP 还是 IAP?为什么?想清楚这个问题,你对这两种方式的理解就到位了。