CN / EN
CN / EN

写技术文章

技术分享 | BLE无广播问题分析思路及案例分享

Ping

汇顶员工
2024-02-05 11:17:08

BLE广播就是周期性的向空中发送特定的数据包,以便其它设备能够发现广播设备的存在。以t为广播间隔,每发送一次广播就称为一个广播事件。按照蓝牙Spec,广播有37、38、39三个射频信道,所以一个广播事件是在三个信道上分别发送一个广播包。

一、BLE无广播现象

设备运行过程中, 在应该有广播的场景下无法扫描到广播, 且设备没有出现卡死或 hardfault 问题。

二、问题分析思路及解决方案

1. 分析设备的RF是否有异常,通过DTM固件和对应工具测试TX信号— GR551x系列芯片DTM测试参考指导指南

2. 确认 ble_gap_adv_start() 是否有调用,如果是没有调用开广播函数,则检查并完善代码逻辑。

3. 确认 ble_gap_adv_start() 的返回值是否为 0 ,当返回值不为 0 时, 根据错误信息进一步获取错误原因。如果是参数错误, 则按规则修改参数; 如果是 0x000F 错误, 则等当前广播关闭后再开启新的广播。

API 错误码 说明
ble_gap_adv_start0x0025原因分析:开启支持扫描的扩展广播, 但没有设置扫描响应数据时, 返回该错误。
解决方法: 使用 ble_gap_adv_data_set() 设置扫描响应数据。
0x0026原因分析:无效的 duration 参数
1. 开启GAP_ADV_TYPE_ADV_HIGH_DIRECT_IND 广播, 但 duration 参数设置不合理时, 返回该错误;
2. disc_mode 设置为GAP_DISC_MODE_LIM_DISCOVERABLE , 但duration 设置为 0 时, 返回该错误;
解决方法:
1. 开启GAP_ADV_TYPE_ADV_HIGH_DIRECT_IND 广播时, 设置合理的 duration 参数, 取值范围 0 <duration <= 1.28S ;
2. 当 disc_mode 设置为GAP_DISC_MODE_LIM_DISCOVERABLE 时,duration 设置不为 0;
0x000F原因分析:非法操作
1. 在当前广播已开启的情况下, 再次调用开广播函数时, 返回该错误;
2. 连续调用 ble_gap_adv_stop()和ble_gap_adv_start()。 协议栈是异步的, 调用
ble_gap_adv_stop() 并不会立即关闭广播, 此时调用ble_gap_adv_start() 会返回 0x000F 错误码。

4. 确认 app_gap_adv_start_cb() 中 status 是否为 0,当 status 不为 0 时, 根据错误信息进一步获取错误原因。如果是参数错误, 则按规则修改参数; 如果是其它错误, 则可以调用 ble_gap_adv_start() 重新开启广播。

API 错误码 说明
app_gap_adv_start_cb0x4A原因分析:app_gap_adv_start_cb() 回调中的参数 status 为 0x4A时, 表示广播参数或数据异常。异常情况可能是以下两种情况:
1. 当 disc_mode 设置为GAP_DISC_MODE_LIM_DISCOVERABLE 时, 广播数据中flags 数据应设置为 0x02 0x01 0x05;
2. 当 disc_mode 设置为GAP_DISC_MODE_GEN_DISCOVERABLE 时, 广播数据中 flags 数据应设置为 0x02 0x01 0x06;

三、案例分析

1. 如何开启两个MAC地址不同的广播

连续开启两个广播的函数调用逻辑如下,按该流程执行后虽然能够开启两个广播, 但两个广播的 MAC 地址是一样的, 为第二次调用 ble_gap_addr_set()设置的地址。

以V2.0.1版本SDK为例,正确开启两个MAC地址不同的广播流程如下:开启第一个广播, 等待第一个广播开启成功, 再开启第二个广播。

2. 重启广播0x000F错误案例

当需要停止当前广播, 重新开启新的广播时, 一般函数调用逻辑如下:调用ble_gap_adv_stop()停止广播 -> 设置广播参数 -> 调用ble_gap_adv_start() 重启广播。使用该逻辑时, ble_gap_adv_start() 会有概率返回 0x000F 错误, 这是因为协议栈是异步的 ,调 用 ble_gap_adv_stop() 并不会立即关闭广播 ,此时调用ble_gap_adv_start() 会返回 0x000F 错误码。

可以参考如下方法封装停止广播函数, 确保函数退出后广播被停止:

uint8_t s_is_adv_exc_cplt;
uint8_t s_adv_index;
// 广播停止回调
static void app_gap_adv_stop_cb(uint8_t inst_idx, uint8_t status,
gap_stopped_reason_t reason)
{
    if (GAP_STOPPED_REASON_ON_USER == reason && BLE_SUCCESS == status && \
    inst_idx == s_adv_index)
    {
        s_is_adv_exc_cplt = 1;
    }
} 

// 封装停止广播函数,退出该函数后, 广播已经被停止
uint16_t user_adv_stop(uint8_t index)
{
    sdk_err_t error_code;
    extern void ble_task_force_schedule(void);
    s_is_adv_exc_cplt = 0;
    error_code = ble_gap_adv_stop(index);
    if (error_code == SDK_SUCCESS)
    {
        s_adv_index = index;
        while(!s_is_adv_exc_cplt)
       {
           ble_task_force_schedule();
       }
    } 
    return error_code;
}


0收藏

0赞成

您的评论
我们时刻倾听您的声音
联系销售

扫描关注公众号

打开微信,使用“扫一扫”即可关注