DTM命令实战:不依赖HCI/ACI的蓝牙射频测试指南
2026/8/31 22:26:44 网站建设 项目流程

做射频测试的同行都知道,HCI 和 ACI 是两个绕不开的接口词。可真到了蓝牙认证和产线量产测试环节,我更习惯直接使用 DTM 命令去控制被测设备,而不是费劲去跑协议栈。DTM 全称 Direct Test Mode,蓝牙规范里专门为射频测试定义的直通模式,它可以让芯片乖乖地发一个固定频率、固定功率的信号,或者统计固定通道上的接收丢包率。最近后台不少人在问“wifi芯片aci测试”和 DTM 到底什么关系,干脆写一篇完整实操向的文章,把“用 DTM 命令控制、而不是 HCI / ACI 控制”这件事讲透。这篇内容适合刚接触蓝牙/WiFi 产测的工程师,也适合做底层射频验证的硬件开发者,读完你至少能知道 DTM 命令长什么样、怎么发、踩过哪些坑。

1. 为什么是 DTM,而不是 HCI / ACI

1.1 三套接口,分工完全不同

很多人刚接触蓝牙和 WiFi 芯片时,容易被 HCI、ACI、DTM 这三个缩写弄混。简单说,HCI 是主机和控制器之间的标准通信接口,蓝牙协议栈跑在上面,用来发起扫描、创建连接、收发 GATT 数据,是“正常工作模式”的总线。ACI 则是厂商私有的应用控制接口,常见于 WiFi 芯片或者 Combo 芯片,主要用来做射频校准、天线调优、固件参数配置,不同厂家之间的命令格式甚至名字都可能不一样。

DTM 是另一条路,它不关心你怎么建连、怎么发包、怎么组网,只做一件事:直接控制射频前端进入发射或接收测试状态。你可以把 HCI 和 ACI 理解成“驾驶模式”,车能跑、能转向、能停车;而 DTM 是修车店里的“底盘测功机”,不关心你踩刹车灵不灵,只管把发动机拉到某个固定转速,测输出功率、测振动、测油耗。

所以标题里说“not HCI / ACI”,核心意思就是:测试射频指标时,不要去依赖完整的协议栈,也不要依赖厂商私有驱动接口,而是走蓝牙社区和认证机构通用的 DTM 测试语义。严谨一点说,很多芯片的 DTM 命令在底层传输时仍然会套一个 HCI 帧的壳子,但它的命令语义和常用的连接管理 HCI 命令完全不是一回事,它属于测试模式专用命令,不参与协议状态机。

1.2 用 DTM 到底解决了什么

我在做蓝牙模块量产时,最头疼的不是射频指标本身,而是协议栈带来的不确定性。普通 HCI 命令控制蓝牙芯片发数据,系统要跑完广播、扫描、连接、加密、重传、跳频这一整套流程,任何环节有波动,测试结果就千奇百怪。比如同一块板子,上午测功率 -2dBm,下午变成 -5dBm,查了半天发现是对面工位的 WiFi 干扰了某个跳频频点。

DTM 把这种不可控性直接砍掉。它关闭跳频、关闭重传、关闭协议状态机,DUT 就像一台固定频率、固定速率、固定功率的“信号发生器”或“接收机”。这对认证测试特别重要,蓝牙射频一致性测试(RF PHY Conformance)明确要求使用 DTM 流程,因为只有这样才能确保每一台被测设备处于完全相同的物理状态。

产线效率是另一个关键原因。用 HCI 建连测试,每个 DUT 要额外花几百毫秒甚至几秒去握手、配对。而 DTM 命令可以在几十毫秒内切换信道和 PHY,测试脚本一秒钟能跑好几个用例,这对动辄几千片模组的产线来说,节省的时间非常可观。

对比维度HCI / ACI 路径DTM 路径
控制内容建连、扫描、数据收发 / 厂商私有射频配置固定的发射/接收测试参数
协议栈依赖完整协议栈或厂商驱动不需要协议栈
测试可重复性受跳频、重传影响,波动大高,状态固定
产测速度慢,需要连接流程快,直接切信道
适用场景功能测试、协议测试射频认证、产线射频测试

2. DTM 命令体系与核心参数拆解

2.1 标准 DTM 命令家族

蓝牙规范里,DTM 的核心命令其实就三条:发射测试(Transmit Test)、接收测试(Receive Test)、测试结束(Test End)。很多人以为 DTM 很复杂,是厂商一大堆私有命令,实际上底层标准很收敛,复杂的是参数组合。

发射测试命令的核心参数包括:发射信道、PHY 类型、测试数据包长度、数据包负载模式。信道号直接决定中心频率,例如 BLE 信道 0 对应 2402 MHz,信道 n 对应 2402 + 2n MHz。PHY 类型在 BLE 5.x 里可以是 1M、2M、Coded S=8、Coded S=2,这个参数决定调制速率和覆盖能力。测试数据包长度用于模拟不同负载下的射频信号,一般产测用 37 字节或者 255 字节都比较常见。

