1. 芯片烧录的本质:从 Flash 的视角看问题
很多新手第一次接触单片机时,总会被一套陌生的说法搞懵:“给芯片烧录一下”“用 ISP 下载”“需要 ICP 烧写”“做了 IAP 才能远程升级”。听起来像三个完全不相关的操作,实际上它们都是同一件事——把编译好的固件(二进制机器码)写入芯片内部的 Flash 存储器。
1.1 烧录到底在干什么:一条指令一个地址的搬运
芯片上电后,CPU 会从固定的地址(比如 Cortex-M 内核的 0x08000000)读取指令并执行。所谓“烧录”,就是通过某种通信方式,把 Hex 或 Bin 文件里的数据,按照目标地址逐个写入 Flash。你可以把Flash 想象成一块可以反复擦写的小黑板,烧录就是往黑板上写板书;擦除则是拿板擦把旧内容抹掉。Flash 的特性是先擦后写、按扇区擦除,所以烧录过程经常包含“整片擦除、按扇区写入、校验回读”三步。
这个过程中有两点很容易被忽略:
- Flash 写入前必须擦除,而且擦除是按扇区(sector/block)进行的,不是按字节。比如 STM32F103 的中容量 Flash 扇区大小是 1KB,小容量是 1KB,大容量前 4 个扇区各 16KB,后续每个 64KB。这直接决定了固件升级时不能只改一个字节,至少要按扇区整块更新。
- 烧录通常还要做“校验”环节。正常烧录器写完后会回读数据,和源文件逐字节比对。如果你见过“Verify Failed”这种报错,多半是时钟配置不对、供电不稳或者线材接触不良,而不是 Flash 物理损坏。
1.2 Flash、SRAM、ROM 的简单划分
很多术语让人混淆,是因为存储介质没理清。
- ROM:出厂固化的只读存储器,单片机里常说的 BootROM(引导 ROM)就是出厂写死的程序,用户改不了。
- Flash:可擦写的非易失性存储,用户的应用程序就放这里。掉电不丢数据,但写入需要擦除。
- SRAM:运行内存,高速度、掉电丢数据,放变量和栈。
芯片烧录涉及的其实只是 Flash,但 ISP 机制依赖 BootROM,IAP 机制和 SRAM 有交集(后面会展开)。建议新手画一张“Flash / BootROM / SRAM”三块区域的地图贴在工位旁边,很多概念瞬间就清晰了。
1.3 为什么芯片不能出厂就把固件写好
芯片厂不知道你要用它做什么,所以出厂时 Flash 是空的(或者只有 BootROM)。它提供的是“能被执行程序的硬件框架”,而“程序内容”必须由你通过烧录写进去。这就像一个白板出厂时板擦和粉笔都备好了,但是板书内容要你自己写。
理解了这个本质,你就能明白 ISP、ICP、IAP 的差异,不在“烧录”本身上,而在“烧录的通道和时机”上。
2. ISP / ICP / IAP:三个缩写背后的通道哲学
这三个词同属“芯片编程”领域,却代表着三条完全不同的烧录路径。很多教程把它们并列讲,但新手看完只会背字母,不知道选哪个。我换一种讲法:烧录时,你手里有什么硬件通道,决定了你能用哪种方式。
2.1 ISP:借道已有通信接口的“远程施工”
ISP(In-System Programming)是利用芯片已有的通信接口(UART、SPI、I2C、USB 等)完成程序烧录。它不依赖专用调试器,一根 USB 转 TTL 串口线就能搞定。
原理是:芯片出厂时内置了一段 BootROM(比如 STM32 的系统存储器中的 Bootloader),芯片上电时如果检测到 BOOT 引脚配置正确,就会运行这段 BootROM,等待外部通过串口等接口发送固件数据,然后由 BootROM 自己擦写 Flash。
优点:硬件门槛极低,成本几乎为零,适合没有专用调试器的新手、量产现场维护。缺点:速度可能慢一点;如果芯片的 BootROM 出厂后被人为禁用或损坏,这条通道就断了;另外,能被 BootROM“接管”的引脚通常是固定的,不够灵活。
STC 单片机是最典型的 ISP 玩家。它的串口下载特别出名,但也有个小“玄机”——需要“冷启动”,先断电再上电进入下载状态,因为这个 BootROM 只在复位后的短暂时间内有效。后面我会在第五章细讲这块。
2.2 ICP:专用调试接口的“直接开锁”
ICP(In-Circuit Programming)通过芯片的调试接口(JTAG / SWD)直接对 Flash 编程。它不依赖 BootROM,而是直接利用芯片内部的调试端口,通过 CoreSight / JTAG 访问 CPU 和内存系统,实现擦写 Flash。
优点:速度比 ISP 快、可靠性高,而且可以同时调试——单步、断点、看变量,这些用 ISP 做不了。缺点:需要额外买调试器(ST-Link、J-Link、DAP-Link),成本几十到几百不等;接口引脚一般占用 SWDIO/SWCLK 两到四根线,在 PCB 空间紧张的场合会有点心疼。
我现在做嵌入式开发,首选方案一定是 SWD 调试器。不是因为发烧,而是因为“能调试”这个能力让开发效率高十倍。等你被一个逻辑 bug 折磨两个小时时,你就会懂单步执行的可贵。
2.3 IAP:运行中的自我换血
IAP(In-Application Programming)和前两者有本质不同:它在应用运行过程中,由用户程序自己擦写 Flash,不需要外部工具介入。
这就像你的手机系统更新:你正在用手机,后台下载固件包,然后点击“重启并安装”,整个 Flash 的写入过程是由 System 分区里的升级程序自己完成的,不需要拆机插线。
单片机的 IAP 与此完全同构:
- 程序分成两个区域:**Bootloader(引导区)**和App(应用区)
- 上电后先运行 Bootloader,它检查是否有升级请求
- 没有请求就跳转到 App;有请求就接收新固件(通过串口、CAN、以太网等),写进 App 区
- 写完做校验,再跳转到新 App 执行
这是所有“OTA 升级”“远程升级”的底层基础。没有 IAP,产品出厂后想换固件只能开盖插线,这在物联网时代是不可接受的。
2.4 三个方式怎么选:一张表说清
| 特性 | ISP | ICP | IAP |
|---|---|---|---|
| 外部工具 | USB转串口即可 | 专用调试器 | 无需工具 |
| 速度 | 较慢 | 快 | 取决于传输通道 |
| 可调试 | 不可以 | 可以 | 无法调试 Bootloader 的跳转逻辑 |
| 依赖 BootROM | 依赖 | 不依赖 | 不依赖(但需自写引导程序) |
| 应用场景 | 开发板烧录、现场维护 | 开发调试、量产烧录 | 产品远程升级、APP 内更新 |
注意:这三者并不互斥。实际上,一颗 STM32 往往同时支持 ICP(通过 SWD)和 ISP(通过串口 BootROM),量产时甚至会把“ICP 烧录引导程序 + IAP 远程升级应用”组合使用。搞清楚差异后,面对“为什么不烧不进去”这种问题,你就能先从通道查起,而不是怀疑 Flash 坏了。
3. 各种“ISP”真不是一回事:图像处理、点云配准与芯片烧录的撞名事故
如果你在搜索框里输入“ISP”三个字母,会跳出来一堆让你怀疑人生的结果:ISP 图像处理、ISP 配准、富瀚 ISP、ISP pipeline、FPGA ISP、STC ISP 去弹窗……到底哪个才是芯片烧录?答案是:都是,但只有一个是烧录。
3.1 ISP(Image Signal Processor):摄像头里的“修图圣手”
图像处理领域也有个 ISP,全称 Image Signal Processor(图像信号处理器),是摄像头模组里的核心硬件模块,负责把 CMOS 传感器输出的 RAW 数据转换成我们肉眼能接受的图像:做坏点校正、黑电平校正、去马赛克、白平衡、降噪、色彩校正、锐化、HDR 等。
这就是网上大量出现“isp pipeline”“fpga isp”“富瀚 isp”的原因。富瀚半导体(Fullhan)是做安防视频芯片的公司,它们的 SoC 里集成了 ISP 模块,所以“富瀚 ISP”指的其实是安防摄像头芯片的图像处理单元,而不是芯片烧录。FPGA ISP 则是指在可编程逻辑芯片里用硬件描述语言实现图像处理算法,非常考验寄存器级和流水线设计的功力。
这里给嵌入式开发的朋友一个提醒:你在网上搜问题,如果看到“ISP”这个词,建议先看上下文。如果是摄像头、CMOS、RAW、3A 这些词一起出现,那是在聊图像;如果出现串口、BootROM、Flash,那是在聊烧录。否则你会花一晚上研究图像处理,结果发现跟你的烧录问题毫无关系。
3.2 ICP(Iterative Closest Point):点云配准里的“对齐魔法”
同样的情况出现在 ICP 上。三维点云配准里的 ICP(Iterative Closest Point,迭代最近点算法)是机器人、SLAM、三维重建领域常用的经典算法:通过反复迭代找到两帧点云之间的旋转平移矩阵,把一个点云“对齐”到另一个点云上。
搜索“icp 配准”出来的词条,基本都是这种算法讲解,跟芯片烧录的 ICP(In-Circuit Programming)完全不是一个东西。我认识的一个做视觉算法的同学,第一次听我说“ICP 烧录”,愣了三秒——他满脑子都是最近点迭代。
3.3 避开“撞名陷阱”的方法论
这种撞名在工科领域非常常见(想想 AMBA、DMA、PDMA)。我的建议是:
- 搜索时加限定词:查烧录用“ISP 串口下载”“SWD 烧录”“STM32 ISP”,查图像用“ISP 图像处理器”,查配准用“ICP 点云算法”。
- 看网站类型:电子相关论坛、芯片原厂文档,出现的 ICP/ISP 基本与烧录相关;计算机视觉语义下的 ICP,通常在机器人领域网站出现。
- 把上下文词汇一起搜索:“STM32 ISP”比“ISP”有效十倍;“ICP 配准”则不会误入“在电路编程”。
4. 从 Bootloader 到 App 跳转:IAP 升级的完整拆解
如果说 ISP 和 ICP 是“外部工具帮你擦黑板”,IAP 就是“黑板自己擦自己”。这部分实操性最强,也是最容易出 bug 的地方。我拆成几个关键点来讲,按顺序走通,你就能自己实现一个基础的 IAP 升级功能。
4.1 IAP 分区规划:一张 Flash 地图的诞生
做 IAP 第一步不是写代码,是规划 Flash 布局。以 STM32F103(512KB Flash)为例,常见规划是:
| 起始地址 | 大小 | 内容 |
|---|---|---|
| 0x08000000 | 16KB | Bootloader |
| 0x08004000 | 496KB | App |
如果使用更小的 Flash(比如 64KB),可以 0x08000000 放 4KB Bootloader,App 从 0x08001000 开始。关键是地址对齐:App 的起始地址最好按扇区边界对齐,避免擦除时误删了 Bootloader 一部分。
在 Keil/IAR 里,需要把 App 工程的链接地址(IROM1 / ROM start address)改成 0x08004000(或对应地址)。很多人第一步就卡在这里:App 编译出来还是默认从 0x08000000 开始,结果一跳转就死机。
4.2 跳转细节:中断向量表偏移和栈顶指针
Cortex-M 内核跳转到 App 时,需要做两件事:
- 重新设置 MSP(主栈指针):App 的前 4 字节存放的是初始 MSP 值。
__get_MSP()/__set_MSP()读取并设置。 - 设置 PC 指针:App 的前 4 字节之后(地址偏移 4 处)存放的是复位向量(Reset_Handler),把它赋给 PC。
同时,因为向量表跟着 App 走,必须修改 VTOR 寄存器(SCB->VTOR = APP_ADDRESS),否则所有中断都会错误地跳到 Bootloader 的向量表里执行。
典型跳转代码片段:
#define APP_ADDRESS 0x08004000U typedef void (*pFunction)(void); void jump_to_app(void) { uint32_t app_reset_handler; pFunction jump; // 检查栈顶指针是否合法:一般要求介于 SRAM 范围内 if (((*(volatile uint32_t *)APP_ADDRESS) & 0xFFF00000) != 0x20000000) { while(1); // 栈顶值非法,说明 App 区没有有效固件 } // 关闭全局中断、重设 VTOR __disable_irq(); SCB->VTOR = APP_ADDRESS; app_reset_handler = *(volatile uint32_t *)(APP_ADDRESS + 4U); jump = (pFunction)app_reset_handler; __set_MSP(*(volatile uint32_t *)APP_ADDRESS); jump(); }这段代码里有一个很关键的校验:取 App 地址处的 4 字节,判断高字节是否是 0x2000 开头。因为 Cortex-M 的 SRAM 起始地址一般是 0x20000000,合法的栈顶指针一定落在 SRAM 区域。如果 App 区是空的(擦除后全是 0xFF),这里的值就是 0xFFFFFFFF,跳转必挂。这个防呆写法务必保留。
4.3 “boot 里面定义的变量复位后会怎样”:一个被问烂的问题
热搜词里有“iap boot里面定义的变量复位后会怎样”,这确实是个高频面试题,也是实际排障的死角。
先说结论:如果跳转时没有关闭全局中断,且 Bootloader 里定义的变量还留在 SRAM 中,它们在 App 复位后会被重新初始化(因为 App 的启动代码会执行 C 运行时初始化,把 .bss 清零、把 .data 从 Flash 拷贝到 SRAM),Bootloader 里赋的值全部丢失。
也就是说:你试图通过一个全局变量告诉 App“我是不是从 boot 跳转过来的”,在 App 的 startup 汇编代码里就已经被清零了。数据传递必须在跳转前另想办法。常见的三种方案:
- 在 SRAM 高端地址固定一块保留区:利用 linker 文件预留一小段不参与初始化的 SRAM(比如 linker 里的
RAM_NOINIT段),boot 写入、App 读取。 - 使用 RTC 备份寄存器(Backup Registers):很多 MCU 有备份域寄存器,复位不清零。
- 用户 Option Bytes / 特定 Flash 扇区:自己在 Flash 里留一个小区域专门存状态;但要注意擦写的磨损和稳定性。
我们项目里最常用的就是“保留 SRAM 段 + 备份寄存器双保险”,可靠性很高。
4.4 GD32F103、STM32H750、HC32L136 的 IAP 差异
这部分是热搜词里出现频率最高的几个芯片,我挨个说下实际差异和避坑点。
GD32F103:Arm Cortex-M3 内核,Flash 起始地址同样是 0x08000000,跟 STM32F103 的 IAP 逻辑基本一致。需要注意 GD32 和 STM32 的外设寄存器和 Flash 操作时序并非 100% 一样,IAP 升级代码建议从原厂库或自己的实际板子上验证,不要直接搬 STM32 的 demo。尤其是 Flash 等待周期、页大小、擦除粒度,GD 部分型号跟 STM32 有差异。
STM32H750VBT6(Cortex-M7):这颗芯片官方 Flash 只有 128KB,但实际可以扩展到 2MB 左右,因为它的设计是把用户程序放到外部 QSPI Flash,上电后把外部 Flash 映射到 0x90000000 地址空间。因此 IAP 更像“二次引导”:先跑内部 Bootloader(放在内部 Flash),在 Bootloader 里初始化 QSPI 控制器,再把外挂 Flash 里的 App 固件映射或搬运到 RAM/外部 Flash 地址执行。这里有个常见坑:QSPI Flash 访问速度慢,在跳转到 App 之前一定要把 QSPI 时钟、读模式配置好,否则 App 首条指令都取不出来。建议用内存映射模式(memory-mapped mode),而不是每次手动读数据。
HC32L136(小华半导体低功耗 MCU):Flash 分成多个 Bank,带独立的保护寄存器。IAP 时最容易遇到的问题一是 Flash 擦写的时间窗口(英文资料叫 tPROG/tERASE),二是中断处理顺序——擦写 Flash 期间如果来了高优先级中断,且中断向量表还指向 App,容易造成跳飞。升级流程最好先切换到 Bootloader 的向量表,然后再发擦写命令。
5. 实战中的烧录选择与排坑笔记
看完理论,最后一章按下不表理论,直接说我在项目里怎么选烧录路径、遇到哪些坑、怎么排。
5.1 优先用 ICP 还是 ISP:从调试到量产的一贯逻辑
开发调试阶段:优先 SWD(ICP)。因为要断点、单步、看变量,没有调试器就像没有仪表盘开车。哪怕是 STC 这种传统上只支持串口 ISP 的单片机,现在也有仿真协议(STC-ISP 搭配 U8W/U8 调试器),但体验和 ST-Link 的 SWD 仍不可比。
小批量试产或现场升级:优先 ISP。一根串口线,一个下载软件,成本最低;不需要拆开产品外壳接触调试引脚。前提是产品预留了 ISP 下载口(比如 BOOT 引脚的跳线或按钮)。
量产阶段:离线烧录器 + 烧录座。用 ST-Link/J-Link 一台台连电脑烧,效率低且容易出人为错误。离线烧录器(比如树莓派 Pico 自己改的、各家原厂的量产烧录工具)可以把固件存到烧录器里,按下按钮直接烧。配合烧录座(黄色弹簧座),工人只需要“放芯片-按启动-拿芯片”。
5.2 STC 单片机 ISP 下载的“冷启动”玄机
STC 的 ISP 下载流程和 STM32 不同:它需要“冷启动”——先在下载软件里点“下载”,然后给目标板断电再上电。因为 STC 的 BootROM 在芯片上电复位瞬间才工作,检测到串口数据后才会进入 ISP 模式。如果你在芯片运行时直接按下载,软件会一直等。
正确顺序是:
- 把 USB-TTL 串口的 TX/RX 接到单片机的 RXD/TXD(注意交叉,以及 CH340/CP2102 的电平)。
- 点软件“下载/编程”按钮。
- 给单片机重新上电(拔电再插,或者按复位键配合)。
- 观察下载进度条。
遇到过最常见的坑:STC-ISP 软件在下载时弹窗提示“文件超出缓冲区”或者卡在握手阶段,多半是波特率设置过高、串口号选错、或者板子的 5V 供电不稳。换一个稳定的 USB 口、降低波特率(比如 9600)就解决了。
另外提一句:STC 官方 ISP 软件的体验确实让很多人吐槽,但不要去网上搜所谓的“去弹窗/去广告破解版”,这种来路不明的工具除了安全隐患,还可能悄悄篡改你的固件、植入后门。正规做法是去官网下载最新版,或者如果你真的不喜欢这个软件,考虑换支持 IAP 的芯片,绕开它。
5.3 SWD 接口连不上?先查这几处
SWD 连不上的问题,95% 出在硬件连接而不是调试器本身。我总结了一套排查顺序:
- 线序确认:SWDIO、SWCLK、GND、VCC 四根线,一定要确认调试器引脚和板子丝印一一对应。这个错误低级,但高频发生。
- 目标板供电:目标板必须独立供电(或由调试器供电且电压匹配)。如果只有调试器的 3.3V 而板子需要 5V,有些芯片会起不来。
- SWDIO/SWCLK 是否被复用成 GPIO:如果你的代码初始化时把 SWDIO 引脚当成了普通 IO,调试器就再也连不上了。ST 的做法是硬件复位后、代码运行前的一小段时间窗口内连接调试器,然后全擦除(Erase All)或者禁止从 Flash 启动。有些开发板上有 BOOT0 跳线,可以从 SRAM 启动,绕开被占用的 SWD 引脚。
- 复位电路是否正常:SWD 连接初期,调试器会拉低复位引脚 nRST 让内核停在复位状态,如果板子的复位电容太大或复位芯片异常,耐心等它恢复或手动短接一下复位。
- 目标电压不匹配:SWD 接口的参考电压必须与目标芯片 IO 电压一致。J-Link 的 VTref 引脚通常接目标板 3.3V,如果接错(比如接了 5V 而芯片是 3.3V),可能直接烧掉调试接口。
5.4 Flash 保护位(RDP)与烧录失效
高级 MCU(STM32、GD32、HC32)都有读保护(RDP)。如果芯片开启了 RDP Level 1,未授权工具无法读取 Flash;Level 2 则永久禁止调试。很多人烧录失败,是因为以前测试时打开了读保护,导致 SWD 被锁定。
解除方法:ST-Link Utility / STM32CubeProgrammer 做“Full Chip Erase”可以解除 Level 1(代价是 Flash 全清)。Level 2 通常无法解除,只能换芯片。所以生产线上,除非必要,不建议开 Level 2,万一要返修就麻烦了。
6. 烧录之外的技术演进:OTA 会取代传统烧录吗
聊到最后,还有一件小事值得提:随着物联网普及,“烧录”这个动作本身正在被重塑。很多模组(Wi-Fi 模组、蜂窝模组)出厂时只烧一个极小的 Bootloader,然后通过 OTA 把完整固件推送到设备端,再由设备端的 IAP 逻辑完成后续烧录。工厂里最理想的流程是“只烧一次引导程序,永不拆机”。
但这不代表 ISP/ICP 会消失。恰恰相反——最底层的 Bootloader 必须靠 ISP 或 ICP 写入,一旦写坏了只能退回 ICP 甚至烧录座修复。所以基本功永远是基本功。
过段时间你会发现,烧录这件事真正难的,不是那根线怎么接、软件怎么点,而是你是否理解“程序是怎么被执行的,Flash 又是怎么被擦写的”。把最内核的机制想透,不管是 STC 的冷启动、STM32 的 BootROM、还是 H750 的 QSPI 映射,在你眼里都只是同一个故事的不同章节罢了。
我个人经验是:新手第一块开发板,别急着玩花活,先用 SWD 把点灯程序烧进去、跑起来,再用串口 ISP 烧一次,最后自己写个 IAP 引导程序给自己升个级。这三步走完,芯片烧录这件事你就真的过关了。