拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

芯片烧录ISP、ICP、IAP全解析:从原理到实战

芯片烧录ISP、ICP、IAP全解析:从原理到实战

1. 芯片烧录到底在烧什么?先把概念理清楚

刚入行那会儿,我第一次听到“烧录”这个词,脑子里浮现的是拿烙铁往电路板上怼的画面。后来才知道,这跟焊接半毛钱关系没有,烧录说的是把固件代码写进芯片里。你可以把它理解成给芯片“装系统”——芯片出厂时里面是空的,跟一块没装系统的硬盘差不多,得把程序灌进去它才能干活。

芯片烧录的本质,是通过特定的硬件接口和通信协议,将编译好的二进制固件写入芯片的Flash或ROM中。这个过程涉及三个关键要素:烧录器(负责产生时序信号和电压)、通信接口(比如SWD、JTAG、UART、SPI等)、目标芯片(接收数据并写入存储区)。三者缺一不可,任何一个环节出问题,烧录都会失败。

那为什么会有ISP、ICP、IAP这三个词?说白了,它们描述的是“在什么阶段、用什么方式把固件写进去”的三种不同场景。ISP是芯片焊到板子上之前或之后,通过芯片自带的BootROM程序来烧;ICP是直接用调试器通过SWD/JTAG接口烧;IAP是芯片已经在运行了,通过程序自己把自己更新掉。三者的核心区别在于谁来执行烧录动作——是芯片内部的固化程序、外部调试器、还是用户自己的应用程序。

这三个概念之所以容易混淆,是因为它们经常出现在同一块板子的不同开发阶段。比如你打样回来第一块板子,可能先用ICP把Bootloader烧进去,然后产线量产时用ISP批量烧录,产品出厂后需要升级时再用IAP远程更新。一个产品完整生命周期里,三种方式可能都会用到。

注意:很多人把“烧录”和“下载”混着用,严格来说下载是把固件从电脑传到烧录器,烧录是烧录器把固件写进芯片,中间隔了一层。但在日常交流中,大家基本混着说,不影响理解。

2. ISP、ICP、IAP三种方式的核心差异

2.1 ISP:靠芯片自带的“引导程序”吃饭

ISP全称In-System Programming,翻译过来叫“在系统编程”。这里的“在系统”指的是芯片已经焊在电路板上了,你不需要把它拆下来。ISP的核心依赖是芯片出厂时固化在BootROM里的一段引导程序,这段程序芯片厂商写死了,你改不了,但它支持通过特定接口(通常是UART、USB、CAN等)接收外部数据并写入用户Flash区。

我拿STM32举例,它的BootROM里就有一段ISP程序,你只需要把BOOT0引脚拉高、BOOT1拉低,复位后芯片就会进入ISP模式,等待上位机通过UART发送固件。这时候你用官方的Flash Loader Demonstrator或者开源的stm32flash工具,选好串口号和波特率,就能把hex或bin文件写进去。

ISP最大的好处是不需要额外的调试器。产线上你只需要一个USB转串口模块,几块钱的成本,就能批量烧录。而且因为用的是芯片自带的程序,不依赖外部工具链,稳定性很高。但缺点也很明显:速度慢。UART波特率一般也就115200到921600,烧个大一点的固件要等好几十秒。另外不同厂商的ISP协议不一样,工具也不通用,ST的不能烧NXP的,换芯片就得换工具。

还有一个坑:有些芯片的ISP模式需要特定引脚上电时序配合,比如某些国产MCU要求在上电瞬间某个引脚保持低电平,晚了或早了都进不去。我第一次用某款国产芯片时就栽在这上面,后来拿示波器抓时序才发现是上电复位时间不够。

2.2 ICP:调试器直接怼,快准狠

ICP全称In-Circuit Programming,叫“在电路编程”。它跟ISP最大的区别是:不依赖芯片自带的BootROM,而是直接用外部调试器通过SWD或JTAG接口访问芯片的调试模块,进而操作Flash控制器。你可以把它理解成“走后门”——调试接口本来就是芯片设计时留给开发者的,权限最高,能直接读写内存和Flash。

