LE DTM

DTM 用于控制 DUT,并向 Tester 提供测试报告。

概述

Direct Test Mode 用于测试低功耗蓝牙设备的 RF PHY 层。 DTM 可以通过两种方式设置:基于 HCI 或者通过一个 2-wire UART 接口。

在本文档中, DTM 通过第二种方式设置,即通过一个 2-wire UART 接口。其测试框架如图所示:

../../../../../_images/dtm_test_framework.png

使用 2-wire UART interface 的测试框架

  1. DUT 运行 DTM 应用,测试设备 MT8852B 向 DUT 发送 DTM 命令。

  2. DTM 应用分析收到的命令并调用相应接口以向 MT8852B 发送数据包 (transmitter test) 或从 MT8852B 接收数据包 (receiver test)。

  3. DTM 应用收集测试结果,并通过 DTM 事件发送给 MT8852B。

  4. MT8852B 根据 DTM 事件判断并显示测试结果。

发射测试

../../../../../_images/dtm_transmiter_test.png

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 输出的调制特性。

接收测试

../../../../../_images/dtm_receiver_test.png

Receiver Test 消息序列图

Upper tester 向 DUT 发送命令,使 DUT 准备接收 lower tester 发送的测试数据包。lower tester 发送测试数据包给 DUT,接收流程结束后,DUT 向 upper tester 回报事件。

  • 灵敏度测试

    在向 DUT 发送测试控制信息后,MT8852B 向 DUT 发送 LE 相关数据包。DUT 统计收到数据包的数目,MT8852B 通过 2-wire 接口读取该参数。

  • 接收完整度测试

    采用 -30 dBm 发射功率和 PRBS 9 payload,MT8852B 向 DUT 随机发送偶数个 LE 相关数据包。这些数据包的 CRC 为有效值或无效值。DUT 记录接收数据包的数目,MT8852B 通过 2-Wire 接口读取该参数以计算 FER。该测试将在选择的频率上重复三次。

  • 最大输入功率测试

    在向 DUT 发送测试控制信息后,MT8852B 以 -10 dBm 发射功率向 DUT 发送 LE 相关数据包。DUT 记录接收数据包的数目,MT8852B 通过 2-Wire 接口读取该参数。

环境要求

该 sample 工程可以在以下开发板上运行:

环境要求

Hardware Platforms

Board Name

RTL87x2G HDK

RTL87x2G EVB

为快速搭建起开发环境,可参考 快速入门 中提供的详细指导。

硬件连线

请参考 快速入门 中的 EVB 接口和模块 章节。

编译和下载

该示例可以在 SDK 文件夹中找到:

Project file: samples\bluetooth\dtm\proj\rtl87x2g\mdk

Project file: samples\bluetooth\dtm\proj\rtl87x2g\gcc

编译和运行该示例请遵循以下步骤:

  1. 打开项目文件。

  2. 要编译目标文件, 请参考 快速入门 中的 编译 APP Image

  3. 编译成功后,目录 samples\bluetooth\dtm\proj\rtl87x2g\mdk\bin 下会生成 APP bin 文件 app_MP_sdk_xxx.bin

  4. 要下载 APP bin 到 EVB,请参考 快速入门MP Tool 章节列出的步骤。

  5. 在 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
../../../../../_images/dtm_mt8852b_uart.png

MT8852B 的 UART

../../../../../_images/dut_uart.png

DUT 的 UART

测试步骤

配置 DUT 和 MT8852B

如图所示,按 On/Standby 按钮以启动 MT8852B,然后按 EUT addr 按钮修改 EUT address。

../../../../../_images/dtm_mt8852b_init.png

启动 MT8852B

先按 Sel 按钮,然后选择 BLE2WIRE 作为 Source。

../../../../../_images/dtm_eut_address.png

选择 EUT address 中的 Source

Setup 按钮设置 Low energy 脚本。

../../../../../_images/dtm_low_energy.png

设置 Low energy 脚本

运行 MT8852B

根据测试用例运行 MT8852B。

  • 运行所有测试用例

    Run 按钮运行所有测试用例。

../../../../../_images/dtm_test_scripts.png

运行所有测试用例

  • 运行单个测试用例

    选择需要测试的用例,然后按 Single 按钮和 Run 按钮运行单个测试用例。

../../../../../_images/dtm_test_single_script.png

运行单个测试用例

测试结果

Pass 的测试结果如图所示,已经 Pass 的测试用例后面会显示字母 P

../../../../../_images/dtm_test_result.png

DTM 测试结果

代码介绍

本章将按照以下几个部分进行介绍:

源码路径

  • 工程目录: samples\bluetooth\dtm\proj

  • 源码目录: samples\bluetooth\dtm\src

dtm 工程中的源文件当前被分为几个组,如下所示:

└── Project: dtm
    └── 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,更多信息可参阅文档 Host Image 中的章节 GAP LIB的使用方法

Bluetooth Host 介绍

示例工程默认使用 Bluetooth Host image 版本 bt_host_0_0,更多信息可参阅 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 参数。

更多关于 LE GAP 初始化和启动流程的信息可查阅 LE Host 中的章节 GAP 参数的初始化

主要函数

dtm_app.c 文件中,UART0_Handler() 接收来自 MT8852B 的命令。示例代码如下:

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() 处理来自 MT8852B 的测试命令,调用 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() 向 MT8852B 发送事件。示例代码如下:

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;
}