烧录协议入门: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 的典型工作流程:

  1. 芯片上电,CPU 从复位向量(通常是 0x00000000 或 0x08000000)开始执行。
  2. 执行 Bootloader 代码,初始化时钟、串口、GPIO 等外设。
  3. 检查烧录触发条件(引脚电平、串口命令、Flash 标志位等)。
  4. 如果触发条件满足,进入烧录模式,等待上位机发送固件数据。
  5. 接收数据,写入用户应用程序所在的 Flash 区域。
  6. 烧录完成后,跳转到用户应用程序入口。
  7. 如果触发条件不满足,直接跳转到用户应用程序。

为什么 Bootloader 要自己初始化外设?因为芯片上电后,外设时钟默认是关闭的。如果不初始化串口,你怎么收数据?

2.3 烧录流程概述

不管用 ISP 还是 IAP,烧录流程的核心步骤是差不多的。我画了一张流程图,把整个链路串起来。

烧录流程概述图 烧录流程概述 上位机准备固件文件 建立串口连接(波特率协商) 握手与校验(芯片 ID、Flash 大小) 传输数据(分帧发送 + CRC 校验) 写入 Flash(按页擦除 + 编程) 校验与跳转(读回比对 / 复位运行) 注意 每个步骤都可能失败 需要设计超时重试机制 和错误处理逻辑 常见协议 ST 的 DFU 协议 NXP 的 ISP 协议 各家的私有串口协议

这张图里,我特意把“握手与校验”标成了红色。为什么?因为这是最容易出问题的地方。我记得有一次调试,上位机一直报“芯片 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?为什么?想清楚这个问题,你对这两种方式的理解就到位了。