ICP的典型工具是J-Link、ST-Link、DAPLink这些调试器。以J-Link为例,你接上SWDIO、SWCLK、GND、VCC四根线,打开J-Flash软件,选好芯片型号,加载固件,点“Program”就完事了。速度比ISP快得多,因为SWD时钟可以跑到几MHz甚至几十MHz,烧个几百KB的固件也就一两秒。

ICP的优势在于速度快、通用性强。同一款J-Link可以烧ARM Cortex-M全系列,换芯片只需要在软件里改型号。而且ICP不占用芯片的通信外设,你UART、SPI该干嘛干嘛,互不影响。产线上如果产量不大,用ICP是最省事的方案。

但ICP也有它的局限。首先你得有调试器,J-Link正版不便宜,虽然国产替代很多,但稳定性和兼容性参差不齐。其次ICP需要引出调试接口,SWD至少占两个引脚,对于引脚资源紧张的芯片来说是个负担。更关键的是,ICP无法在芯片运行时进行——你必须让芯片停下来,调试器才能接管。所以产品出厂后想远程升级,ICP就无能为力了。

实操心得:用ICP烧录时,如果遇到“Cannot connect to target”的报错,先检查三件事——芯片供电是否正常、复位引脚是否被拉低、SWDIO/SWCLK有没有接反。我遇到过好几次是因为板子上电后程序立刻把SWD引脚复用成了GPIO,导致调试器连不上。解决办法是按住复位键再点烧录,或者用“Connect under reset”模式。

2.3 IAP:程序自己给自己“动手术”

IAP全称In-Application Programming,叫“在应用编程”。这个最有意思——芯片已经在跑程序了,程序自己决定要不要更新自己。具体做法是:Flash里分成两块,一块是Bootloader(引导区),一块是Application(应用区)。Bootloader负责检查有没有新固件、要不要更新,Application才是真正干活的业务代码。

当需要升级时,Bootloader通过某种通信方式(UART、CAN、以太网、无线等)接收新固件,把它写到Application区,然后跳转过去执行。整个过程不需要拆机、不需要接调试器,甚至不需要人到现场。这就是为什么智能家居设备能通过手机App推送固件更新——背后就是IAP在干活。

IAP的关键在于Bootloader的设计。你得考虑:固件怎么分包传输、怎么校验完整性(CRC32还是MD5)、升级失败怎么回滚、断电了怎么办。我见过太多项目因为Bootloader没写好,升级到一半断电直接变砖。正确的做法是双区备份——新固件先写到备份区,校验通过后再拷贝到运行区,这样即使拷贝过程中断电,Bootloader下次上电还能从备份区恢复。

还有一个容易忽略的点:中断向量表的偏移。ARM Cortex-M芯片的中断向量表默认在Flash起始地址,但Application区通常不在0x08000000,所以需要在Application的启动代码里设置SCB->VTOR寄存器,把向量表偏移到Application的起始地址。忘了这一步,中断就会跳到Bootloader的向量表里去,程序跑飞。

2.4 三种方式对比速查

对比维度ISPICPIAP
执行主体芯片自带BootROM外部调试器用户Bootloader
接口UART/USB/CANSWD/JTAG任意通信接口
速度慢(百KB级需数十秒)快(百KB级1-2秒)取决于通信带宽
是否需要调试器否是否
能否远程升级否否是
占用引脚通信引脚SWDIO+SWCLK通信引脚
典型场景产线量产研发调试现场升级

3. 从零搭建一套完整的烧录方案

3.1 硬件准备与接线要点

假设你手头有一块STM32F103的板子,想把这三种方式都跑一遍。你需要准备:USB转TTL模块(CH340就行)、ST-Link V2调试器、杜邦线若干、目标板。

