LE DTM
概述
Direct Test Mode用于测试低功耗蓝牙设备的 RF PHY 层。 DTM可以通过两种方式设置:基于 HCI 或者通过一个 2-wire UART 接口。
在本文档中, DTM通过第二种方式设置,即通过一个2-wire UART接口。其测试框架如图所示:
DUT运行DTM应用,测试设备MT8852B向DUT发送DTM命令。
DTM应用分析收到的命令并调用相应接口以向MT8852B发送数据包(transmitter test)或从MT8852B接收数据包(receiver test)。
DTM应用收集测试结果,并通过DTM事件发送给MT8852B。
MT8852B根据DTM事件判断并显示测试结果。
Transmitter Test
Upper tester向DUT发送命令,使DUT发送测试数据包给lower tester。发送流程结束后,DUT会向upper tester回报事件。
- 输出功率测试
MT8852B通过RS232、USB 或2-Wire接口发送测试控制信息,以指导DUT发送相应测试数据包。MT8852B至少在20%~80%的burst持续时间内测量接收数据包的平均功率。
- 载波 & 漂移测试
基于接收数据包的长度,载波漂移测试执行频率漂移测量。以与基本速率初始载波测试同样的方式测量载波频率偏移,只针对low energy相关数据包的8位前同步码。
- 调制指数测试
针对选择的频率范围(LOW、MEDIUM和HIGH),该测试测量DUT输出的调制特性。
Receiver Test
Upper tester向DUT发送命令,使DUT准备接收lower tester发送的测试数据包。lower tester发送测试数据包给DUT,接收流程结束后,DUT向upper tester回报事件。
- 灵敏度测试
在向DUT发送测试控制信息后,MT8852B向DUT发送 LE 相关数据包。DUT统计收到数据包的数目,MT8852B通过2-Wire接口读取该参数。
- 最大输入功率测试
在向DUT发送测试控制信息后,MT8852B以-10 dBm发射功率向DUT发送LE相关数据包。DUT记录接收数据包的数目,MT8852B通过2-Wire接口读取该参数。
环境要求
该sample工程可以在以下开发板上运行:
Hardware Platforms |
Board Name |
---|---|
RTL87x2G HDK |
RTL87x2G EVB |
为快速搭建起开发环境,可参考 快速入门 中提供的详细指导。
硬件连线
编译和下载
该示例可以在SDK文件夹中找到:
Project file: samples\bluetooth\dtm\proj\rtl87x2g\mdk
Project file: samples\bluetooth\dtm\proj\rtl87x2g\gcc
编译和运行该示例请遵循以下步骤:
打开项目文件。
要编译目标文件, 请参考 快速入门 中的 编译APP Image。
编译成功后,目录
samples\bluetooth\dtm\proj\rtl87x2g\mdk\bin
下会生成app bin文件app_MP_sdk_xxx.bin
。要下载app bin到EVB,请参考 快速入门 中 MP Tool 下载 章节列出的步骤。
在EVB上按下 reset 按钮,工程将开始运行。
测试验证
本章节将对测试步骤和测试结果进行详细介绍。
准备步骤
下载DTM应用
编译和下载DTM应用到DUT。
连接DUT和MT8852B
第一步是使用RS232,通过2-wire UART连接DUT和MT8852B,DUT的TX引脚和RX引脚应与RS232的对应引脚相连。
DTM应用默认将 P3_1 设为Data UART的TX引脚,将 P3_0 设为Data UART的RX引脚。
#define DATA_UART_TX_PIN P3_1
#define DATA_UART_RX_PIN P3_0
测试步骤
配置DUT和MT8852B
如图所示, 按 On/Standby 按钮以启动MT8852B,然后按 EUT ADDR 按钮修改EUT address。
先按 Sel 按钮,然后选择 BLE2WIRE 作为Source。
按 Setup 按钮设置Low energy脚本。
运行MT8852B
根据测试用例运行MT8852B。
运行所有测试用例
按 Run 按钮运行所有测试用例。
运行单个测试用例
选择需要测试的用例,然后按 Single 按钮和 Run 按钮运行单个测试用例。
测试结果
Pass的测试结果如图所示,已经Pass的测试用例后面会显示字母 P。
代码介绍
本章将按照以下几个部分进行介绍:
源码路径 中介绍项目目录和源代码文件。
Bluetooth Host介绍 中介绍了Bluetooth Host相关信息。
章节 初始化 中介绍DTM参数和Bluetooth Host初始化。
章节 主要函数 中介绍DTM的函数。
章节 GAP回调函数处理 中介绍DTM的GAP回调函数处理。
源码路径
工程目录:
samples\bluetooth\dtm\proj
。源码目录:
samples\bluetooth\dtm\src
。
LE dtm工程中的源文件当前被分为几个组,如下所示:
└── Project: broadcast
└── secure_only_app
└── Device Includes startup code
├── CMSE Library Non-secure callable library
├── Lib Includes all binary symbol files that user application is built on.
├── ROM_NS.lib
└── lowerstack.lib
└── rtl87x2g_sdk.lib
└── gap_utils.lib
├── peripheral Includes all peripheral drivers and module code used by the application.
├── Profile Includes LE profiles or services used by the sample application.
└── APP Includes the ble_scatternet user application implementation.
├── data_uart.c
├── app_task.c Create message queue and application task.
├── dtm_app.c Handle commands from MT8852B and return with events.
└── main.c Entry of application, initialize parameters and register application message callback.
示例工程使用与 bt_host_0_0
匹配的默认GAP LIB,更多信息可参阅文档 Bluetooth Host Image 中的章节 GAP LIB的使用方法。
Bluetooth Host介绍
示例工程默认使用Bluetooth Host image版本 bt_host_0_0
,更多信息可参阅
Bluetooth Host Image。
关于Bluetooth Host所支持的蓝牙功能的详细信息,请参阅文件 bin\rtl87x2g\bt_host_image\bt_host_0_0\bt_host_config.h
。
初始化
当EVB启动并且芯片复位时, main()
函数将被调用,它执行以下初始化函数:
int main(void)
{
le_gap_init(0);
gap_lib_init();
app_le_gap_init();
application_task_init();
os_sched_start();
return 0;
}
le_gap_init()
用于初始化GAP并配置链接个数。app_le_gap_init()
用于初始化GAP参数。
主要函数
在 dtm_app.c
文件中, UART0_Handler()
接收来自8852B的命令。示例代码如下:
void UART0_Handler(void)
{
uint8_t uartdata[2] = {0, 0};
uint8_t *p = uartdata;
uint16_t command = 0;
uint32_t int_status = 0;
int_status = UART_GetIID(UART0);
UART_INTConfig(UART0, UART_INT_RD_AVA | UART_INT_LINE_STS, DISABLE);
switch (int_status)
{
case UART_INT_ID_TX_EMPTY:
break;
case UART_INT_ID_RX_LEVEL_REACH:
case UART_INT_ID_RX_TMEOUT:
while (UART_GetFlagState(UART0, UART_FLAG_RX_DATA_RDY) == SET)
{
UART_ReceiveData(UART0, p++, 1);
if (p - uartdata > 2)
{
break;
}
}
command = (uartdata[0] << 8) | uartdata[1];
APP_PRINT_INFO1("FORM 8852B: 0x%x", command);
dtm_test_req(command);
break;
case UART_INT_ID_LINE_STATUS:
break;
default:
break;
}
UART_INTConfig(UART0, UART_INT_RD_AVA, ENABLE);
return;
}
dtm_test_req()
处理来自8852B的测试命令,调用GAP层接口测试。示例代码如下:
void dtm_test_req(uint16_t command)
{
uint8_t contrl = 0;
uint8_t param = 0;
uint8_t tx_chann = 0;
uint8_t rx_chann = 0;
uint8_t data_len = 0;
uint8_t pkt_pl = 0;
uint8_t cmd = (command & 0xc000) >> 14;
uint16_t event = 0;
//the upper 2 bits of the data length for any Transmitter or Receiver commands following
static uint8_t up_2_bits = 0;
//physical to use
static uint8_t phy = 1;
//modulation index to use
static uint8_t mod_idx = 0;
//local supported features
static uint8_t lcl_feats[GAP_LE_SUPPORTED_FEATURES_LEN] = {0};
switch (cmd)
{
case 0:
contrl = (command & 0x3f00) >> 8;
param = (command & 0xfc) >> 2;
switch (contrl)
{
case 0:
if (param == 0)
{
up_2_bits = 0;
phy = 1;
mod_idx = 0;
}
else
{
event |= 1;
}
dtm_uart_send_bytes(event);
break;
......
case 5:
/*
MT8852B do not send these commands
0x00 Read supportedMaxTxOctets
0x01 Read supportedMaxTxTime
0x02 Read supportedMaxRxOctets
0x03 Read supportedMaxRxTime
*/
break;
default:
break;
}
APP_PRINT_INFO3("dtm_test_req: up_2_bits 0x%x, phy 0x%x, mod_idx 0x%x", up_2_bits, phy, mod_idx);
break;
......
}
}
dtm_uart_send_bytes()
向8852B发送事件。示例代码如下:
void dtm_uart_send_bytes(uint16_t event)
{
uint8_t uartdata[2] = {0};
uartdata[0] = (event & 0xff00) >> 8;
uartdata[1] = event & 0xff;
uint8_t *p_ch = uartdata;
uint8_t i = 0;
for (i = 0; i < 2; i++)
{
while (UART_GetFlagState(UART0, UART_FLAG_THR_EMPTY) != SET)
{
;
}
UART_SendData(UART0, p_ch++, 1);
}
}
GAP回调函数处理
app_gap_callback()
函数用于处理GAP回调函数消息。
更多关于GAP回调函数的信息可以查阅 LE Host 中的章节 Bluetooth LE GAP回调函数。
当测试开始时,GAP层使用 GAP_MSG_LE_DTM_ENHANCED_RECEIVER_TEST
或者 GAP_MSG_LE_DTM_ENHANCED_TRANSMITTER_TEST
消息来通知APP执行 Transmitter Test 或者 Receiver Test。示例代码如下:
T_APP_RESULT app_gap_callback(uint8_t cb_type, void *p_cb_data)
{
T_APP_RESULT result = APP_RESULT_SUCCESS;
T_LE_CB_DATA *p_data = (T_LE_CB_DATA *)p_cb_data;
uint16_t status = 0;
uint16_t event = 0;
APP_PRINT_INFO1("app_gap_callback: cb_type %d", cb_type);
switch (cb_type)
{
......
#if F_BT_LE_5_0_DTM_SUPPORT
case GAP_MSG_LE_DTM_ENHANCED_RECEIVER_TEST:
#endif
status = p_data->le_cause.cause;
if (status == 0)
{
APP_PRINT_INFO2("app_gap_callback: event 0x%x, status 0x%x", (event & 0x8000) >> 15, event & 0x1);
}
else
{
event |= 1;
APP_PRINT_INFO2("app_gap_callback: event 0x%x, status 0x%x", (event & 0x8000) >> 15, event & 0x1);
}
dtm_uart_send_bytes(event);
break;
......
#if F_BT_LE_5_0_DTM_SUPPORT
case GAP_MSG_LE_DTM_ENHANCED_TRANSMITTER_TEST:
#endif
status = p_data->le_cause.cause;
if (status == 0)
{
APP_PRINT_INFO2("app_gap_callback: event 0x%x, status 0x%x", (event & 0x8000) >> 15, event & 0x1);
}
else
{
event |= 1;
APP_PRINT_INFO2("app_gap_callback: event 0x%x, status 0x%x", (event & 0x8000) >> 15, event & 0x1);
}
dtm_uart_send_bytes(event);
break;
case GAP_MSG_LE_DTM_TEST_END:
status = p_data->p_le_dtm_test_end_rsp->cause;
if (status == 0)
{
event |= 1 << 15;
event |= p_data->p_le_dtm_test_end_rsp->num_pkts;
APP_PRINT_INFO2("app_gap_callback: event 0x%x, packet count 0x%x", (event & 0x8000) >> 15,
event & 0x7fff);
}
else
{
event |= 1;
APP_PRINT_INFO2("app_gap_callback: event 0x%x, status 0x%x", (event & 0x8000) >> 15, event & 0x1);
}
dtm_uart_send_bytes(event);
break;
}
return result;
}