数据包负载模式很多人会忽略,它其实是往发射数据里填什么样的比特流。标准里定义了多种模式,比如 PRBS9 伪随机序列、连续 11110000、连续 10101010 等。我最常用的是 PRBS9,因为伪随机序列会让信号频谱更接近真实数据,功率测量、频谱模板测试都更有参考性。如果填连续 0 或连续 1,频谱会变成一根很纯的单音谱线,某些测试项反而不符合预期。

接收测试命令相对简单,核心参数是接收信道和 PHY。进入接收模式后,DUT 会在硬件层统计收到的有效数据包数量、CRC 错误等。测试结束后通过 Test End 命令让芯片回传收到的包数量,上位机再用“发送包数 - 接收包数”算出丢包率 PER(Packet Error Rate),这就是接收灵敏度的核心指标。

2.2 一个 DTM 命令帧到底长什么样

以最典型的 LE 发射测试为例,命令的完整逻辑其实包含三部分:操作码、参数长度、参数内容。操作码会告诉芯片“这是一条 DTM 测试命令”,参数长度告诉芯片“后面还有几个字节要读”,参数内容就是信道、PHY 这些具体配置。

通用实现中,LE Transmit Test 的操作码是 0x201B,LE Receive Test 操作码是 0x201D,LE Test End 操作码是 0x201F。传输到芯片时按小端顺序发送,所以 0x201B 会变成1B 20两个字节。

字段取值示例含义
操作码1B 20LE Transmit Test
参数长度04后面跟 4 个字节
TX 信道00信道 0,即 2402 MHz
数据长度2537 字节测试包
数据负载模式00PRBS9
PHY011M PHY

发送的时候,很多芯片还会在命令前后加一层私有的帧头、帧尾或者校验字段。比如国内几家蓝牙 SoC 厂商,会在标准 DTM 命令前加一个短的同步头,后加 CRC。所以如果你直接用公版命令发过去没反应,不要急着怀疑命令不对,先看厂商文档里有没有封装要求。

2.3 控制通道不一定要走 HCI / ACI

这里必须解释一个容易杠的点:DTM 命令在很多芯片上最终是通过 HCI 帧传下去的,那标题为什么说不走 HCI?因为 DTM 和 HCI 是不同层面的东西。DTM 是测试语义,HCI 是传输容器。你如果使用完整的 HCI 协议栈去发扫描、建连命令,那才叫“用 HCI 控制”;而只发几条 DTM 测试命令,不启动协议栈,那它本质上是“用 DTM 命令控制”。

ACI 就更特殊了。WiFi 芯片产测时,很多工程师习惯用厂商 ACI 工具去下发射频指令,比如调 TX 功率、切天线、配置带宽。这些工具确实好用,但坑在于 ACI 命令完全私有化。同一个 WiFi 芯片,换了新版本 SDK,部分命令可能不兼容;换了芯片厂商,以前写的脚本全部作废。而 DTM 因为面向蓝牙标准化测试,规则更稳定,至少蓝牙侧的命令语义在协议版本之间基本可以沿用。所以如果你的 Wi-Fi 芯片支持蓝牙共存或者 Combo 测试模式,优先把 DTM 流程跑通,会比依赖 ACI 更稳。

3. 实操:从零跑通一个 DTM 射频测试

3.1 前期准备

先准备一套最小测试环境。DUT 方面,需要一块可以烧录测试固件的开发板,注意这里一定要烧 DTM 测试固件,不是正常的应用固件。很多芯片原厂都会提供单独的 DTM 固件,比如 Nordic 的 nRF Connect Desktop 里就有 DTM 相关工具,TI 的 SmartRF Studio 也可以生成测试固件。烧录 DTM 固件的目的是绕开操作系统和蓝牙协议栈,让芯片上电后进入纯测试状态。

连接方面,我习惯用 USB-UART 模块,接到芯片 UART 测试口。电平要注意,有些开发板是 3.3V IO,有些是 1.8V,最好直接确认原理图,不要乱接。波特率通常选 115200、8N1,关闭流控。如果芯片有测试模式选择引脚,上电时要拉高或拉低,具体以 datasheet 上电时序图为准。

射频输出口要用质量好的同轴线连到频谱仪或者综测仪。如果环境有干扰,强烈建议把 DUT 放进屏蔽盒,尤其是做 RX 灵敏度测试时,屏蔽盒能挡掉大部分环境杂波。

3.2 进入 DTM 模式

上电后先别急着发发射命令。我第一件事永远是先发一条 Test End 命令,把芯片内部可能有残留的测试状态清干净。类似“关门之前先反锁一下”,避免上次测试未正常退出导致状态机卡死。