先看ISP接线。STM32F103的ISP通过UART1,引脚是PA9(TX)和PA10(RX)。把USB转TTL的TX接PA10,RX接PA9,GND对GND。然后BOOT0拉高到3.3V,BOOT1拉低到GND。注意BOOT0不能悬空,悬空时电平不确定,可能进不去ISP。我一般直接用一个跳线帽把BOOT0接到3.3V排针上。

ICP接线更简单。ST-Link V2的SWDIO接PA13,SWCLK接PA14,GND接GND,3.3V接3.3V。四根线搞定。注意有些板子的SWD引脚被外部电路拉了上拉或下拉电阻,阻值太小会影响信号质量,一般4.7K到10K没问题,1K以下就可能出问题。

IAP不需要额外接线,用你Application里选定的通信接口就行。比如用UART做IAP,那还是PA9/PA10,但这次不需要动BOOT引脚,因为Bootloader是你自己写的,跳转逻辑由你控制。

注意:接线时务必断电操作,带电插拔杜邦线容易打火,严重时可能烧掉芯片的IO口。我亲眼见过同事带电插拔把STM32的PA13烧了,SWD再也连不上,只能换芯片。

3.2 ISP烧录实操:以STM32为例

先装好STM32CubeProgrammer,这是ST官方工具,支持UART、USB、SWD多种方式。打开软件,选择UART模式,端口选CH340对应的COM号,波特率选115200,奇偶校验Even,数据位8,停止位1。这些参数是STM32 BootROM规定的,不能随便改。

然后板子上电,BOOT0保持高电平。点击“Connect”,如果一切正常,软件会读出芯片型号和Flash大小。这时候你点“Open file”加载编译好的hex文件,再点“Download”就开始烧录了。烧录完成后,把BOOT0跳回GND,复位,程序就跑起来了。

整个过程最常遇到的问题就是连不上。排查顺序:先确认COM口选对了没有,设备管理器里看看CH340驱动装没装;再确认BOOT0电平对不对,拿万用表量一下;然后检查TX/RX有没有接反,很多人在这里翻车。如果还不行,试试降低波特率到9600,有些CH340模块在高波特率下不稳定。

3.3 ICP烧录实操:J-Link与STM32CubeProgrammer配合

ICP我用得最多的是STM32CubeProgrammer加ST-Link,或者J-Flash加J-Link。以STM32CubeProgrammer为例,选择SWD模式,频率默认4MHz,点击Connect。如果芯片之前跑的程序把SWD引脚复用了,就连不上,这时候需要按住复位键,点Connect,等软件开始连接了再松开复位键。

连接成功后,界面会显示Flash内容。你可以直接加载hex文件然后点Download,也可以先Erase再Program。我一般习惯先全片擦除再烧,避免旧数据残留导致奇怪的问题。烧录速度方面,STM32F103的64KB Flash,SWD 4MHz下大概1.5秒烧完,比ISP快了一个数量级。

J-Flash的用法类似,但J-Link的兼容性更好,支持芯片型号更多。如果你用的是国产MCU,比如GD32、APM32,J-Link可能需要手动添加芯片支持包,或者选一个兼容的STM32型号凑合用。我试过用J-Link烧GD32F103,选STM32F103的配置也能烧进去,但Flash算法可能不完全匹配,烧录大文件时偶尔会出错。

3.4 IAP实现:手把手写一个Bootloader

IAP的Bootloader我写过不下十个版本,从最简单的UART升级到带AES加密的无线升级都做过。这里给一个最精简的UART IAP框架,基于STM32 HAL库。

Flash分区规划:Bootloader占0x08000000到0x08007FFF(32KB),Application占0x08008000到0x0801FFFF(96KB)。Bootloader启动后先检查一个标志位,如果标志位是0x5A5A5A5A,就进入升级模式,否则跳转到Application。

#define APP_ADDR 0x08008000 #define UPGRADE_FLAG_ADDR 0x08007FF0 #define UPGRADE_FLAG_VALUE 0x5A5A5A5A void jump_to_app(void) { uint32_t app_stack = *(volatile uint32_t*)APP_ADDR; if ((app_stack & 0x2FFE0000) == 0x20000000) { __set_MSP(app_stack); void (*app_entry)(void) = (void*)(*(volatile uint32_t*)(APP_ADDR + 4)); SCB->VTOR = APP_ADDR; app_entry(); } }

