前几天夜里有个做毕设的学弟给我打电话,说他手里的STM32F103C8T6“废了”。现象很典型:Keil里点下载,JLink弹出一行红字Could not connect to target,试了几次都一样,板子上的LED也彻底不闪了。他自己在网上查了一圈,结论是芯片被锁死,准备扔了换新的。我让他先别急着丢,把JLink的SWD四根线重新核对一遍,然后在命令行里敲了几条命令,十分钟不到,程序正常烧录进去,板子又活了。
其实所谓“STM32被锁死”,绝大多数情况并不是硬件损坏,而是Flash读写保护状态被触发。只要搞清楚保护机制、JLink的正确解锁姿势,以及BOOT0/BOOT1启动模式这几个关键词,救回来基本没有难度。这篇文章就把完整的流程和原理都摊开讲,包括JLink驱动、SWD接口定义、Flash读写保护分级、启动模式切换,以及各种解锁失败后的排查链路。不管你是做毕业设计的新手,还是量产调试时遇到“变砖”芯片的工程师,照着做基本都能解决。
1. “锁死”的真相:先分清Flash读保护和写保护
1.1 RDP分级:Level 0、Level 1、Level 2的区别
很多人一听“Flash读写保护”就默认芯片完蛋了,其实这是误解。STM32的读保护(RDP,Read Protection)并不是一个开关那么简单,它分了三个等级,不同等级的严重程度天差地别:
- Level 0:出厂默认状态,调试接口完全开放,可以用JLink、ST-Link随便读写和擦除Flash。绝大多数开发板拿回来就是这种状态。
- Level 1:最常见的“锁死”状态。此时通过调试接口访问主Flash会被拒绝,不能读、不能擦除、不能下载。但注意,芯片自身已经烧录固件的话,固件仍然可以正常运行,外部引脚和功能不受影响。这个等级是可逆的,解除保护后Flash会被全片擦除,但芯片本身没有任何损伤。
- Level 2:永久保护,一旦设置就再也无法通过任何调试接口、ISP接口访问Flash,也无法降级回Level 0。等于芯片从物理层面变成一次性产品,程序只能写一次,之后永远不能读也不能改。这个状态基本等于给芯片判了死刑。
打个比方:把芯片比作一台手机。Level 0是出厂状态随便玩;Level 1就像忘记锁屏密码,虽然进不去系统,但还能通过恢复模式刷机清数据,手机本身没坏;Level 2则是把存储芯片直接焊死,恢复模式也进不去,只能换主板。
RDP保护的是“读”,而写保护(WRP,Write Protection)是另一个维度:它针对指定扇区,让这些区域变成只读,防止程序被意外篡改。WRP开启后,芯片通常能正常连接调试器,但擦除或写入时会在特定扇区报错,表现和RDP完全不同。所以排查问题前,先搞清楚芯片到底是哪种保护状态,方向不对后面全白折腾。
1.2 好端端的芯片为什么会开保护
我见过不少新手一脸茫然:我也没设置过什么保护啊,怎么突然就锁死了?实际上RDP被触发的原因比想象中多,而且很多都是无意识操作:
- 程序里写了操作Option Byte的代码。最常见的是OTA Bootloader。很多Bootloader在跳转到App之前会主动开启RDP,防止别人把固件读走。但当你在调试阶段反复刷写时,一旦RDP被置上,JLink立刻失联。
- 用STM32CubeProgrammer或J-Flash手动设置了读保护。有些量产工具在烧录时会顺手勾选“Enable Read Protection”,目的是保护固件不被抄板。这个设置跟着Option Byte写进芯片,下次你想调试就傻眼了。
- 买到了二手或翻新芯片。有些芯片是拆机料,上一任使用者在产品固件里开了RDP,你没做任何操作,芯片到手就是锁定状态。
- Keil的Flash Download选项误操作。虽然正常用Keil下载不会主动开RDP,但如果你在量产模式下点了“Erase Full Chip”以外的特殊选项,又配合了第三方的烧录工具,可能不知不觉把Option区域也写了一遍。
1.3 判断芯片保护状态的两个信号
怎么确认芯片确实是RDP锁死,而不是接线问题或者芯片真坏了?看两个信号:
第一,JLink Commander能识别到芯片内核,但访问Flash被拒绝。比如连接时能显示Found Cortex-M3,但后面跟一行Can not read register,或者直接提示Device is secured。
第二,STM32CubeProgrammer连接时报“Read protection is enabled”。这个提示非常直白,看到基本就能确诊。
还有一种情况:JLink完全连不上,报错Cortex-M3 not found或Cannot connect to target。这种不能直接断定是RDP,因为接线错误、供电异常、芯片进入低功耗模式都可能造成同样现象。第二章先把硬件因素排查干净,再执行解锁操作,顺序不要搞反。
2. 动手前必须确认的:JLink接线、驱动与目标板状态
2.1 SWD四根线怎么接才不会出问题
JLink和STM32之间最常用的连接方式是SWD,只需要四根线:SWDIO、SWCLK、GND、VTref。很多开发板还引出了3.3V电源脚,如果目标板本身没有独立供电,也可以用JLink的供电脚,但注意JLink的供电能力有限,带个最小系统还行,带电机、屏幕就直接外接电源。
如果你用的是20针JTAG接口,对应的关键引脚是:VTref在第1脚,SWDIO在第7脚,SWCLK在第9脚,GND是第4、6、8、10、12、14、16、18、20这些地脚任选其一,RST复位引脚在第15脚。小板上最常见的接法就是直接找标着SWDIO、SWCLK、GND、3V3的排针,一一对应接上。
这里有个特别容易被忽略的点:VTref必须接对。JLink是靠VTref引脚检测目标板电压的,它读到的电压为0,就会认为目标板没上电,直接拒绝工作。我遇到好几个“JLink识别不到单片机”的案例,最后发现都是VTref悬空,或者接到了一个和地短路的焊盘上。另外,SWDIO和SWCLK接反也是新手高发错误,这两根线不能调换,调换后信号完全错位,连接必然失败。
2.2 驱动装完还是识别不到?先看这三处
JLink驱动的安装本身不复杂,但有些细节会让人卡很久。装完驱动后,先把JLink插到电脑,打开设备管理器,展开“通用串行总线控制器”或“端口”,应该能看到一个J-Link设备。如果设备前面有黄色感叹号,说明驱动没装上,或者被系统拦截了。
最容易踩的三个坑:
第一,Windows 11或Windows 10 64位系统下,驱动签名导致安装失败。解决办法是开机时进入高级启动,选择“禁用驱动程序强制签名”,然后重新安装驱动。网上说的“兼容模式安装”也可以试试,但效果不如禁用签名来得彻底。
第二,杀毒软件拦截驱动加载。JLink驱动涉及底层USB驱动文件的释放,有些安全软件会视为风险操作直接隔离。安装驱动时暂时关掉实时防护,装完再开。
第三,兼容版JLink固件和驱动版本不匹配。市面上有些非官方JLink,插上后驱动界面会弹“The connected probe is a J-Link clone”之类的警告。这种情况轻则无法解锁操作,重则JLink直接蓝屏。我的建议是:如果你手头只有这种设备,做解锁时不要抱太大希望,能用就用,不能就别勉强,直接换ST-Link反而省心。
2.3 连接前的关键预检
接线和驱动都确认没问题后,先做一步预检:打开JLink Commander(安装驱动后会自动装好),输入connect,选择设备型号和接口,如果能正常显示目标芯片ID、内核类型,说明物理链路已经通了。如果在这里就失败,后面所有解锁操作都不用谈。
预检时还要注意:
- 目标板必须已经上电,并且电源指示灯亮着。
- 如果SWD线超过20厘米,直接把通信速率降到100kHz,高速率下的线间串扰很容易导致连接失败。
- 如果程序里把SWD引脚复用成了普通GPIO,也会导致调试器连不上。这时候需要把BOOT0拉高后复位,让芯片从系统存储器启动,再尝试连接。
- 复位引脚上如果有大电容,会造成上电后长时间处于复位状态,JLink也连不上。可以先把复位电容断开,或者连接瞬间手动送一个复位脉冲。
预检通过后,才真正进入解锁环节。
3. 核心操作:用JLink Commander把RDP从Level 1降回Level 0
3.1 交互式命令逐条执行
JLink Commander是SEGGER官方提供的命令行工具,安装目录下能找到JLink.exe。解锁的核心命令是unlock,针对不同型号的STM32,命令格式是unlock后面加设备名。
完整交互流程如下:
- 打开命令提示符,进入JLink安装目录,输入
JLink.exe回车。 - 看到提示符后输入
connect回车。 - 系统会让你指定设备型号,比如
STM32F103C8,直接输入型号回车。不同的芯片要用对应的名称,比如F407就输STM32F407VG,如果不知道具体型号,输一个系列名如STM32F1xxx也行,但不建议,容易选错Flash算法。 - 选择目标接口,输入
S代表SWD,或者直接回车选默认。 - 设置通信速率,输入
4000表示4000kHz。如果芯片处于保护状态导致连接不稳定,直接输入100用最慢速度连。 - 连接成功后,命令行会进入
J-Link>提示符,此时执行:
unlock STM32F103C8这里要敲的设备名必须和前面连接时用的完全一致。执行后JLink会提示解锁序列完成。
- 解锁完成后立即执行全片擦除:
erase- 然后复位并运行:
r go- 最后输入
exit退出。
这一步很多教程没强调,但我强调一下:解锁完成后必须断电重启。Option Byte的修改不会立刻生效,硬件需要重新加载选项字节才能真正从Level 1回到Level 0。有人执行完unlock就直接回Keil下载,结果还是报错,然后得出“解锁没用”的错误结论。正确的做法是:JLink退出后,把目标板完全断电,等两秒再重新上电,然后再用Keil下载。
3.2 写脚本一键解锁
如果手头有多块板子要解锁,或者以后还可能要批量操作,建议把命令写进脚本文件,一条命令直接跑完。
新建一个unlock.jlink文件,内容如下:
unlock STM32F103C8 erase r go exit然后在命令行执行:
JLink.exe -device STM32F103C8 -if SWD -speed 4000 -autoconnect 1 -CommanderScript unlock.jlink参数说明:
-device:指定目标芯片型号。-if:接口类型,写SWD。-speed:通信速率,单位kHz。-autoconnect 1:自动连接,省去手动确认步骤。-CommanderScript:指定要执行的脚本文件。
执行后看到Unexpected end of file就说明脚本跑完了,然后断电重启,正常下载。脚本文件尽量不要放在带空格的路径下,比如C:\Users\你的名字\Desktop这种路径可能因为空格解析出问题,放在纯英文目录比如D:\jlink最稳。
3.3 unlock之后为什么还要erase
这里解释一下解锁的原理,不然你只记住命令,换一个芯片型号还是会蒙。
STM32内部有一块独立的Option Byte区域,RDP的状态就存在这个区域里。当你执行unlock时,JLink做的事情是:往Flash控制器的Key Register写入解锁密钥,然后修改Option Byte中的RDP字段,把它从Level 1改回Level 0。但STM32硬件有个约束:要从高等级保护降级到低等级,必须先把主Flash完整擦除,防止保护被绕过时留下敏感数据。所以解锁过程本身就隐含了全片擦除,之后的erase命令只是再保险一遍,确保所有扇区都处于可写状态。
这也是为什么常说“解锁等于清空”。如果你板子里有不想丢失的出厂固件,在解锁前要有个心理准备,固件救不回来,只能重新烧录。
另外,强烈建议不要通过JLink手动修改Option Byte直接把RDP写成Level 2。有些JLink脚本或者第三方工具提供了直接写Option Byte的功能,写错一个值芯片就永久变砖。Level 2一写入,ST-Link、JLink、串口ISP全部失效,没有任何恢复手段,只能换芯片。解锁操作的底线就是只降级,不开新保护。
4. BOOT0/BOOT1不只是跳线帽:三种启动模式的正确理解
4.1 三种启动模式分别对应什么场景
标题里提到“启动模式切换详解”,这里展开聊透。STM32的BOOT0和BOOT1引脚共同决定芯片复位后从哪里取指执行,典型的配置表如下:
| BOOT0 | BOOT1(F1系列为PB2) | 启动位置 | 典型场景 |
|---|---|---|---|
| 0 | 任意 | 主Flash | 正常运行用户程序 |
| 1 | 0 | 系统存储器 | 进入出厂ISP Bootloader,串口/USB/DFU刷机 |
| 1 | 1 | SRAM | 调试RAM中的程序,实际项目很少用 |
F1系列里BOOT1引脚其实就是PB2,很多开发板没有单独引出BOOT1,因为正常使用根本不需要它——只要BOOT0接地,芯片就从主Flash启动,BOOT1是什么状态无所谓。这就是为什么很多人从头到尾没碰过BOOT1,板子也能正常工作。
4.2 什么时候才需要动启动模式
这里有一个关键认知要建立:用JLink解锁Flash读写保护,不需要切换启动模式。SWD调试接口和CPU的运行状态是独立的,它通过调试端口发指令给芯片内部,不需要芯片先“跑起来”。所以芯片锁死后,JLink仍然能发起解锁流程。
那启动模式切换的意义在哪?在两条场景下非常有用:
第一,SWD物理链路本身被破坏或连不上,手头又没有JLink。比如工程把PA13/PA14复用成了普通GPIO口,而这两个脚正是SWDIO和SWCLK,芯片启动后就无法响应调试器。如果不切换启动模式,JLink永远连不上。但你把BOOT0拉高后复位,芯片从系统存储器启动,SWD引脚复位后恢复默认功能,这时候JLink可能就能连上了。
第二,需要走串口ISP刷机的场景。系统存储器里固化的出厂Bootloader支持通过USART1直接烧录程序,不需要JLink、ST-Link任何调试器,只需要一个USB转TTL模块。这在“什么都没有,只有一根串口线”的情况下是最后的抢救手段。
4.3 从系统存储器启动实战:串口ISP救砖
操作流程其实非常简单:
- 给板子断电。
- 把BOOT0跳线帽接到3.3V(逻辑1),BOOT1接GND(逻辑0)。有些开发板是拨码开关,那就把BOOT0拨到ON,BOOT1拨到OFF。
- 重新上电。芯片复位后进入系统存储器Bootloader。
- 用USB转TTL模块连接串口:模块的TX接芯片的RX(F1通常用USART1,引脚是PA9和PA10,PA9是TX,PA10是RX),模块的RX接芯片的TX,GND接GND。注意不要接反。
- 打开STM32CubeProgrammer,选择UART模式,选对COM口号,波特率可以先用115200,如果连不上就降到9600。
- 点击Connect,如果能看到芯片型号和Flash大小,说明已经进入ISP模式。
- 这时候有两种选择:如果只是想刷程序,直接在“Erase & Programming”里选择固件文件下载;如果目标是解除RDP保护,切到“Option Bytes”页面,把Read Protection从Level 1改成Level 0,点Apply。
- 操作完成后断电,BOOT0恢复接GND,重新上电,芯片就恢复正常状态。
注意,通过ISP同样受到RDP Level 1的限制:它允许你把Level 1改回Level 0,但代价依然是把Flash全片擦除。如果上一手设置了Level 2,ISP也救不了,这在前面说过了。
有一个容易被忽略的坑:电脑识别不到USB转TTL模块的COM口。原因是CH340这类芯片的驱动没有安装,或者被系统识别成了未知设备。这时候先去设备管理器看看有没有带感叹号的设备,装上对应驱动,再回来操作。很多“启动模式切换后依然无法刷机”的报错,最后发现是USB转TTL模块根本没被电脑认出来。
5. 解锁失败的排查链路:从接线到Option字节逐项核对
5.1 症状一:目标电压读数为0
JLink连接时如果显示Target voltage: 0.0V,说明JLink通过VTref引脚检测不到目标板电压。按这个顺序排查:
- 目标板有没有真的上电?电源开关开了吗?万用表量一下3.3V引脚有没有电压。
- VTref那一根线接对了吗?很多20针转4线的转接板,VTref端子是空的,需要单独接一根线到目标板3.3V。
- 目标板电源部分是不是短路了?有些开发板在USB口和3.3V之间有一个自恢复保险丝,电流异常时保险丝断开,板子看起来没坏但就是没电。
- 如果以上都正常,换一根杜邦线再试。杜邦线内部断裂也是常事,尤其插拔次数多了以后。
5.2 症状二:能连上但下载报错
JLink能识别芯片,但Keil下载时报Flash Download failed - Cortex-M3/M4,这种一般不是RDP锁死,而是三个原因:
- Flash算法选错。Keil的Options for Target → Utilities → Settings里,Flash Download页面列出了烧录算法。F103C8应该用STM32F10x Med-density,F103ZET6用High-density,F407用STM32F4xx系列对应容量。选错算法时下载到一半会报地址越界或校验失败。
- WRP扇区写保护。如果只是特定地址段擦写失败,而其他扇区正常,大概率是WRP保护了这个区域。这种要触发解除写保护需要先全片擦除,再用JLink的unsecure或STM32CubeProgrammer的Remove Write Protection处理。
- 芯片是翻新片或非原厂片。有些便宜芯片内部Flash型号不标准,标准算法写不进去,尝试用低速模式或者换一颗原厂片看看。
5.3 症状三:提示J-Link clone或固件过老
老版本JLink插上新出的STM32型号,固件里没有对应芯片的ID绑定信息,会直接报错或者无法识别。常见提示包括The connected probe is a J-Link clone、Firmware of connected J-Link is too old。
这种兼容版JLink的问题不太好完美解决——刷新固件属于占用官方资源的灰色操作,正规渠道也不建议这么做。我的建议是:如果手头有ST-Link,直接换ST-Link配合STM32CubeProgrammer做解锁,效果一样且不需要折腾固件。如果没有ST-Link,至少确认手头JLink能识别相同系列的其他芯片,如果能识别,说明有解;如果连老芯片也报克隆警告,那基本可以放弃这个硬件了。
5.4 症状四:芯片处于低功耗状态导致连接失败
如果程序里进了STOP或者STANDBY模式,调试接口会被关闭,JLink无法连接。这种场景经常出现在低功耗产品开发中:你刚下载了一个进休眠的程序,下一秒JLink就失联了。
解决方法:
- 按住目标板上的复位键不放。
- 在JLink Commander里执行连接命令。
- 当连接过程开始的一瞬间松开复位键,让芯片从复位向量开始执行,还没进入休眠前抢到调试权限。
- 连接成功后,先把Option Byte里的RDP确认一下(防止休眠和RDP问题混淆),再重新烧录一个不进休眠的程序覆盖掉。
如果按这个方法试了三次还没成功,可以考虑把复位引脚直接接到GND,让芯片一直处于复位状态,此时CPU不运行程序,调试接口理论上更容易连接。注意这种方法只对连不上但又怀疑是代码问题的情况有效,对RDP Level 1没有作用。
5.5 避免RDP误开的三个实操习惯
解锁的终极技巧是尽量不要触发锁死。防患于未然比事后解锁高效得多,我自己的项目里固定遵守几个习惯:
- 不把RDP设置写进正式固件。Bootloader需要开RDP保护固件是量产阶段的需求,开发调试阶段用宏开关把它关掉,或者用条件编译控制,等真正量产再打开。
- 统一用脚本做批量解锁。手头有几十块待升级板卡时,每块都手动输命令容易出错,写一个JLink脚本循环处理,速度快而且不会误操作。脚本里明确只执行unlock和erase,绝不放写Option Byte的指令。
- 保留一个带BOOT跳线的救砖接口。产品PCB设计时,至少预留BOOT0、BOOT1、SWD、UART这几个测试点。很多工程师为了省事只留SWD四线,后来RDP锁死了只能飞线,反而更麻烦。
复盘一下整个流程:遇到STM32下载失败,先冷静判断是RDP还是WRP,再检查JLink硬件链路的四个要素(供电、SWD接线、驱动、连接速度),确认芯片处于Level 1后,用JLink Commander执行unlock和erase并断电重启,或者切入系统存储器启动模式用ISP刷机。整个过程里最容易翻车的不是解锁命令本身,而是忽略断电重启、VTref没接、SWD接反这几个细节。希望这篇能帮你把“芯片被锁死”从事故清单里划掉。