Test End 命令格式很简单,通用实现是1F 20 00,其中 1F 20 是操作码,00 是参数长度。如果返回一个 HCI Command Complete 事件,并且 Status 为 0,说明 DTM 环境正常。然后就可以发 LE Transmit Test 命令了。

下面是一个用 Python 和 pySerial 发 DTM 命令的最小示例,适合产线自动化脚本快速验证:

import serial import time ser = serial.Serial('COM10', 115200, timeout=0.5) # 1. 先发送 Test End,清空状态 test_end = bytes.fromhex('1F 20 00') ser.write(test_end) time.sleep(0.05) print("Test End response:", ser.read(255).hex()) # 2. 进入 TX 测试:信道0,包长37,PRBS9,1M PHY # 参数: 00 25 00 01 le_tx = bytes.fromhex('1B 20 04 00 25 00 01') ser.write(le_tx) time.sleep(0.05) resp = ser.read(255) print("TX start response:", resp.hex())

需要注意的是,这个示例是基于标准 HCI 事件帧的通用实现,部分芯片会把响应帧加一层私有头。如果你用原厂工具能收到回复,但脚本收不到,多半就是私有封装的问题。

3.3 跑通 TX 连续波测试

命令发出去以后,芯片应该会在指定信道持续发射。这时候在频谱仪上应该能看到以 2402 MHz 为中心的一根谱线,带宽和 PHY 有关。如果频谱仪显示“无信号”,先不要查命令,先查射频线缆、接头和板子天线匹配。我做产测时经常遇到这种情况,最后发现是 SMA 转接线断了。

功率测试要等信号稳定一点再采样。芯片从收到命令到 PLL 锁定、PA 完全建立,通常需要几十毫秒。脚本里发完命令后延时 50 到 100ms,再去用频谱仪读取峰值功率,否则第一次采样可能偏小。

DTM 命令本身通常不带功率参数。发射功率主要由芯片内部 PA 配置决定,你在 DTM 模式下测到的是默认功率,一般接近最大发射功率。如果你需要测不同功率档位下的指标,那就得配合厂商的私有校准命令去写功率等级。这种情况下,还是会把厂商命令和 DTM 命令混合使用,但需要注意先后顺序,先写功率,再启动 DTM 发射。

3.4 跑通 RX 灵敏度测试

接收测试要比发射测试稍微绕一点。DUT 进入 Receive Test 模式后,只负责接收和统计,不会主动发包。这时候需要另一个设备帮它发数据包,可以是综测仪,也可以是另一块支持 DTM 发射的开发板。

在综测仪上设置好信道、PHY、包长和发包数量,比如发 1000 包。DUT 侧执行 LE Receive Test,等发包结束,再发 Test End 命令,让 DUT 返回它收到的包数量。PER 就是 (1000 - 收到包数) / 1000。

用 Python 读取 Test End 响应里的统计数据时,注意解析偏移。标准 HCI Command Complete 事件里,状态字节之后才是两个字节的 Num Packets。片段示例:

test_end = bytes.fromhex('1F 20 00') ser.write(test_end) time.sleep(0.05) resp = ser.read(255) if len(resp) >= 8: status = resp[5] num_packets = int.from_bytes(resp[6:8], 'little') print(f"status={status}, received_packets={num_packets}")

如果你的测试固件带私有帧头,这个 offset 要跟着调整。最稳妥的方法是先抓一份“已知状态”的响应,手动数一下哪个字节是状态。

3.5 自动化产测流程参考

一条完整的 DTM 产测流程可以写成固定序列:上电 -> 复位 Test End -> TX 测试 -> 频谱功率/频率检测 -> Test End -> RX 测试 -> 读取 PER -> Test End -> 断电判定。每项测试都设独立超时,避免一个用例卡死拖住整线。

测试项参数示例合格阈值参考
发射功率信道 0,1M,PRBS9≥ -2 dBm
中心频率误差信道 0≤ ±50 kHz
接收 PER信道 0,1M,发送 1000 包≤ 1%
2M PHY 发射信道 0,2M指标不同平台差异大

4. 常见问题与排查技巧实录

4.1 DTM 命令发送后无回复

这是新手问得最多的问题。第一反应先查最基础的三件事:UART 接线有没有接反、波特率是否匹配、开发板是否真的进入了 DTM 模式。我见过有人把 DTM 固件烧进去以后,测试引脚没拉对,芯片一直跑在正常启动流程里,发任何 DTM 命令都没反应。

第二件事是检查命令格式。不同芯片厂商对 DTM 命令封装不同,有的厂商要求每个命令前加两个字节帧头,有些还要在命令末尾加 CRC 校验。你拿标准命令发过去,芯片可能不识别,甚至不回包。这种情况下,用原厂工具抓一份正常通信的串口日志,对比一下自己的命令,是最快的排查方式。