升级流程:上位机通过UART发送固件,每包256字节,带包序号和CRC16校验。Bootloader收到一包就写一包,写之前先擦除对应扇区。全部收完后计算整体CRC32,跟上位机发过来的比对,一致就置标志位并复位,不一致就报错重传。

这里有个关键细节:擦除Flash时CPU会暂停。STM32的Flash擦除是按扇区来的,一个扇区1KB或2KB,擦除时间大概20到40毫秒。这期间如果来了中断,中断向量表还在Flash里,CPU取不到指令就会HardFault。所以擦写Flash时要么关中断,要么把中断向量表搬到RAM里。我一般选择关中断,简单粗暴,反正升级过程中也不需要响应什么中断。

实操心得:IAP升级最怕断电。我早期做的版本没有备份区,升级到一半断电,Bootloader标志位已经置了但Application没写完,结果上电后Bootloader跳转到空的Application区,直接HardFault。后来改成双区备份,新固件先写到备份区,校验通过后再拷贝到运行区,拷贝前先擦运行区,拷贝完再清标志位。这样即使拷贝中断电,下次上电Bootloader发现标志位还在,会重新从备份区拷贝。

4. 烧录过程中那些让人抓狂的问题

4.1 常见问题速查表

现象可能原因排查方法解决方案
ISP连不上BOOT引脚电平不对万用表量BOOT0确保BOOT0=3.3V,BOOT1=GND
ISP连不上TX/RX接反交换TX/RX试试交叉接线
ICP连不上SWD引脚被复用看原理图确认用Connect under reset
ICP连不上芯片供电不足量VDD电压确保3.3V稳定,电流够
IAP跳转后跑飞向量表没偏移检查SCB->VTOR在Application里设置VTOR
IAP升级失败Flash擦除未完成看返回值擦除后等待BSY位清零
烧录后程序不跑复位电路问题量NRST引脚检查复位电容和上拉电阻

4.2 那些年我踩过的坑

第一个坑:Flash写保护。有些芯片出厂时默认开启了读保护或写保护,你烧录时会报“Flash protected”之类的错误。STM32的话需要用STM32CubeProgrammer解除保护,但注意解除读保护会全片擦除,数据全丢。我有个项目量产时忘了解除写保护,产线烧了500片全部失败,返工花了两天。

第二个坑:时钟配置错误导致烧录后不运行。ICP烧录时调试器用的是芯片内部RC时钟,跟你程序里配置的时钟没关系。但程序跑起来后如果时钟配置错了,比如外部晶振没起振但程序里等着HSE就绪,就会卡在时钟初始化里。现象就是烧录成功但程序不跑。解决办法是用示波器量晶振引脚,或者临时改成内部时钟测试。

第三个坑:IAP升级包大小超过分区。我见过一个项目,Application区规划了64KB,结果固件编译出来65KB,升级时写到一半发现越界了,把Bootloader区给覆盖了。芯片直接变砖,只能拆下来用编程器重新烧。所以规划分区时一定要留余量,至少留10%到20%的缓冲。

第四个坑:CRC校验算法不一致。上位机用CRC32,下位机用CRC16,或者多项式不一样,导致校验永远不过。这种问题最隐蔽,因为数据传输本身没问题,就是校验对不上。解决办法是两边用同一份代码,或者用标准算法比如CRC-32/ISO-HDLC,多项式0x04C11DB7,初始值0xFFFFFFFF,结果异或0xFFFFFFFF。

4.3 产线烧录的效率优化

如果你要做小批量生产,比如一次烧几十片,用ICP一个个烧太慢了。我一般会做一个烧录治具,把板子放上去,探针自动接触SWDIO、SWCLK、GND、VCC,然后用一个多路烧录器同时烧多片。市面上有那种一拖四、一拖八的烧录器,原理就是内部集成了多个J-Link或者DAPLink。

