公司动态

STM32WB55 SafeBoot烧录报错排查:RDP写保护与解锁实战

📅 2026/8/30 0:44:24
STM32WB55 SafeBoot烧录报错排查:RDP写保护与解锁实战
最近在调一个基于 STM32WB55 的 BLE 项目为了做安全的 OTA 升级需要先把 SafeBoot 烧进去。结果第一次上手就被打脸ST-Link 能正常连接芯片但只要一点编程STM32CubeProgrammer 就弹出一句 Error when programming SafeBoot。我整整折腾了两天查遍了论坛和手册最后发现真正的原因远不是一句连接失败那么简单。这篇就把整个排查链路和最终的解决方案整理出来给正在踩同样坑的朋友一个参照。这里说明一下适用的读者如果你正在用 STM32CubeProgrammer 给 STM32WB55 烧 SafeBoot、烧无线栈、或者做安全启动相关的固件更新遇到过 Error when programming SafeBoot、编程到一半失败、连接后无法下载这类问题这篇文章基本覆盖了你需要检查的全部关键点。1. 先说清楚SafeBoot 究竟是哪一段程序为什么这么难烧1.1 STM32WB55 的双核启动链STM32WB55 不是一颗普通的单核 MCU它内部有 Cortex-M4 应用核和 Cortex-M0 无线核。M4 负责跑用户应用M0 核专门处理蓝牙协议栈、Zigbee、802.15.4 这些射频任务。两个核之间通过 IPC 通信M4 要发数据给射频不是自己操作外设而是把命令打包发给 M0 核去执行。这带来一个很重要的特点整颗芯片不只是用户程序 系统 bootloader两层结构而是用户程序 无线栈固件 安全启动服务 系统 bootloader多层结构。ST 把安全启动、无线栈升级、密钥校验这些能力封装在底层服务里其中就包含 FUSFirmware Upgrade Services和 RSSRoot Secure Services。而在很多工程文档和讨论里SafeBoot 指的就是处于启动链最前端的安全引导程序它负责在 M4 应用核心运行之前先校验镜像的签名和完整性防止未授权固件被直接烧进去。你可以把它理解成一道安检门不是谁拿个包都能进候机厅SafeBoot 先检查包的来源和标识通过以后才放行。放到芯片上SafeBoot 检查完下一级镜像后才把启动控制权交给用户应用。1.2 为什么编程 SafeBoot 时特别容易报错正因为 SafeBoot 的角色特殊它通常被放在 Flash 的保护区域内。有些情况下芯片出厂后已经被配置成 RDP Level 1 甚至 Level 2调试接口的访问权限受到严格限制有些情况是用户为了防克隆手动开启了写保护把 SafeBoot 所在的扇区锁死了还有些情况是 SafeBoot 与无线栈共用一些底层 flash 服务直接按普通应用固件的方式去烧写必然触发保护机制。我遇到的 Error when programming SafeBoot核心原因就是这个我要写的目标区域处于保护状态或者当前芯片的调试权限不够导致烧录器打开了连接、却写不进去。所以排查这个错误必须沿着硬件连接 - 调试权限 - 存储保护 - 烧录方式这条线走缺一步都容易绕远路。2. 我是怎么复现到这个报错的三条典型路径2.1 路径一直接烧库函数代码踩到写保护第一种情况最容易发生在刚接触 STM32WB55 的开发者身上。很多人从 STM32F4、F1 系列转过来习惯了直接打开 Keil 或 CubeIDE 点下载以为只要 SWD 连上就能写。结果到了 STM32WB55 上如果之前对 Flash 做过写保护配置或者上一版程序启用了安全启动你再直接烧用户代码就会在烧写到 SafeBoot 区域时撞墙。我当时就是先跑了一个官方示例为了做测试把 RDP 改到了 Level 1。后来再想烧新程序时CubeProgrammer 在连接阶段是正常的能读到芯片型号、UID 和设备 ID但点击下载后没过多久进度条就停住控制台输出 Error when programming SafeBoot。这个路径很典型因为它说明软件和连接都正常问题出在权限和存储保护上。2.2 路径二RDP 从 Level 1 降级失败第二种情况更隐蔽。有人之前出于保密需求把芯片设置成 RDP Level 1。Level 1 下调试接口还能连接但已经不允许随意读写用户 Flash尤其是访问安全相关的区域。这时候你想重新烧录 SafeBoot系统会拒绝写入。正确的做法是先通过 Option Bytes 把 RDP 降到 Level 0但这个降级动作会触发全片擦除而且擦除过程本身也可能因为保护设置而失败。我见过一个典型报错场景在 CubeProgrammer 的 Option Bytes 页面把 RDP 改成 Level 0点 Apply然后弹窗提示要擦除整个 Flash选择确认后界面卡住最终在日志里看到和 Error when programming SafeBoot 类似的提示。这种问题通常不是芯片坏了而是擦除动作和现有无线栈/FUS 分区发生了冲突。2.3 路径三先烧无线栈再烧 SafeBoot地址冲突第三条路径和 STM32WB55 的双核架构直接相关。因为无线栈固件占用了 Flash 中专门划分的区域而 SafeBoot 又处在安全启动段如果你的下载配置里没有把这两个段的地址搞清楚编程器可能会把 SafeBoot 镜像写到无线栈的区域或者反过来把无线栈的数据覆盖到保护区域。我最开始犯的错误就是因为急着测试直接拿同事给的 BLE 项目包把无线栈的 .bin 和 SafeBoot 的 .bin 一股脑塞进烧录脚本。结果无线栈烧录成功后再烧 SafeBoot 就报错。后来看日志才知道烧录器默认把 SafeBoot 当成普通用户代码企图写到 0x08000000 起始地址但那个区域前面已经被 FUS/RSS 相关的安全服务占用了。这一条想说明的是给 STM32WB55 烧录不是一个 hex 文件全搞定那么简单。你首先得承认它是双核系统要分开处理 M4 应用、M0 无线栈、SafeBoot 和系统服务区。3. 第一层排查硬件连接和电源别让 ST-Link 背锅3.1 VDDSW 没接M0 核根本起不来第一次排查时我下意识认为是 ST-Link 连接不稳定换了杜邦线、换了调试口问题依旧。直到我翻到数据手册的电源域说明才反应过来STM32WB55 有一个独立电源域 VDDSW专门给 M0 无线核和射频部分供电。如果这个引脚没有正确供电M0 核起不来无线栈无法初始化SafeBoot 相关的底层服务也就没有运行条件。实际表现是芯片从 SWD 接口看仍然能连接因为你看到的是 M4 核但一旦要访问与无线核相关的 flash 区域或者要执行安全启动相关操作底层服务不响应编程就会中断。所以我给所有用 STM32WB55 做板子的人一个建议画板时一定要确认 VDDSW 接法正确不能想当然地认为它就是普通模拟电源。开发板、自制板、模块板都分别量一下 VDDSW 电压。3.2 SWD 连接质量NRST、短线、电平硬件排查的第二件事是 SWD 连接线。这里有个容易被忽略的点很多 STM32WB55 开发板在设计时已经把 NRST 引出来了但你在调试时如果不是用 ST-Link 的 20 针全功能接口而是自己接四根线SWDIO、SWCLK、GND、3V3往往省掉了 NRST。省掉 NRST 不是完全不能烧但在芯片处于异常状态、或者要修改 Option Bytes 时没有复位信号会让你陷入连接正常但操作失败的怪圈。我后来特意把 NRST 加上CubeProgrammer 的稳定性明显提升。另外SWD 线最好控制在 10cm 以内杜邦线质量差的时候高速下载很可能在写 Flash 中途断连报错日志也会出现类似 Error when programming 的信息。3.3 先确认 ST-Link 和 CubeProgrammer 版本这个问题看着基础但我确实在版本上栽过。STM32CubeProgrammer 早期版本对 STM32WB 系列的支持并不完整尤其是对 FUS 和 SafeBoot 相关的命令支持不够。如果你的版本低于 2.12建议先升级到 STM32CubeProgrammer 最新版本ST-Link 固件也要同步升级用 ST 官方工具 ST-Link Upgrade 刷一遍。在排查顺序上我会先用 CubeProgrammer 做一次最小验证连接芯片读取 UID 和 Flash 大小。如果这一步都稳定再继续往下查保护。如果连这步都时好时坏那基本可以判断是硬件连接问题先别急着动 Option Bytes。4. 真正的主凶RDP、写保护和 Option Bytes4.1 RDP 三级权限与烧录失败的关系排查完硬件后问题大概率落在 RDP 和 Option Bytes 上。RDP 是读保护但它不只是防止别人读固件那么简单它直接决定了调试接口能不能访问 Flash能不能修改 Option Bytes甚至能不能全片擦除。RDP 等级调试访问Flash 读/写Option Bytes 修改解除方式Level 0完全开放正常读写可以修改无需解除Level 1仍可连接但受限用户 Flash 读被限制写可能被拒绝受限降级到 Level 0会触发全片擦除Level 2调试接口永久关闭不可直接读写不可修改不可逆芯片锁定如果你之前用 Trusted Package Creator 或者安全启动脚本给芯片设置过保护RDP 很可能不是 Level 0。这时候直接编程 SafeBoot 会报错原因就在这。比较麻烦的是 Level 1因为 CubeProgrammer 连接时看起来一切正常但执行写操作就会失败报错信息不直接提示RDP is set而是给你一个通用的烧写错误。我建议在任何安全启动相关操作前先用命令行工具读取 RDP 状态STM32_Programmer_CLI.exe -c portSWD modeUR连接成功后会列出 Option Bytes 摘要其中 RDP 一栏会显示当前等级。如果你看到RDP: Level 1或RDP: Level 2先不要烧录任何东西降级处理是第一优先级。4.2 WRP / PCROP 对 SafeBoot 区域的封锁除了 RDP还有一类保护和防克隆有关叫写保护 WRP 和代码读保护 PCROP。STM32WB55 的 Flash 分为多个扇区组Option Bytes 里可以对某几个扇区使能写保护。一旦写保护使能用户程序无法往这些扇区写入调试接口也不行。SafeBoot 由于处在安全引导区域经常被出厂配置或手动配置成写保护状态。这种情况下编程动作会被硬件拒绝CubeProgrammer 就会报 Error when programming SafeBoot。实际操作中我会在 CubeProgrammer 的 Option Bytes 页面里逐项检查RDP必须为 Level 0WRP1A / WRP1B / WRP2A / WRP2B需要确认 SafeBoot 对应的扇区组没有被置位PCROP确认 SafeBoot 区域没有被设置成代码读保护BOOT0 / nSWBOOT0 / nBOOT1确认启动模式不会干扰编程如果你打算彻底还原芯片最省事的办法是用 GUI 界面一键把保护全部取消。但注意这个动作可能会触发全片擦除包括你的无线栈。所以操作前先做好固件备份。4.3 用 CubeProgrammer 一键解除保护的正确姿势具体操作是这样打开 STM32CubeProgrammer连接成功后进入Option Bytes页面在Read Out Protection下拉框里选Level 0点击Apply。此时程序会弹窗提示 This operation will erase all the device 之类的警告确认后等待完成。如果是命令行环境可以这样解锁STM32_Programmer_CLI.exe -c portSWD modeUR -ob RDP0执行完以后芯片会执行一次全片擦除调试权限恢复到 Level 0。这时再连一次确认 RDP 显示为 Level 0就可以继续烧录 SafeBoot 了。需要特别强调的是 RDP Level 2 不可逆一旦设置成 Level 2调试口永久锁定只能换芯片。所以除非你真的要做量产防破解否则千万不要在生产之前乱开 Level 2。5. 成功把 SafeBoot 烧进去的完整操作流程5.1 烧录前的准备工作我踩过坑之后形成了一个固定流程每次给 STM32WB55 烧 SafeBoot 都按这个走基本不再出问题。准备阶段要做三件事备份当前芯片的无线栈和用户固件。你可以用 CubeProgrammer 的Read功能把整个 Flash 导出成一个 bin 文件放在安全目录。这一条在你有无线栈、有校准数据、有量产固件时尤其重要不然全片擦除之后哭都来不及。拿到正确的 SafeBoot 镜像。不同 STM32WB 系列、不同无线协议栈版本对应的 SafeBoot 可能不一样。最好从 ST 官方固件包STM32Cube_FW_WB里找不要随便用网上传的 bin。确认烧录地址和下载算法。STM32WB55 的项目里CubeProgrammer 会加载对应的外部加载器或内部 Flash 算法如果选错烧录时也会出现编程错误。5.2 GUI 和 CLI 双版本操作推荐用 GUI 版本做可视化烧录用 CLI 版本做批量生产。GUI 的操作路径是连接 ST-Link 后在Download页面选择 SafeBoot 镜像文件确认起始地址0x08000000根据你工程的 MAP 文件确认勾选Verify programming然后点击Start。如果你的 SafeBoot 镜像不是独立文件而是需要配合 FUS 更新那就要用Firmware Upgrade Services相关的流程。简单来说ST 把无线栈和 SafeBoot 的底层升级集成在 FUS 里你需要在 CubeProgrammer 的FUS页面连接底层服务然后选择要升级的镜像。CLI 版本的核心命令大致是这样的# 1. 解除读保护并全片擦除慎用 STM32_Programmer_CLI.exe -c portSWD modeUR -ob RDP0 # 2. 下载 SafeBoot 镜像到指定地址 STM32_Programmer_CLI.exe -c portSWD modeUR -w SafeBoot.bin 0x08000000 -v # 3. 如果是无线栈相关先通过 FUS 接口确认状态 STM32_Programmer_CLI.exe -c portSWD modeUR -fwupgrade WirelessStack.bin我在生产脚本里还会在烧录之后加一个-v参数也就是Verify,确保写入到 Flash 的数据和源文件一致。这个验证步骤能帮你排除大部分未发现的编程错误。5.3 烧完怎么验证烧完 SafeBoot 之后不要急着断电。我一般做三步验证第一步重新连接 CubeProgrammer读取 Option Bytes确认 RDP 等级没有意外变成 Level 1 或 Level 2。第二步通过Read功能把刚写入的 SafeBoot 区域再读出来和源 bin 做一次 MD5 或 SHA256 比对。命令行可以加-v自动校验但手工比对更直观。第三步如果是带安全启动的项目直接复位芯片观察应用是否能够正常开机。如果 SafeBoot 校验不过芯片会卡在启动阶段表现就是 LED 不跑、串口没有输出、SWD 能连接到但程序不运行。这种情况第一时间检查签名、密钥和 SafeBoot 版本是否匹配。6. 避坑总结编程 SafeBoot 的快速检查表最后把我这次排查中认为最值得记住的几点列成一个快速检查表下次再遇到 Error when programming SafeBoot照着走可以省很多时间。检查项可能症状解决方向ST-Link / 杜邦线 / NRST连接不稳定烧到一半断开换短线接 NRST升级 ST-Link 固件VDDSW 电源能连接但无法写无线相关区域检查 VDDSW 供电万用表实测RDP 等级编程被拒全片擦除失败降级到 Level 0注意会擦除 FlashWRP / PCROPSafeBoot 区域无法写入Option Bytes 里取消写保护CubeProgrammer 版本旧版本对 WB55 支持不全升级到最新版本镜像和地址不匹配烧录成功后无法启动核对 MAP 文件重新选择起始地址另外我想特别建议一点不要把 SafeBoot 烧录和普通应用烧录混在一个脚本里。STM32WB55 的 Flash 布局很讲究SafeBoot、FUS、无线栈、用户应用、用户数据区每一块都有各自的地址和保护策略。我在量产脚本里会把 SafeBoot 和无线栈的烧录分离先烧底层服务再烧用户应用最后统一设置 RDP Level 1 做安全保护。这次踩坑让我最大的体会是遇到编程报错第一步不是怀疑硬件坏了也不是盲目去 Unlock而是先把芯片当前的调试权限、保护等级和 Flash 布局搞清楚。很多时候问题就出在你以为能写但芯片根本不让你写。ST 的安全启动机制本身就设计得比较谨慎你越急着跳过去它就越会在你最想不到的地方拦住你。希望这篇排查记录能帮你少走几趟弯路。