1. 先说结论:这不是单一原因,而是一整条故障链
STM32WB55出现“cannot be read, erased, programmed”这类报错,十有八九不是芯片物理损坏,而是调试接口状态、Option Bytes配置或双核唤醒机制出了问题。我前前后后经手过十几块WB55的开发板和自绘板,每次遇到这种问题,第一反应都不是怀疑芯片“假砖”,而是先走一套固定的排查流程:接线、供电、复位、连接方式、读保护等级、双核调试会话,最后才是芯片本身。
这篇文章会把完整排查思路写出来。适合两类人看:一类是用STM32WB55做低功耗蓝牙或Zigbee产品开发,烧录时突然连不上芯片的工程师;另一类是刚拿到官方评估板,第一次接ST-Link就报错的入门玩家。无论你是用STM32CubeProgrammer还是Keil/IAR,底层逻辑都一样,只是报错文本略有差异。
先给你一个定心丸:STM32WB55这颗芯片的设计相当皮实,真正因为内部Flash物理损坏导致无法编程的情况极少。绝大多数“cannot read/erase/program”都集中在连接状态、保护位、低功耗模式或双核仲裁这几个环节。下面我按实际排查顺序展开,你能直接照着操作。
2. 排查步骤一:硬件连接与供电,别急着怪芯片
2.1 复位电容、调试引脚、供电波纹
我先说一个最容易忽略的坑:STM32WB55沿用SWD调试接口,但它的NRST引脚对复位电路比较敏感。很多自绘板为了省事,直接在NRST上接一个0.1uF电容,这本身没问题,问题出在电容取值过大,或者ST-Link和目标板之间还存在另一套复位电路。一旦复位脉冲被拉低时间过长,连接阶段就反复失败,报错表现就是“cannot read”或“connection error”。
另一个高频故障点是供电。WB55内置射频前端,瞬态电流比普通MCU大,启动瞬间如果电源纹波偏大,内部LDO无法稳定建立,内核可能处于一种“半睡半醒”的状态。这种情况下,调试口尽管能检测到设备,但读取IDCODE失败,或者读出来一个全是0xFF/0x00的ID,ST-Link直接放弃连接。我遇到过一次,板子用AMS1117从5V转3.3V,输出端只放了10uF电容,结果在射频发射瞬间电压跌落超过200mV,每次连接成功率不到一半。
排查时我一般这样操作:先用USB供电或外部稳压电源给目标板独立供电,ST-Link和板子之间只连SWDIO、SWCLK、GND,不连3.3V,排除调试器供电能力不足的干扰。然后示波器看NRST复位释放后的上升沿,正常应该是干净的单次上升沿,如果看到多次毛刺或缓慢爬升,先处理复位电路。
2.2 换线、换ST-Link、手动复位
连接线是另一个容易被忽略的变量。SWD虽然只有四根线,但工作在几MHz速率下,杜邦线过长或者接触不良会导致时钟边沿变形。我踩过最狠的一次:用了30厘米的杜邦线连接,CubeProgrammer能识别到芯片但一执行read就报“Error: cannot read memory”,换成10厘米以内的杜邦线后问题消失。SWDIO和SWCLK最好等长,且不要和射频天线部分靠太近,否则蓝牙发射时调试口直接断连。
如果你用的是山寨ST-Link,还要留意固件版本。老版本ST-Link固件对WB55双核调试支持不完善,读ID时能通过,进入调试模式后却无法控制CPU。建议先升级到ST-Link On-Board固件最新版,或者在STM32CubeProgrammer里刷新固件。实在不行,换一个官方STLINK-V3SET或J-Link,很多奇葩问题直接消失。
还有一个“土办法”很有效:在CubeProgrammer里把连接速度从默认的4MHz降到1MHz或更低。WB55的SWD引脚与射频相关功能存在复用,某些情况下高速连接不稳定,降速虽然慢一点,但能显著提高连接成功率。我现在的习惯是:评估板用4MHz,自绘板和长线场景一律降到1.8MHz或1MHz。
3. 排查步骤二:调试接口被“锁死”的几种可能
3.1 RDP读保护等级
如果硬件连接没问题,供电也稳定,但STM32CubeProgrammer仍然提示无法读取Flash或执行擦除,那就要考虑RDP读保护等级。STM32WB55的Option Bytes里有一个RDP位,分为三个等级:
- Level 0:无保护,全功能开放,正常读写擦除。
- Level 1:禁止通过调试接口读取Flash内容,但仍允许擦除和重新编程,前提是连接时CPU处于复位状态或调试端口已释放。
- Level 2:最高保护,调试接口永久锁定,芯片上几乎无法通过SWD恢复,只能通过系统Bootloader或特定手段处理,且某些情况下是不可逆的。
很多量产板出厂时会被设置成Level 1,防止固件被读取。如果你拿到的是别人的板子、二手核心板或测试遗留板,连接后看到“Read protection is enabled”或者“Error: Cannot read memory”就非常正常。这种情况下并不是芯片坏了,而是需要先做一次“全片擦除”或“解除读保护”。
这里有个关键点:从Level 1回到Level 0,常规操作是勾选CubeProgrammer里的“Remove read protection”选项,执行后芯片会自动执行一次全片擦除。这意味着板上固件会消失,同时也解释了一个现象——为什么很多人“刚连上就报错,想读Firmware却全读成0xFF”。不是你操作有问题,而是保护机制不允许你在不擦除的前提下读取任何数据。
3.2 TrustZone与Option Bytes
STM32WB55在较新的固件包里启用了TrustZone安全扩展后,调试连接机制会有明显变化。如果你启用了TrustZone,那么芯片会被划分成安全区和非安全区,调试端口需要先获取安全区访问权限,否则只能看到非安全区的部分内容,甚至连IDCODE读取都受限。
这种情况下的报错往往是“Cannot access target”或“RDP level not supported”。我早期调试一个带TrustZone的示例工程时,反复出现“cannot read”的问题,后来发现是因为TZEN位被置1,而CubeProgrammer的默认连接配置没有勾选“Enable TrustZone”相关的访问模式。
遇到这类问题,可以先连接后查看Option Bytes页面,确认TZEN、RDP、BOR等关键位。如果TZEN处于使能状态而你暂时不用TrustZone,可以尝试把TZEN清0。但要注意,TZEN位只能在特定条件下修改,部分芯片还需要先执行整片擦除才能改变。若你的产品确实要用TrustZone,那就要用支持TrustZone的调试工具和连接参数,不是拉一根SWD线就能解决的。
3.3 双核架构的影响
STM32WB55不是单核MCU,它内部有Cortex-M4应用核和Cortex-M0+网络协处理核。M0+核负责蓝牙协议栈/Zigbee协议栈,M4核负责用户应用。问题在于:两个核共享内部Flash和部分外设,调试端口也由统一调试子系统管理。
如果你之前用M0+核做过调试或者跑过协议栈固件,而M0+核当前处于低功耗睡眠或锁定状态,M4核的调试会话可能无法正常访问Flash。典型现象是:CubeProgrammer识别到设备,但一执行读取或擦除,命令就卡住或立即报错。
解决办法是使用STM32CubeProgrammer的“Dual Core”调试模式,或者连接时选择“System Bootloader”而不是“Hot Plug”。使用System Bootloader模式时,芯片会重启并进入内嵌Bootloader,此时两个核都被复位,调试端口不再受当前运行固件干扰,执行全片擦除和重新编程的成功率会高很多。这也是救砖时最推荐的连接方式。
4. 实战操作:怎么救回一个“假砖”的WB55
4.1 用STM32CubeProgrammer强制连接
先说明:我以下步骤均以STM32CubeProgrammer 1.15及以上版本为例。新版本对WB55支持更好,尤其是对双核和TrustZone的处理更成熟。如果你还在用老版本,建议先升级,不然很多选项根本看不到。
打开软件后,右上角选择ST-LINK,接口选SWD,频率降到低档,然后不要直接点Connect。在“Mode”里选择“Under reset”或“Hot Plug”。“Under reset”要求在芯片复位期间建立连接,适合当前固件把调试口配置成普通IO、或程序跑飞导致调试口失效的场景。标准救砖流程我先建议“Under reset”,如果失败再切“Hot Plug”。
点击Connect后,观察日志区域。如果提示“Device ID = 0x495”之类的ID,说明连接成功。此时不要急着点Read,先进入Option Bytes页面看一眼RDP等级。如果是Level 1,直接下拉选择Level 0,点击Apply。软件会弹窗提醒将执行全片擦除,确认后等待完成。
注意:解除读保护的过程需要断开已有调试会话重新连接,芯片会先擦除全部Flash,再恢复RDP为Level 0。这个过程不能断电,否则Option Bytes可能写入不完整,导致进入更麻烦的状态。
4.2 解除读保护的正确姿势
解除读保护在CubeProgrammer里非常直观,但我遇到过几个细节问题:
第一,如果你连接时选了“Hot Plug”,而芯片CPU正运行着低功耗代码,解除读保护的操作可能失败。因为写Option Bytes需要CPU配合,CPU睡死的话操作无法完成。这时一定要用“Under reset”模式重连。
第二,如果芯片的RDP已经是Level 2,CubeProgrammer会直接拒绝所有调试操作,此时普通SWD是不可解的。唯一常规恢复路径是使用芯片内嵌的Bootloader,通过USART或USB接口执行System Bootloader擦除。STM32WB55的Bootloader默认支持USART1和USB,需要把BOOT0引脚拉高再复位,然后用CubeProgrammer选择UART或USB接口连接,执行擦除。
第三,解除保护后,芯片的Option Bytes里其他配置也会被重置,比如看门狗选择、BOR级别、Flash双Bank模式。回读一遍Option Bytes,确认和你预期一致。我见过有同事解保护后忘记重新配置BOR,导致低温环境下芯片复位异常,排查了很久。
4.3 擦除全片与恢复默认Option Bytes
连接成功后,点击“Full chip erase”按钮,会执行整片擦除。这对WB55来说很安全,它会同时擦除M4核和M0+核的Flash区,包括用户选项区之外的主存储区。擦除期间如果看到报错“Cannot erase memory”,大概率是RDP保护等级还没降下来。
擦除完成后再做一次全片Verify。如果地址0x08000000处全部为0xFF,说明擦除干净了。此时先不急着下载程序,建议先执行“Option Bytes”页面里的“Restore Default”或手动把RDP设为Level 0,TZEN设为0,BOR等级设为合适值。这样做的目的是把芯片恢复成出厂状态,排除遗留配置干扰后续开发。
恢复默认Option Bytes后,断电重新上电,再次用SWD连接,此时应该能顺畅读取到空片状态。此时烧录一个最简单的LED闪烁工程验证MCU是否完全恢复。如果一切正常,说明芯片没问题,之前只是保护位和调试配置在作祟。
4.4 编写脚本化处理
如果你手头有多块板子需要恢复,每次都点GUI未免太慢。STM32CubeProgrammer提供了命令行工具STM32_Programmer_CLI,可以写脚本来批量处理。以下是我在实际生产测试中常用的命令:
STM32_Programmer_CLI -c port=SWD mode=UR reset=HWrst -ob RDP=0 STM32_Programmer_CLI -c port=SWD mode=UR reset=HWrst -e all -v STM32_Programmer_CLI -c port=SWD mode=UR reset=HWrst -w firmware.hex -v第一条命令用于解除读保护,第二条执行全片擦除和校验,第三条烧录固件并校验。如果你需要取消TrustZone,可以追加参数:
STM32_Programmer_CLI -c port=SWD mode=UR reset=HWrst -ob TZEN=0使用脚本化处理时有一点要提醒:如果你的连接线质量一般,擦除和烧录过程中意外中断,芯片可能留在半擦除状态。脚本层面最好加一个失败重试机制,比如总次数小于3次,每次失败后重新连接。量产阶段我更推荐用独立的烧录夹具和短距离连接线,保证稳定。
5. 常见错误与提示速查表
5.1 “Cannot read”等错误含义
我整理了一份速查表,覆盖我实际见过的错误文本和对应处理方向。注意,STM32CubeProgrammer和第三方IDE的报错措辞可能不同,但本质问题基本可以对应:
| 报错关键词 | 可能原因 | 优先处理 |
|---|---|---|
| Cannot read memory | RDP保护、连接不稳定、CPU低功耗 | 检查RDP等级,切换Under reset,降低SWD速率 |
| Cannot erase memory | RDP Level 1/Level 2、Flash写保护 | 先解除读保护,再全片擦除 |
| Cannot connect / Connection error | 接线错误、供电异常、ST-Link固件旧 | 换线、验证供电、升级ST-Link固件 |
| Device ID mismatch / 0x000000 | SWD信号问题、目标板未上电、复位电路异常 | 检查NRST、SWDIO/SWCLK,手动拉低复位再连 |
| RDP Level 2 | 芯片最高级保护 | 仅能通过Bootloader或更换芯片 |
| Cannot access target | TrustZone使能、调试端口被禁用 | 查看TZEN位,尝试System Bootloader模式 |
| Error: connection error 0xE2E0 | ST-Link非法命令或目标未响应 | 降低频率,用UR模式重试 |
这张表并不是官方文档的精确定义,而是我根据实际排障经验做的映射。拿“Cannot read memory”来说,可能有五六种细微原因,但表格里的优先级是我验证过概率最高的顺序。我在处理问题时,习惯先排除硬件连接,再排除保护位,最后才怀疑芯片。因为怀疑芯片是成本最高也最不容易改变主意的方向,往往浪费一两天后才发现只是Option Bytes没配置对。
5.2 排查优先级
如果你现在手头正好有一块连不上的WB55,建议按这个顺序操作,每一步都记录下现象,避免重复操作:
- 确认板子供电正常,测量3.3V稳定,且在复位和射频发射时没有明显跌落。
- 检查SWDIO、SWCLK、GND是否连接可靠,是否使用过长导线。
- 用STM32CubeProgrammer,选择SWD、频率1MHz、Under reset模式,尝试连接。
- 如果连接成功,先查看Option Bytes里的RDP、TZEN、BOR、Flash保护位。
- 如果RDP为Level 1,执行Remove protection,允许全片擦除。
- 如果连接失败,尝试System Bootloader模式,通过BOOT0引脚进入Bootloader,再用UART/USB连接。
- 擦除全片,恢复默认配置,重新验证。
- 如果以上全部失败,再考虑硬件层面的问题,比如OXIDE损坏、晶振异常、焊盘短路。
这套顺序我写进了团队的新人培训文档里,目的就是防止新手一上来就“大力出奇迹”,直接在GUI里乱点导致Option Bytes越弄越糟。有条理地记录每一步结果,比盲目尝试几十种连法要快得多。
6. 我的几点实操心得
6.1 关于下载调试
STM32WB55的调试体验比STM32F1系列要“矫情”不少。F1时代我随便拿四根杜邦线就能连,WB55则对布线、复位和供电环境更敏感。尤其是自绘PCB,建议SWDIO和SWCLK上各加一个33欧姆串联电阻,靠近MCU放置,能有效抑制振铃。如果产品空间允许,再留一个测试点接到NRST,救砖时会非常省事。
另外,WB55的M0+核和M4核共享Flash,但并非所有调试器都能同时良好支持。IAR较新版本对双核调试支持不错,但如果你只是烧录用户应用,建议在CubeProgrammer里选择“Erase sectors”而不是“Erase full chip”,这样只擦除M4核应用所在扇区,保留M0+核的协议栈固件。不然你全片擦除后,蓝牙协议栈固件也消失了,重新下载BLE固件是另一套繁琐流程。
6.2 关于低功耗
这是我踩得最深的一个坑。WB55常用于低功耗场景,工程师喜欢在代码里立刻进入Sleep模式或Stop模式。如果你调试时连接那一刻CPU正睡死,SWD会经常无法建立稳定连接。不是说SWD不能唤醒CPU,而是唤醒过程和调试端口仲裁的时序在特定条件下会冲突。
后来我的习惯是:开发阶段先把低功耗相关代码用宏关掉,保证CPU一直活跃,调试完再打开。如果产品需要验证真实低功耗行为,我会在代码里加一个“调试模式”:上电后等待10秒再进入低功耗,给调试器充足时间连接。这样既不牺牲产品逻辑,又保住了可调试性。遇到“插上ST-Link就正常,拔掉就各种奇怪复位”的板子,也优先检查是不是低功耗进入时序把调试引脚状态改变了。
6.3 关于量产
量产阶段遇到“cannot read, erased, programmed”最头疼,因为板子数量多,人工排查不现实。我的方案是:在产线治具上固定使用STM32CubeProgrammer命令行脚本,烧录前先执行一次Option Bytes检查,确认RDP等级和TZEN状态。如果检测到非预期状态,自动执行全片擦除和Option Bytes恢复,再继续烧录。
脚本里还要加入日志输出,把每块板的序列号、MAC地址、烧录结果写进文件。这样一旦出现批量问题,可以回头定位是连接异常、读保护状态异常还是Flash编程失败。我遇到过一批板子在产线上大概有3%连不上,排查后确认是某批焊接物料导致SWCLK引脚虚焊,而不是固件问题。如果没有日志和批量脚本,这类问题会非常隐蔽。
最后分享一个救砖小技巧
如果你手上的WB55已经被折腾到“Under reset”也连不上的地步,可以先尝试把ST-Link的SWD频率降到最低(部分工具可以到几百kHz),连接时按住板子复位键不放,点击Connect后再松开。原理是让调试器在芯片复位释放的瞬间抢占调试端口,这招对“固件启动后立刻改引脚功能”的板子特别有效。
我个人在实际排查中还有一个小癖好:每次连接前,都先量一下SWDIO引脚对地电阻,正常应该呈二极管特性,大约0.5V压降。如果测出直接短路或高阻,就不用浪费时间去查软件了,先解决焊接问题。这个方法简单但很管用,尤其在量产现场没有示波器的时候。毕竟STM32WB55这颗芯片本身并不容易坏,绝大多数时候都是外围环境在制造问题,找到它、解决它,芯片自然就活了。