如何实现BLE 最大数据吞吐率并满足设计功耗要求?

我们开发的BLE 设备多数都有两点要求:一是低功耗,电池供电需要持续工作数周甚至数个月;二是将BLE peripheral产生的数据快速传送给central,传输数据功耗较高,提高传输速率缩短传输时间也有利于降低平均功耗。我们该如何设置广播参数与连接参数以达到我们要求的功耗呢?该如何设置连接参数与报文长度(PDU / MTU)以尽可能达到最大传输速率呢?

一、如何提高BLE 数据传输速率?

BLE 数据传输相关的服务中有一个比较基础的串口透传服务,本文以nRF5_SDK_17.0.2 中的ble_app_uart 工程为例,展示如何提高BLE 的数据传输速率。

在尝试提高BLE 数据传输速率前,需要先获得两个信息:

  1. 当前使用的BLE 协议栈支持的理论最大数据吞吐率是多少?
  2. 如何获知当前的BLE 数据传输速率是多少?

1.1 Nordic BLE 最大数据吞吐率是多少?

对于第一个问题,我们可以从Nordic 协议栈规格说明书中获知,比如使用s132 softdevice 可以参考文档:S132 SoftDevice SoftDevice Specification v7.1,查阅Bluetooth Low Energy data throughput 章节,数据传输速率使用下面的公式:

#define OPCODE_LENGTH        1
#define HANDLE_LENGTH        2

Throughput_bps = num_packets * (ATT_MTU - OPCODE_LENGTH - HANDLE_LENGTH) * 8 / seconds

这里统计的传输数据指的是应用数据,ATT_MTU 减去Attribute protocol PDU Opcode 和Attribute Handle 字段长度,剩下的就是Attribute Value 字段(也即有效的应用数据)。每个字节占8 比特,下表中的传输速率单位是kbps(如果要换算成 KB/s 需要除以8),下表Connection interval 与Connection Event Length 相等:
S132 softdevice data throughput
从上表可知,跟传输速率相关的因素主要有ATT MTU size、Connection interval、Connection Event Length、Communication Mode、LE PHY speed 等。比如ATT MTU size 为23、Connection interval 与Connection Event Length 取7.5 ms、Communication Mode 为Send Notification、LE 1M PHY 的最大速率为24 KB/s;ATT MTU size 为247、Connection interval 与Connection Event Length 取50 ms、Communication Mode 为Send Notification、LE 2M PHY 的最大速率为165.94 KB/s。

1.2 如何获知BLE 当前数据吞吐率?

一般BLE peripheral 作为GATT Server 向BLE central 也即GATT Client 传输数据,想获得BLE 当前的数据吞吐率,一般有三种方式:

  1. BLE peripheral 端统计单位时间内发送出去的数据量;
  2. BLE central 端统计单位时间内接收到的数据量;
  3. BLE sniffer 抓取单位时间内传输的报文中有效数据量。

Nordic 手机端的应用并没有提供显示当前数据吞吐率的功能,我们开发GATT Server 应用再去修改BLE central 代码比较麻烦。BLE sniffer 抓包分析倒是比较方便,wireshark + nRF sniffer 抓包方案容易丢包也没有直接统计数据吞吐率指标,专业的蓝牙分析仪Ellisys Bluetooth Explorer 倒是可以直接统计数据吞吐率,蓝牙分析仪成本太高。因此,本文选择第一种方案,在BLE peripheral 代码中添加统计数据发送量的功能,并通过RTT Log 打印出来。

我们在.\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart 示例工程的基础上添加统计单位时间内数据发送量的代码,Nordic UART Service 我们在博文:如何实现扫码连接BLE 设备的功能? 中已经介绍过了,二者主要的代码逻辑差不多,主要有两点不同:

  • ble_app_uart 工程在GAP 阶段作为Advertiser,在函数advertising_init 中初始化广播包内容、广播间隔、广播超时时间等,然后在函数advertising_start 中开始广播;ble_app_uart_c 工程在GAP 阶段作为Scanner 和Initiator,在函数scan_init 中设置扫描过滤条件、注册scan_evt_handler 等,然后在函数scan_start 中开始扫描周围的广播设备;
  • ble_app_uart 工程在GATT 阶段作为GATT Server,在函数services_init --> ble_nus_init 中添加NUS service(包括RX Characteristic、TX Characteristic)、注册nus_data_handler 等,其中NUS 为Primary Service 对外提供串口透传服务;ble_app_uart_c 工程在GATT 阶段作为GATT Client,在函数db_discovery_init 和nus_c_init 中发现对端设备提供了哪些services(特别是NUS 服务)、注册db_disc_handler 和ble_nus_c_evt_handler 等,发现NUS 服务后就可以访问该服务了。

