蓝牙(BLE/BT)

FAQ1 设备连接手机后,手机界面出现鼠标箭头,如何修改

../../_images/index0.png

可以按如图修改


FAQ2 设备蓝牙名如何修改?

../../_images/index1.png ../../_images/index2.png

默认solution会先读取nvm信息设置蓝牙名,读取失败会用mac地址拼接一个蓝牙名,如果更改mac地址后,蓝牙名字未更改,需要先检查nvm信息是否有更新,特别地, 如果要用烧录工具烧写的BT NAME,需要先用接口rt_flash_config_read(FACTORY_CFG_ID_BTNAME, (uint8_t *)local_name, sizeof(local_name));读出数据再去设置 蓝牙名


FAQ3 hci log无输出

先确保代码有打开’HCI_ON_LOG’ ‘LOG_ON_CONSOLE’ 这两个宏,再按文档排查hci常见faq


FAQ4 速查:BLE 传文件速度慢

1. 先按收益做 3 件事

优先级

优化项

目标值

收益

1

MTU 协商

517 / 185

+500~900%

2

连接间隔切高性能档

15ms

+200~500%

3

PHY 切 2M

2M PHY

+80~100%

3 项做完:速率通常从 <20 KB/s → 60~100 KB/s。


2. 影响因素排序

层级

因素

影响

ATT

MTU 未协商(默认23B)

差 9~25 倍

LL

连接间隔太大(100ms vs 15ms)

差 6 倍

PHY

没切 2M(还在 1M)

差 2 倍

应用

逻辑复杂 / 打印多 / 校验复杂

效率低

系统

外部存储速率

读写速度

射频

距离远 / WiFi 干扰 / RSSI 低

重传降速

对端

iOS 保守 / 老手机只支持 1M / BT、BLE 互相影响

视机型

并发

多连接 / 音频显示抢 CPU

视场景


3. 连接参数:默认代码 + 手动控制

默认代码逻辑(自动档):

sibles_acquire_tx_pkts_hook
    └─ if (buffer_num >= BLE_SPEED_ADAPT_TX_COUNT)   // 数据包 >3
           └─ 更新为快速模式
    └─ 连续 30 秒无数据传输
           └─ 自动更新为低速模式
  • OTA、表盘传输时速度自动控制,客户不用管。

  • 默认代码里连接参数不是一连接就固定,而是按数据量动态切。

手动控制函数:

// 进低速
void ble_enter_low_power(uint8_t conn_idx);

// 进快速
void ble_exit_low_power(uint8_t conn_idx);

// 任意更新连接参数
uint8_t connection_manager_update_parameter(
    uint8_t conn_idx,
    uint8_t interval_level,
    uint8_t *data
);

4. MTU:默认代码 + 手动协商

默认代码逻辑:

  • 默认最大 MTU 由 ble_max_mtu_get() 决定。

  • 如果用户没实现这个函数,协议栈用默认值 1024。

  • 取值范围:>= 23 且 <= 1024。

  • 连接成功后,默认代码不会自动把 MTU 提到最大,需要主动调用交换,或等对端发起。

手动协商函数:

// 连接成功后主动发起 MTU 交换
uint8_t sibles_exchange_mtu(uint8_t conn_idx);

// 协议栈回调,获取本端想用的最大 MTU
uint16_t ble_max_mtu_get();

对端设置成功后的上报事件:

SIBLES_MTU_EXCHANGE_IND

默认路径小结:

BLE 连接成功
    └─ 可调用 sibles_exchange_mtu(conn_idx) 主动协商
    └─ 或等对端发起,成功后上报 SIBLES_MTU_EXCHANGE_IND
    └─ 本端最大 MTU 由 ble_max_mtu_get() 决定
           └─ 未实现 → 默认 1024

5. PHY

默认代码连接成功后启动定时器切 2M:

ble_connect.c -> ble_event_handler -> case BLE_GAP_CONNECTED_IND:
-> ble_update_phy_timeout_start
-> ble_update_phy_timeout
-> ble_gap_update_phy

FAQ5 有些 BT 的 Profile 服务不需要,怎么关闭

背景问题

默认 solution 代码中,业务逻辑与 UI 绑定太深,对应的宏控制不全。
直接关闭宏编译会出现一堆报错,无法通过简单的宏开关来裁剪 Profile。

建议方案

不要动宏开关,直接控制对应 Profile 的 init 函数,将其注释掉。

位置:bts2_app_demo.c → bt_init_profile()

示例代码

void bt_init_profile(bts2_app_stru *bts2_app_data)
{
    /*HFP HF */
#ifdef BT_USING_HF
    //bt_hfp_hf_init(bts2_app_data);
    //bt_hfp_hf_start_enb(bts2_app_data);
#endif

    /*for sdk config do not change BT_USING_AG*/
#ifdef BT_USING_AG
    //bt_hfp_ag_app_init(bts2_app_data);
    //bt_hfp_start_profile_service(bts2_app_data);
#endif

#ifdef BT_FINSH_PAN
    bt_pan_init(bts2_app_data);
    bt_pan_reg(bts2_app_data);
#endif

    /*A2DP SNK */
#ifdef BT_USING_A2DP
    //bt_av_init(bts2_app_data);
#endif

#ifdef BT_USING_AVRCP
    //bt_avrcp_init(bts2_app_data);
#endif

#ifdef BT_USING_HID
    //bt_hid_init(bts2_app_data);
#endif

#ifdef BT_USING_PBAP
    //bt_pbap_clt_init(bts2_app_data);
#endif

#ifdef BT_USING_SPP
    bt_spp_init(bts2_app_data);
    bt_spp_srv_start_enb(bts2_app_data);
#endif
}

操作要点

步骤

说明

1

找到 bts2_app_demo.c 中的 bt_init_profile() 函数

2

定位到不需要的 Profile 对应的 init / start_enb 调用

3

直接注释掉该行(不要删宏,避免其他文件引用报错)

4

保留宏定义本身,仅注释函数调用

注意事项

  • 对代码大小有严格要求的情况:此方法无效,因为宏仍然开启,相关代码仍会被编译进去,只是不执行。此时只能逐个解决编译报错,从宏层面彻底裁剪。

  • 注释 init 后,该 Profile 的服务不会启动,但相关代码仍占用空间。

  • 若注释后出现链接报错(如其他模块引用了该 Profile 的符号),需一并处理引用点。