软件方面,J-Flash支持命令行模式,你可以写个批处理脚本,自动加载固件、烧录、校验、记录序列号。我之前的产线脚本大概长这样:

JFlash.exe -openprj"stm32f103.jflash" -open"firmware.hex" -connect -erasechip -program -verify -startapp -exit

配合一个扫码枪,扫一个序列号就烧一片,烧录记录自动存到数据库里。这样效率比手动点鼠标高多了,而且不会漏烧或重复烧。

对于超大批量,比如几万片,那就直接找芯片原厂或者烧录厂做OTP烧录,他们在芯片封装阶段就把固件写进去了,你拿到手就是成品。不过OTP只能烧一次,改不了,适合固件已经冻结的量产项目。

5. ISP Pipeline与图像处理中的ISP是两码事

搜“ISP”的时候你会发现大量关于“ISP Pipeline”和“ISP图像处理”的内容,这跟芯片烧录里的ISP完全是两个东西。图像处理里的ISP是Image Signal Processor,图像信号处理器,负责把传感器输出的RAW数据转换成RGB图像。它内部有去马赛克、白平衡、伽马校正、降噪等一堆算法模块,这些模块串起来就是ISP Pipeline。

为什么会有这个混淆?因为缩写一样。芯片烧录的ISP是In-System Programming,图像处理的ISP是Image Signal Processor。你在搜索资料时如果看到“ISP去弹窗”、“ISP调试”之类的词,那说的是图像处理,跟烧录没关系。我刚开始做嵌入式时也被绕进去过,后来才分清楚。

如果你正好在做摄像头项目,需要调试ISP Pipeline,那跟烧录唯一的交集是:你可能需要把ISP的配置文件(比如IQ文件)烧录到芯片外挂的Flash里。这时候用的还是ICP或ISP方式,只是烧的内容不是固件而是参数文件。本质上没区别,都是往Flash里写数据。

提示:STC ISP去弹窗这个热搜词,说的是STC单片机用ISP方式烧录时,上位机软件会弹广告窗口,有人做了去弹窗的版本。这跟技术本身无关,纯粹是工具软件的问题。如果你用STC芯片,建议找官方最新版工具,或者用命令行模式避免弹窗干扰。

6. 选型建议:什么时候用哪种方式

如果你在研发阶段,手头有调试器,那ICP是最优解。速度快、通用性强、不挑芯片,J-Link一插,什么STM32、GD32、NXP都能烧。而且ICP支持在线调试,打断点、看变量、单步执行,这些是ISP和IAP做不到的。

如果你在产线量产,产量不大且芯片支持ISP,那ISP更划算。一个USB转串口模块才十几块钱,比J-Link便宜多了。而且ISP不占用调试引脚,产线工人操作也简单,跳线帽一插一拔的事。但前提是芯片的ISP协议要稳定,有些国产芯片的ISP工具做得稀烂,经常连不上,那还是老老实实用ICP。

如果你的产品已经出货,需要现场升级,那IAP是唯一选择。但IAP的开发成本最高,你得写Bootloader、设计通信协议、处理异常回滚。我建议IAP的Bootloader尽量做简单,只负责收数据和写Flash,复杂的逻辑放到Application里。Bootloader越简单越不容易出bug,而且一旦Bootloader出问题,整个设备就变砖了,只能返厂。

还有一个混合方案:ICP烧Bootloader + IAP升级Application。产线用ICP把Bootloader烧进去,Bootloader里包含IAP功能。产品出厂后通过IAP升级Application。这样产线效率高,现场升级也方便。我大部分项目都是这个套路,实测很稳。

最后说一个容易被忽略的点:烧录文件的格式。hex文件带地址信息,bin文件是纯二进制。ICP和ISP工具一般两种都支持,但IAP通常用bin,因为Bootloader需要知道每个字节写到哪个地址,hex解析起来麻烦。编译时记得勾选生成bin文件,Keil里在User选项卡的After Build里加一行fromelf --bin -o "$L@L.bin" "#L"就行。

返回列表