手里拿到一块 Nucleo-WBA25CE1 开发板,第一件事不是点灯,而是把它切到 Direct Test Mode(DTM)里跑一趟射频指标。这个标题看着像是蓝牙协议栈里的一个冷门模式,实际上凡是做 BLE 产品的硬件工程师、射频调试工程师,还有准备做蓝牙认证的研发朋友,都绕不开它。这篇文章我就把为什么需要 DTM、怎么在 Nucleo-WBA25CE1 上把 DTM 跑起来、以及实操中常见的坑串成一条完整链路记录下来,希望能帮到正在折腾同样事情的你。
先说结论性的一句话:Direct Test Mode 是蓝牙核心规范里为射频物理层测试专门定义的一种工作模式,它让设备不经过完整的蓝牙协议栈,直接在 PHY 层做收发测试。对开发板来说,这就等于给射频前端开了一个“旁路开关”,我可以绕开 GAP、GATT 这些上层逻辑,直接命令射频芯片在指定信道上发射特定包型、或者在指定信道上接收并统计误包率。对正在调试射频匹配、准备做认证预扫、或者想评估板卡发射功率的人来说,这是最快、最干净的验证手段。
下面我按照完整的实操链路来写,从原理到工具,从编译烧录到测试执行,最后是问题排查,大家可以根据自己的情况直接跳着看。
1. 为什么偏偏要用 Direct Test Mode 验证 NUCLEO-WBA25CE1
1.1 从测试视角理解 DTM:绕开协议栈,直达射频底层
蓝牙设备平时工作的时候,数据要经过应用层、GATT 层、L2CAP 层、链路层,最后才到射频物理层。这个链路好处是功能完整,坏处是如果我想精确测量某个频点的发射功率、频率误差、调制特性,这些上层协议反而成了干扰变量。DTM 的思路很直接:把链路层之上全部摘掉,只保留物理层收发,让测试设备通过一串很简单的控制命令就能让 DUT(被测设备)持续发射或者接收。
打个比方,这就跟汽车出厂前的台架测试一样。整车路测需要考虑路况、变速箱、驾驶习惯,但发动机本身有没有问题,得把发动机拆到台架上,直接踩油门看转速稳定不稳定、功率曲线达不达标。DTM 就是这个“台架”,它测试的是射频前端本身的能力,抛开了协议栈的调度影响。
具体到 Nucleo-WBA25CE1 这块板子,它用的是 ST 的 STM32WBA 系列无线 MCU,集成了 2.4GHz 射频收发器。在正常 BLE 工程里,射频模块由协议栈驱动;但一旦进入 DTM,单片机里的协议栈主体不参与工作,取而代之的是一小段 RF 驱动代码,它等待接收来自测试仪或者串口的 DTM 控制命令,然后立刻执行对应的射频动作。这也解释了为什么 DTM 固件往往非常精简,启动快、行为可控、没有多余的软件干扰。
1.2 实际项目中 DTM 能解决什么问题
很多朋友第一次接触 DTM 是卡在实验室认证那一步,但实际上它的应用远不止认证。
第一个场景是蓝牙 SIG 认证里的 RF-PHY 测试。做蓝牙认证时,认证实验室会要求 DUT 进入 DTM,然后把测试仪和 DUT 连接起来,跑一组规定的发射、接收测试项。如果没有 DTM 支持,设备没法被测试仪控制,认证流程走不动。所以产品要过蓝牙认证,DTM 几乎是必备能力。
第二个场景是研发阶段的射频调试。比如你觉得天线的匹配不太好,想看看板卡在信道 19(2440 MHz)上的实际发射功率是否达标,这时候只需要把 DTM 固件烧进去,让射频持续在某信道发包,再用频谱仪看结果。整个过程可以在几分钟内完成,不用写一整套 BLE peripheral 应用代码。同样的,测试接收灵敏度时,可以让测试仪持续发射,DUT 在 DTM 接收模式下统计误包率。
第三个场景是产线射频校准。很多 BLE 模组厂在出厂前会对每个模组做射频功率校准和频偏校准,产线上的自动化测试程序正是通过 DTM 命令来驱动待测模组,搭配综测仪读取实际发射功率,再通过调整内部寄存器来校准。这时候 DTM 不是可选项,而是产测工具链的地基。
2. 开发板与 DTM 测试环境准备
2.1 先看清 NUCLEO-WBA25CE1 的硬件底细
Nucleo-WBA25CE1 是 NUCLEO-64 规格的开发板,核心是一颗 STM32WBA25 系列无线 MCU,Cortex-M33 内核,主频 100MHz,带 2.4GHz 射频收发器。板载了 ST-LINK 调试器,通过一根 USB 线就能同时完成供电、调试和虚拟串口输出,这对 DTM 测试来说非常方便——因为 DTM 控制命令和日志输出正好可以走这个虚拟串口。
板卡上的 LED、用户按键、Arduino 兼容接口、ST Zio 扩展接口这些资源,在 DTM 工程里一般用不到。但有一点要特别注意:射频测试必须保证天线或者射频连接路径是正常的。开发板的天线区域一般会设计匹配网络和天线座,如果你要做传导测试,需要确认板上是否有 SMA 座或者预留的射频测试点;如果是用 PCB 天线做辐射测试,测试环境放在屏蔽箱里,保证外部干扰不影响结果。
供电也要提一嘴。BLE 射频发射电流并不小,当射频连续发包时,瞬时功耗会比单片机空跑高不少。建议用 USB 供电时选择质量好一点的线,不要用那种只能充电不能传输数据的线。如果测试过程中发现发射功率异常偏低,第一步先排除供电问题。
2.2 四样工具一次备齐:软件、固件、串口、射频仪器
软件方面需要准备四样东西。第一个是 STM32CubeIDE,或者其他支持 STM32WBA 系列的 IDE,比如 Keil、IAR,看个人习惯,ST 生态下我用 STM32CubeIDE 最省事。第二个是 STM32CubeProgrammer,用于烧录和擦除,也可以直接在 IDE 里下载程序,但 CubeProgrammer 在单独处理固件时更独立。第三个是 STM32CubeMonitor-RF,这是 ST 官方的 RF 测试上位机工具,支持把开发板变成一台简易信号源和分析仪,具体支持程度要看工具版本对 WBA 系列的支持情况。第四个是串口助手,我用过很多,功能上其实都差不多,自己习惯就好。
射频仪器方面,如果你手头有蓝牙综测仪,比如 Anritsu MT8852B、Rohde & Schwarz CMW270/CMW500、LitePoint IQxel 这一类,那直接走正规 DTM 测试流程。如果暂时没有综测仪,也可以用频谱仪加信号源做一个简化版测试,前提是你能手动控制 DTM 信道和包型。这篇文章下面会分别讲这两种路径。
串口驱动也要提前确认。Nucleo 板载 ST-LINK 的虚拟串口在 Windows 下通常会自动识别为 COM 口,如果插上 USB 后设备管理器里看不到端口,去 ST 官网装一下 ST-LINK USB 驱动。这一步看着简单,但我在实践中遇到过好几次同事卡在“板子不亮串口”上,最后发现就是驱动没装。
2.3 测试连接拓扑:根据测试方式选择接线
在正式操作前,先把线连对。大致分两种连接拓扑:
一是软件控制的闭环测试,电脑通过 USB 连接开发板,开发板的天线端连接测试仪器。电脑上的 STM32CubeMonitor-RF 或串口助手下发 DTM 命令,DUT 执行发射或接收,然后由仪器侧测量结果。这种方式适合快速验证发射功率和基本信号质量。
二是测试仪直接作为 DTM 主控,测试仪通过串口连接开发板的 UART 引脚(DTM over 2-wire),同时测试仪通过天线口连接 DUT。这个方式更贴近蓝牙认证实验室的做法,因为测试仪会自己控制 DTM 命令序列,逐项执行测试用例。使用这个方式时,需要把开发板上的虚拟串口换成实际 UART 引脚,具体引脚号以开发板手册和示例代码里的管脚定义为准。
提一句,做传导测试时,天线如果没有断开或者没有通过良好屏蔽的同轴线接到仪器上,测试结果会被周围环境干扰,导致功率读数虚高或误包率异常。这是我见过最多的测试数据问题源头,所以接线时不要图省事。
3. 烧录 DTM 固件:从 Cube 到串口 Log 全流程
3.1 获取 STM32CubeWBA 固件包,找到 DTM 示例工程
STM32WBA 系列的外设驱动、BLE 协议栈和示例代码都在 STM32CubeWBA 固件包里。下载方式有两种:在 STM32CubeMX 的软件包管理器里直接安装,或者到 ST 官网下载对应版本的压缩包。安装好后,固件包目录结构大概是STM32Cube_FW_WBA_Vx.y.z,里面按板卡和例程分类存放。
要找 DTM 例程,在Projects目录下进入对应板卡目录,例如Projects/NUCLEO-WBA25CE1/Applications/BLE/,里面应该能看到带有 DTM 或 RF 关键字的应用工程,比如BLE_RF_DTM。如果你的固件包版本还没有预置 WBA25CE1 的板级例程,也不要慌,可以找一个同系列相近板卡的 DTM 工程,复制后通过 STM32CubeMX 重新选择 Board 或者 Device,调整引脚后再编译。这一步就是 STM32Cube 生态常规操作,只要原理图匹配,基本能启动。
顺带提醒一下,STM32CubeWBA 固件包里不同版本的示例代码可能在文件名、目录结构上有差异,不要拿着旧版本的教程硬套新版本路径。最稳的做法是在工程目录下搜 “DTM” 关键字,或者看 README 里的描述,确认例程是不是做射频直接测试的。
3.2 编译、烧录与串口验证,一个环节都不能省
拿到例程之后,下一步是编译。用 STM32CubeIDE 直接导入工程文件,一般选.project或.ioc所在的目录。导入后先检查工程配置里的芯片型号,确认是 STM32WBA25 系列。如果编译器报找不到头文件或器件定义,多半是固件包版本与 IDE 器件支持包不匹配,去 CubeMX 里更新一下固件包,或者在 IDE 中更新器件库。
编译通过后,把开发板通过 USB 连到电脑,在 IDE 里选择调试方式为 ST-LINK,点击下载。烧录完成后,打开设备管理器确认虚拟串口的 COM 口号,用串口助手打开。DTM 示例工程通常会在启动时打印一些日志,比如固件版本、初始化成功信息、进入 DTM 等待命令的提示。如果串口一个字都不打印,先查驱动和 COM 口号,再查工程里的日志默认波特率是不是和你串口助手一致。常见默认波特率是 115200,但有些工程会用 921600,不要想当然。
这里有第一个关键心得:DTM 示例的日志输出和 DTM 命令入口,在很多 ST 例程里是复用同一个 UART 的。也就是说,你在串口助手里既能收到启动日志,也能直接往下发 DTM 命令字节。所以在正式测试前,先确认一下这个串口是不是命令通道。如果用 STM32CubeMonitor-RF,它会自动识别并打开这个端口,不要和串口助手同时占用同一个 COM 口,否则会互相冲突,表现为“端口被占用”或命令无响应。
4. 三种方式实操 NUCLEO-WBA25CE1 的 Direct Test Mode
4.1 方式一:用蓝牙综测仪做标准的 DTM 测试
这是最接近实验室认证的方案。你需要一台蓝牙综测仪,比如 Anritsu MT8852B 或者 CMW270,以及一根合格的射频电缆。连接方式是:综测仪的 RF 口通过线缆连接到开发板天线端,最好在测试前先校准线缆损耗,把这个损耗值在综测仪里做补偿。
然后需要让 DUT 进入 DTM over UART 模式。把开发板的 UART 引脚连接到综测仪的 DTM 控制口。不同综测仪的物理接口可能不一样,有的用 DB9 串口,有的用 USB 转串口,需要做一个电平转换和接线板。接线前一定要确认电平一致,BLE 的 DTM UART 一般是 3.3V TTL,很多蓝牙测试底板也是 3.3V,但还是量一下最稳,电平不一致轻则通讯失败,重则烧引脚。
综测仪上选择 Bluetooth LE 的 Direct Test Mode 测试项,配置需要的信道、包长和包型。测试仪下发命令后,DUT 就会开始发射或接收,仪器端实时显示发射功率、频率误差、调制特性、接收误包率等指标。这套流程的优势是自动化程度高,测试项覆盖完整,和蓝牙认证实验室的测试方法保持一致,适合在产品定型前做一次全面的射频体检。
如果条件允许,建议至少跑这几个测试项:单信道发射功率(最低信道、中间信道、最高信道各测一次)、频率偏移和漂移、发射调制特性、接收灵敏度。这些指标能覆盖射频前端大部分问题。测灵敏度时,仪器会在不同功率电平下发射,DUT 在接收模式下提交统计结果,测试仪自动算出临界灵敏度。整个过程跑完可能需要几分钟,但它给出来的信心值远高于“频谱仪看着信号好像还行”。
4.2 方式二:用 STM32CubeMonitor-RF 免综测仪快速验证
如果只是想做研发阶段的初步验证,不想动用实验室里的综测仪,或者实验室仪器档期排满了,可以用 STM32CubeMonitor-RF 在电脑上直接配合开发板做测试。这个工具本来是 ST 生态里用于无线 MCU RF 性能评估的上位机,连接 ST-LINK 虚拟串口后,可以直接控制板卡进入类似 DTM 的收发模式。
具体流程是:打开 STM32CubeMonitor-RF,选择对应的串口,界面上一般会要求选择当前连接的板卡或目标器件。连接成功后,工具会自动识别芯片,并读取固件中的 RF 相关信息。然后你就可以在界面上配置发射信道、包类型、包长,点击开始,工具就能通过板载射频完成发射或接收测试。发射模式下,外接频谱仪就能看到持续的载波或调制信号;接收模式下,需要外接一个信号源以指定频率和功率发射数据,工具内部会统计误包率并显示出来。
这个工具的界面不同版本可能有差异,但核心操作逻辑不变:选串口、配参数、启动测试。如果你打开工具后发现连不上板卡,先确认是不是串口助手占用了端口;如果能在工具里看到信号但数据一直为 0,检查一下开发板天线端是否接入了测试设备,或者板卡射频初始化是否成功。
这里必须说清楚一个边界:STM32CubeMonitor-RF 不等于蓝牙认证用的 DTM 测试仪,它能做快速验证和趋势观察,但正式的蓝牙认证报告还是以综测仪数据为准。所以我的习惯是研发阶段先用它把大方向调对,送认证前再用综测仪做完整回归。
4.3 方式三:手动 HCI 命令 + 频谱仪,理解底层原理
如果你想彻底搞明白 DTM 的底层机制,或者想为产线写一套自定义的自动化测试脚本,可以尝试手动下发 HCI 命令来驱动 DTM。这个方法要求你对蓝牙 HCI 层有一定了解,但它不受限于 ST 工具,也更容易集成到自己的测试系统里。
在蓝牙核心规范里,与 BLE DTM 相关的三个核心 HCI 命令分别是 LE Receiver Test、LE Transmitter Test、LE Test End。发送这些命令时,需要按 HCI 命令包格式构造数据,包含操作码和参数。比如 LE Transmitter Test 命令需要指定测试信道、测试数据长度和数据包型,LE Receiver Test 需要指定接收信道。命令下发后,DUT 会立即开始发射或接收,直到接收到 LE Test End 命令才会停止。DUT 接收测试的统计结果也在 LE Test End 的返回事件中上报。
在你的电脑上,可以用串口助手以十六进制方式向开发板的 DTM 串口发送命令。命令的完整字节序列以蓝牙核心规范和 ST 的 HCI 接口文档为准,不同版本的协议栈可能对命令封装有细微差别。自己拼包时最容易犯错的就是字节序和参数取值范围,比如测频点不是信道号直接换算,而是通过指定信道号由公式计算,BLE 广播信道 2402MHz 对应起始频率,信道间隔 2MHz,信道 k 的频点等于 2402 + 2k MHz。信道 0 到 39 对应 2402MHz 到 2480MHz。
用这种方式,你可以在没有综测仪的情况下做一个简单的闭环验证:让 DUT 在某个信道持续发射,用频谱仪观察频率是否落在目标频点、功率是否在预期范围;再切换成接收模式,用信号源发射已知分组,看 DUT 统计的误包率和发射功率的关系。方式灵活,但需要你自己维护命令序列和测试逻辑。
代价是要花时间调通命令通路,而且一旦命令格式写错,DUT 不会有任何反应,排查成本比前两种方式高。我的建议是:先把方式二跑通,再利用它的上位机日志观察命令交互,再用方式三自行构造命令,这样学习曲线会平缓很多。
5. 问题排查与避坑笔记
5.1 环境与烧录阶段的常见问题
烧录 DTM 固件时遇到问题是最打击人的,因为还没看到希望就卡住了。我整理了几个高频问题:
第一个是 ST-LINK 无法识别。表现是 STM32CubeProgrammer 里看不到目标芯片,或者 IDE 下载时报 ST-LINK 连接失败。排查顺序是:换一根 USB 数据线,确认不是充电线;检查电脑设备管理器里 ST-LINK 枚举是否正常;在 IDE 里把 ST-LINK 的固件升级到最新。很多时候 ST-LINK 固件太老会导致新芯片连接不稳定。
第二个是编译报错,找不到器件定义或者宏定义。这个多半是固件包和 IDE 器件支持包版本不匹配。解决方法是在 STM32CubeMX 中重新安装并更新 STM32WBA 系列的固件支持包,保证 IDE 里能看到对应芯片型号。如果某一个头文件路径报错,检查工程属性里的 include path 是否完整。
第三个是串口无输出。确认串口号是不是板卡的虚拟串口,有的电脑 USB 插上后会枚举出两个串口,别选错了。再确认波特率。如果两个都没问题,按一下板卡上的复位键,看启动日志会不会重新打印,可能是程序已经在运行但日志没刷新出来。
5.2 DTM 测试执行阶段的数据异常排查
射频测试本身有时也会出现一些让人挠头的数据。我把典型现象整理成表格,方便对照排查。
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
| 频谱仪看不到发射信号 | 天线没接好或射频线缆损坏 | 重新检查射频路径,换线测试 |
| 发射功率比预期低很多 | 供电电压不足、线缆损耗未补偿 | 换 USB 线或外接稳压电源,校准线缆损耗 |
| 频率偏移超限 | 晶振校准未完成或环境温度异常 | 检查是否有准确的 32MHz 晶振,必要时做频偏补偿 |
| 误包率(PER)高 | 接收路径衰减过大、外部干扰、天线阻抗失配 | 检查衰减器设置,使用屏蔽环境,排查天线匹配 |
| DTM 命令无响应 | 串口端口被占用或命令格式错误 | 关闭串口助手,使用隔离供电,重新对照命令字节 |
| 测试结果反复跳动 | 测试环境不稳定,线缆连接松动 | 固定所有连接件,减少人体靠近天线的干扰,尽量在屏蔽箱中测试 |
关于 PER 和 BER,我再补充一个细节。BLE DTM 的接收测试一般统计的是误包率,测试仪连续发送一定数量的数据包,DUT 在接收模式下每收到一个错误包就把它计入统计,测试结束时通过 LE Test End 命令把统计结果上报。所以如果你看到 PER 很高,先不要急着怀疑芯片,检查接收路径的衰减和匹配才是第一位的,我修过很多“灵敏度差”的板子,最后发现是测试线缆本身有问题。
最后说一个我自己的习惯:任何正式测试前,先把已知正常的板卡或者现成参考板跑一遍同样流程,确认测试系统本身是好的,再测试被测板。这样能把测试系统引入的误差和被测试对象的问题区分开,省掉大量排查时间。
这个内容后续要扩展的话,其实还可以向量产测试方向走,比如把 DTM 命令封装成 Python 脚本,结合串口和频谱仪做一轮自动化的产测冒烟。只要掌握了 DTM 的底层逻辑,在 Nucleo-WBA25CE1 上用代码控制射频发射,就只是串口收发和协议解析的问题了。