第三件容易忽略的是 DTM 状态机。如果上一次测试没有正确退出,芯片可能还卡在 RX 或 TX 状态,不会响应新的命令。发送任何命令前,先发 Test End 并把返回值打印出来,能省很多时间。

4.2 测试功率或频率漂移

如果发射测试功率忽高忽低,先检查供电。芯片在发射时电流通常比较大,如果开发板用的是 USB 供电,USB 口输出能力不足会导致功率波动。换独立稳压电源后,指标往往会立刻稳定。频率漂移则优先检查晶振。BLE 对晶振精度要求较高,如果板子是低成本陶振,温度一高频率就跑偏,这时候看频谱仪的中心频率偏了多少。

线缆损耗也要提前标定。我遇到过一块板子功率测试比标称低 1.8dB,折腾半天才发现同轴线缆在 2.4GHz 频段插损有 2 个 dB,校准之后所有数据都正常了。做产测前先用功率计或者综测仪校准整个射频链路,记录补偿值。

4.3 DTM 和 HCI / ACI 命令混用

“混用”是产测脚本最容易出的隐性 bug。比如脚本一开始用厂商 ACI 命令关闭了天线,切换到 DTM 模式后没有重新打开天线,那发射功率就会异常偏低。再比如在 DTM 模式下用普通 HCI 命令去查询设备地址,某些芯片会退出测试模式,或者直接返回错误。

我的经验是,测试脚本里必须严格区分控制通道。DTM 命令只走 DTM 命令解析函数,厂商私有命令只走厂商配置函数,千万不要共用一个 write 函数。每次从 DTM 切到 ACI 配置之前,先发 Test End;从 ACI 配置切回 DTM 之前,再发一次 Test End。这个“双重保险”看起来冗余,但能避免大量诡异问题。

4.4 WiFi 芯片 ACI 测试与 DTM 的关系

做 WiFi 芯片的朋友看到 DTM 可能会疑惑:我们平时测试不都用 ACI 工具吗?没错,WiFi 芯片射频测试中,ACI 是厂商最常用的控制路径,尤其用来配置信道、带宽、MCS、发射功率这些参数。但是如果项目要求“控制时不依赖 HCI / ACI”,比如你在定制一套统测框架,不希望被厂商驱动版本带偏,就需要确认芯片有没有类似 DTM 的 RF Test Mode。

很多 Combo 芯片在 WiFi 侧会提供一套私有的 RF 测试命令,功能和 DTM 类似,但不叫 DTM,有的叫 RF Test Mode,有的叫 Continuous TX Mode。查阅芯片手册时重点看“Direct Test Mode”或者“RF Test Mode”关键词。如果芯片只支持 ACI 配置,没有底层测试命令,那就不能硬套 DTM 流程,这时候老老实实用 ACI 工具做校准,再用 DTM 做蓝牙侧的统一验证,才是合理的方案。

5. 工具选型建议与 DTM 速查

5.1 用什么工具发 DTM 命令

最简单的方案是直接使用厂商提供的 DTM 测试工具。Nordic 有 DTM 固件配合 nRF Connect Desktop,TI 有 SmartRF Studio,这些工具可以在开发阶段快速验证射频指标。但这类工具通常只面向单板测试,不适合产线自动化。

产线阶段我更建议自己写一套基于串口的 DTM 控制脚本,原因很简单:厂商工具没法跟你的 MES 系统、数据库、测试治具联动。Python 的 pySerial 足够应对大部分场景,关键是把命令封装成函数,把测试项做成配置文件。

如果测试量更大,直接用综测仪是最稳的。R&S CMW270、Anritsu MT8852B 这类设备内置 DTM 控制器,可以自动完成发射、接收、PER 统计,还带校准功能。劣势是设备贵,产线初投成本高,但大厂产线几乎都走这条路。

工具适用阶段优点缺点
原厂 DTM 工具研发验证上手快,命令封装完整不适合产线自动化
自写串口脚本产线调试灵活,可集成需要处理私有协议
综测仪量产/认证指标权威,自动化完善设备成本高

5.2 通用 DTM 命令速查表

功能命令关键参数
测试结束Test End
发射测试LE Transmit Test信道、包长、负载模式、PHY
接收测试LE Receive Test信道、PHY
结果返回Command Complete状态、接收包数量

最后再分享一个小技巧:产测脚本里每次切换信道之前,先发一条 Test End,再发新的 TX/RX 命令。这个习惯让我少踩了很多莫名其妙的坑。DTM 之所以好用,就是因为它把射频测试变得足够“干净”,干净的命令、干净的状态、干净的结果。不要一上来就搭协议栈,先把 DTM 跑通,把射频指标摸清楚,再去碰 HCI 和 ACI,会顺手得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询