CANable 启动审查:BOOT0 谁说了算
把下载跳线插上、重新上电,USB 设备就一定会切到 DFU 吗?
对 STM32G4,这个判断还少了一层:芯片究竟听外部引脚的,还是听内部选项位的。若 BOOT0 又和 CAN 收发器的接收输出共用节点,电路图、复位时刻和选项字节就必须一起看。
下面用一块 STM32G431CBT6 的 USB-CAN 电路做具体审查,并给出一个已经完成验证的只读小工具。目标是把“启动地址由谁选择”算清楚。全文没有板上实测,也没有改写选项字节;程序算出系统存储器入口,并不等于电脑已识别 DFU。
图 1:在对应版本的 EDA 编辑器重新导出的 PCB。左为顶面,右为翻板后的底面,属于工程视图,不是焊接成品照片。
一根线,两个角色
先找 U1 的 44 脚。它标为 PB8-BOOT0,接在 BOOT0 网络上;旁边 45 脚 PB9 接 CAN_TX。再看 H2:1 脚所在节点把 CAN_RX 与 BOOT0 接到了一起,2 脚连接 3V3。
图 2:上半部分是 U1 的真实引脚局部,下半部分是 H2。CAN_RX 和 BOOT0 的两种网络标注在此连接,并非两条相互独立的信号。
这意味着 PB8 在运行阶段可以参与 CAN 接收,在复位启动阶段又可能被当成启动选择输入。跳线能改变这个节点的电平,但“电平变了”和“芯片采用它”是两个不同条件。
审查这种复用设计,第一步不是猜固件,而是把下列信息放在同一页:芯片完整型号与封装、引脚号、节点连接、启动选择位,以及复位时的信号来源。换一个 STM32 系列,不能照搬同一套位定义。
三个位,要分两步读
本次核对依据为 RM0440 Rev 1 的启动表与 FLASH_OPTR 位定义。对这份表,先检查 BOOT_LOCK,再决定有效 BOOT0 的来源。
BOOT_LOCK 为 1,启动地址别名指向主 Flash。工具把它作为必须明确提供的输入,不从 OPTR 猜值,也不实现寄存器读取。
BOOT_LOCK 为 0 时,nSWBOOT0 决定选择源:
- nSWBOOT0 = 1:采用启动采样时的 PB8 电平。
- nSWBOOT0 = 0:采用选项位,有效 BOOT0 等于 1 − nBOOT0。
这个反相关系尤其容易读错。软件选择源下,nBOOT0 为 1,得到的有效 BOOT0 才是 0。随后再按有效 BOOT0 和 nBOOT1 查地址:
| 有效 BOOT0 | nBOOT1 | 启动地址别名 |
|---|---|---|
| 0 | 任意 | 主 Flash |
| 1 | 0 | SRAM1 |
| 1 | 1 | 系统存储器 |
因此,“PB8 被拉高”不能单独证明进入系统存储器:nSWBOOT0 可能使引脚不参与选择,BOOT_LOCK 可能改变判定,而 nBOOT1 也参与有效 BOOT0 为 1 时的地址选择。
这些结论描述的是手册中的地址映射规则,不是修改建议。实际器件应先核对当前参考手册、器件修订版和配置读取结果;不要拿本文的示例十六进制值整字写入选项字节。
延迟供电,只解决它能解决的部分
沿 CAN_RX 继续往回看,U2 为 TJA1051T/3/1J:4 脚是 RXD,5 脚是 VIO,接 CAN_3V3。这个接口侧电源经 Q1、Q2 与阻容网络控制。
图 3:U2 的 RXD、VIO 与下方电源控制电路。图中同时保留 CAN 接口、终端电阻和保护部分,便于核对完整上下文;本文没有验证整条 CAN 通信链路。
局部器件是 Q1 AO3401、Q2 AO3400A、R9 1 MΩ、C15 100 nF、R10 100 kΩ。R9 与 C15 的标称乘积为 0.1 s,但这个数值不是已经测得的 VIO 接通延时。
图 4:从图 3 保真裁剪的电源控制局部。没有重新绘制线路、修改参数或补生成芯片标记。
MOS 管的阈值、3V3 上升过程、负载、漏电和电容初始电压,都会影响实际切换过程。尤其要区分两种启动条件:
冷上电时,C15 的初始状态取决于此前断电与放电过程;供电维持期间复位时,不能假设 C15 自动回到零电压。MCU 重新采样启动条件,也不代表 RC 网络重新执行一次相同的上电过程。
所核对手册描述的锁存点是复位释放后内部启动时钟的第 4 个边沿,退出 Standby 时也会重新采样。没有实际启动时钟与波形依据,就不能把这个边沿换算成板上若干微秒,再宣称 RC 一定覆盖了采样窗口。
这块电路提出了很明确的验证问题:如果配置采用 PB8,复位采样时 PB8 究竟处于什么电平?同时观察 3V3、NRST、CAN_3V3 和 PB8,比较冷上电与供电维持的复位过程,才可能回答它。本文未进行这些测量,不能据静态图判定原板已发生故障或保证改动后的效果。
先做一个不会写设备的审查器
工程改进从一个可验证的小范围开始:把选项位、引脚样本和启动表的关系实现成独立脚本。它只接收输入并输出 JSON,不连接设备,不烧录固件。
FLASH_OPTR 中,本次使用的位位置是 nBOOT1 的 bit 23、nSWBOOT0 的 bit 26、nBOOT0 的 bit 27。boot_route.py 的 classify() 内,决定结果的代码如下;完整函数、参数校验和命令行入口随附件提供:
nboot1 = (optr >> 23) & 1
nswboot0 = (optr >> 26) & 1
nboot0 = (optr >> 27) & 1
if boot_lock:
source, effective, alias, used = "BOOT_LOCK", None, "main_flash", False
else:
source = "PB8" if nswboot0 else "option_bit"
effective = pb8 if nswboot0 else 1 - nboot0
used = bool(nswboot0)
if effective is None:
raise ValueError("PB8 sample is required when nSWBOOT0=1 and BOOT_LOCK=0")
alias = "main_flash" if effective == 0 else (
"system_memory" if nboot1 else "sram1"
)
pb8 必须是启动采样时的值。程序运行几秒后再读取 GPIO,把那个结果填进来,无法还原先前的启动采样。若选择引脚而没有提供样本,工具会报错,不替读者猜高低电平。
解压源码包后,在 source 目录打开 PowerShell。验证环境为 Python 3.12.14,只用标准库;以下两组值都是合成输入:
python -B boot_route.py --optr 0x08800000 --boot-lock 0
python -B boot_route.py --optr 0x04800000 --boot-lock 0 --pb8 1
第一组使用选项位,nBOOT0 为 1,有效 BOOT0 为 0,得到主 Flash。第二组使用 PB8,给定采样值为 1,且 nBOOT1 为 1,得到系统存储器。图 5 来自这两次程序实际输出的字段摘录。
图 5:程序真实执行结果的排版图。pb8_sample_used 说明本次分类是否使用 PB8;第一组输入未使用它。图中的 OPTR 不是从这块板读取的配置。
回归测试没有再写一份相同的判断函数来“自证”。测试期望来自独立转录的七行手册启动表,把不关心项展开后覆盖 BOOT_LOCK、nSWBOOT0、nBOOT0、nBOOT1 与 PB8 的全部 32 种二进制组合,并要求每种组合只有一行匹配。
此外还检查反相语义、无关 OPTR 位、缺失 PB8、非法输入和 CLI 错误处理。六项回归在上述环境全部通过,无效命令行输入以退出码 2 拒绝。
python -B -m unittest -v test_boot_route.py
这个验证范围到启动地址分类为止。Flash 内容是否有效、读保护与双 Bank 状态、系统 Bootloader 是否适用、应用是否运行以及 USB 是否枚举,都需要各自的依据。JSON 出现 system_memory,不能写成“DFU 测试通过”。
PCB 能核对什么,不能替代什么
回到同版本顶面局部,可以找到 MCU、下方 CAN 收发器、接口电源控制器件以及板端 DFU 接口。EDA 顶、底面用于确认器件位置和布线背景,原理图用于确认节点,工具用于核对启动表。三者各有用途。
图 6:从本次 EDA 顶面 PNG 裁剪的实际布线。保留原工程丝印;没有改板,也没有执行 ERC/DRC 或实体连通测试。本次未核实板框尺寸,不能据图给出加工尺寸。
遇到类似“下载跳线好像不起作用”的现象,可按这个顺序收集证据:先核对器件与网络,再读取实际启动配置,只有在配置采用外部引脚时才把采样电平带入计算。地址分类符合预期之后,再查供电、USB、固件和主机驱动。
一条排错链路的价值,在于每一步都有输入、有结论、有边界。看到 BOOT0 就直接判断 DFU,恰好跳过了最该先确认的那一步。
源码、来源与验证范围
源码包:下载完整源码包。附件名为 canable2-boot-route-audit-v1.0.zip,含完整 boot_route.py、测试、独立表格、README、MIT 许可及验证记录。解压后按 README 运行,不需要连接电路板。本文的原理图整体与 PCB 高清母图在本次取材中保留;工程版本未修改。
创作来源:HAOstudio 的《【复刻】CAN转USB通信模块-CANable_V2.0》,完整项目网址:https://oshwhub.com/haostudio/canable_v2 。项目页与对应 EDA 工程标示 Public Domain。使用其 V1.0、2024-01-25 的硬件工程重新取图;原理图整体截图为 4000×2600,PCB 顶底面 PNG 均为 2993×4096。正文只做裁剪、保真缩放与轻度锐化,保留必要工程标记,没有使用原文低清图。
参考资料:STM32G4 RM0440 Rev 1,第 87 页 Table 5 与第 107 页 FLASH_OPTR。对应摘录在 ST 中文社区文章中核对:https://shequ.stmicroelectronics.cn/thread-631814-1-1.html 。该帖文字说明与所附手册表格对 nBOOT0 极性有冲突,本次以手册表格为准;维护具体器件时仍须复核当前手册。厂商手册截图不收入本文和源码包。
实际完成:同版本电路与启动规则审查、独立只读工具 v1.0、六项回归和两组合成输入运行。硬件、上游固件与上位机未修改;未进行烧录、选项字节写入、仿真、ERC/DRC、波形或 DFU 实测。本次源码为独立撰写的 MIT 代码,不分发上游固件或另行链接的软件。
技术交流,欢迎关注微信公众号:美男子玩编程。