本文就不展开介绍ble_app_uart 工程代码逻辑了,我们重点关心的是GATT Server 如何使用NUS 服务向GATT Client 发送数据。从函数uart_event_handle 代码可以看出,使用函数ble_nus_data_send 可以通过NUS 服务向对端设备发送数据,该函数的声明如下:

// .\nRF5_SDK_17.0.2_d674dde\components\ble\ble_services\ble_nus\ble_nus.h

/**@brief   Function for sending a data to the peer.
 *
 * @details This function sends the input string as an RX characteristic notification to the
 *          peer.
 *
 * @param[in]     p_nus       Pointer to the Nordic UART Service structure.
 * @param[in]     p_data      String to be sent.
 * @param[in,out] p_length    Pointer Length of the string. Amount of sent bytes.
 * @param[in]     conn_handle Connection Handle of the destination client.
 *
 * @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.
 */
uint32_t ble_nus_data_send(ble_nus_t * p_nus,
                           uint8_t   * p_data,
                           uint16_t  * p_length,
                           uint16_t    conn_handle);

既然是统计单位时间内GATT Server 发送出去的数据量,自然需要一个定时器资源,我们选用低功耗的app_timer。为了提高数据发送速率,我们选择Send Notification 模式。为了少做无用功,我们在NUS Notification enable 的情况下再开始发送数据,当连接断开后便停止发送数据。新增用于统计BLE data throughput 的代码如下:

// .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c

/**@brief Resources related to throughput testing.
 */
#define DATA_THROUGHPUT_INTERVAL            APP_TIMER_TICKS(5)                   /**< data throughput interval (ticks). */
APP_TIMER_DEF(m_timer_throughput_id);

uint32_t m_data_sent_length = 0;
uint8_t m_data_array[BLE_NUS_MAX_DATA_LEN] = {
   0};

/**@brief Data generation timer timeout handler function.
 */
static void data_throughput_timeout_handler(void * p_context)
{
   
    UNUSED_PARAMETER(p_context);
    
    static uint32_t timeout_count = 0;
    ret_code_t err_code;
    
    timeout_count++;

    do
    {
   
        uint16_t length = BLE_NUS_MAX_DATA_LEN;
        err_code = ble_nus_data_send(&m_nus, m_data_array, &length, m_conn_handle);
        if ((err_code != NRF_ERROR_INVALID_STATE) &&
            (err_code != NRF_ERROR_RESOURCES) &&
            (err_code != NRF_ERROR_NOT_FOUND))
        {
   
            APP_ERROR_CHECK(err_code);
        }

        if(err_code == NRF_SUCCESS)
        {
   
            m_data_sent_length += length;
            m_data_array[0]++;
            m_data_array[length-1]++;
        }
    } while (err_code == NRF_SUCCESS);

    // Timer interval 5 ms, when the timer reaches 1 second 
    if(timeout_count == 200)
    {
   
        // Send m_data_sent_length bytes of data within 1 second, which is equal to m_data_sent_length * 8 / 1024 kilobits of data
        NRF_LOG_INFO("****** BLE data throughput: %d kbps ******", m_data_sent_length >> 7);
        m_data_sent_length = 0;
        timeout_count = 0;
    }
}

/**@brief Function for initializing the timer module.
 */
static void timers_init(void)
{
   
    ......
    // Create a data generation timer for testing throughput.
    err_code = app_timer_create(&m_timer_throughput_id, 
                                APP_TIMER_MODE_REPEATED, 
                                data_throughput_timeout_handler);
    APP_ERROR_CHECK(err_code);
}

/**@brief Function for handling the data from the Nordic UART Service.
 */
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流云IoT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值