BP10xx蓝牙开发日志
蓝牙运行框架图
BLE_SUPPORT 这个是ble蓝牙开启定义宏,设置
#ifdef CFG_TWS_SOUNDBAR_APP
#define BLE_SUPPORT ENABLE // BLE config
#else
#define BLE_SUPPORT ENABLE // BLE 启动定义宏
蓝牙config.h 配置选项表
根据代码中的配置选项,以下是整理出的配置选项及其说明的表格:
配置项 | 描述 |
---|---|
ENABLE / DISABLE | 定义了启用和禁用的宏,用于控制功能的开关。 |
BT_PROFILE_BQB_ENABLE | 是否启用BQB测试模式(蓝牙认证测试)。 |
BT_NAME | 蓝牙设备名称(默认为"Hanami-music")。 |
BT_NAME_SIZE | 蓝牙名称的最大长度(固定为40)。 |
BT_ADDR_SIZE | 蓝牙地址的长度(固定为6)。 |
FLASH_SAVE_REMOTE_BT_NAME | 是否保存已连接设备的蓝牙名称。 |
BT_TRIM_ECO0 / BT_TRIM | 老芯片和新芯片的trim值配置。 |
BT_SIMPLEPAIRING_FLAG | 配对模式(0:使用PIN码;1:简单配对)。 |
BT_PINCODE_LEN | PIN码长度(最大16字节,默认为4)。 |
BT_PINCODE | 默认PIN码(默认为"0000")。 |
BT_LSTO_DFT | 连接超时时间(单位为0.625ms,默认为8000,即5秒)。 |
BT_SNIFF_CLK_SEL | Sniff模式的时钟选择(0:HOSC;1:RC;2:LOSC)。 |
BT_TX_POWER_LEVEL | 发射功率级别(默认为21,对应+4dbm)。 |
BT_PAGE_TX_POWER_LEVEL | 回连发射功率级别(默认为16)。 |
BT_INQUIRYSCAN_INTERVAL | Inquiry扫描间隔(默认为0x100)。 |
BT_INQUIRYSCAN_WINDOW | Inquiry扫描窗口(默认为0x12)。 |
BT_PAGESCAN_INTERVAL | Page扫描间隔(默认为0x1000)。 |
BT_PAGESCAN_WINDOW | Page扫描窗口(默认为0x12)。 |
BT_PAGE_TIMEOUT | Page超时时间(默认为5120ms)。 |
BT_A2DP_SUPPORT | 是否支持A2DP协议(默认启用)。 |
BT_AVRCP_SUPPORT | 是否支持AVRCP协议(默认启用)。 |
BT_HFP_SUPPORT | 是否支持HFP协议(条件启用)。 |
BT_SPP_SUPPORT | 是否支持SPP协议(默认禁用)。 |
BT_HID_SUPPORT | 是否支持HID协议(默认禁用)。 |
BT_MFI_SUPPORT | 是否支持MFI功能(默认禁用)。 |
BT_OBEX_SUPPORT | 是否支持OBEX协议(默认禁用)。 |
BT_PBAP_SUPPORT | 是否支持PBAP协议(默认禁用)。 |
BLE_SUPPORT | 是否支持BLE功能(条件启用)。 |
BT_AUDIO_AAC_ENABLE | 是否启用AAC音频支持(条件启用)。 |
BT_AVRCP_ADVANCED | 是否启用高级AVRCP功能(默认启用)。 |
BT_AVRCP_VOLUME_SYNC | 是否启用音量同步功能(条件启用)。 |
BT_AVRCP_PLAYER_SETTING | 是否支持播放器设置功能(默认禁用)。 |
BT_AVRCP_SONG_PLAY_STATE | 是否支持歌曲播放状态反馈(默认禁用)。 |
BT_AVRCP_SONG_TRACK_INFOR | 是否支持歌曲ID3信息反馈(默认禁用)。 |
BT_AVRCP_BROWSER_FUNC | 是否启用AVRCP浏览器功能(默认禁用)。 |
BT_AUTO_PLAY_MUSIC | AVRCP连接成功后是否自动播放音乐(默认禁用)。 |
BT_HFP_SUPPORT_WBS | 是否支持宽频带语音(WBS)(默认启用)。 |
BT_HFP_AUDIO_DATA | HFP音频数据格式(默认为mSBC)。 |
BT_HFP_QUIRY_PHONEBOOK | 是否启用通讯录请求功能(默认禁用)。 |
BT_HFP_CALL_DURATION_DISP | 是否显示通话时长(默认启用)。 |
BT_OBEX_UPDATE_FUNC_SUPPORT | 是否支持通过OBEX进行固件升级(条件启用)。 |
BB_EM_MAP_ADDR / BB_EM_SIZE | BB EM的映射地址和大小配置。 |
BT_BASE_MEM_SIZE | 蓝牙基础内存大小(根据TWS支持情况调整)。 |
BT_BLE_MEM_SIZE | BLE功能的内存大小(根据BLE支持情况调整)。 |
BT_AUDIO_AAC_MEM_SIZE | AAC音频支持的内存大小(根据AAC支持情况调整)。 |
BT_AVRCP_TG_MEM_SIZE | AVRCP TG功能的内存大小(根据相关功能启用情况调整)。 |
BT_AVRCP_BRWS_MEM_SIZE | AVRCP浏览器功能的内存大小(根据功能启用情况调整)。 |
BT_HFP_MEM_SIZE | HFP功能的内存大小(根据功能启用情况调整)。 |
BT_SPP_MEM_SIZE | SPP功能的内存大小(根据功能启用情况调整)。 |
BT_TWS_MEM_SIZE | TWS功能的内存大小(根据功能启用情况调整)。 |
BT_HID_MEM_SIZE | HID功能的内存大小(根据功能启用情况调整)。 |
BT_MFI_MEM_SIZE | MFI功能的内存大小(根据功能启用情况调整)。 |
BT_OBEX_MEM_SIZE | OBEX功能的内存大小(根据功能启用情况调整)。 |
BT_PBAP_MEM_SIZE | PBAP功能的内存大小(根据功能启用情况调整)。 |
BT_POR_TRY_COUNTS / BT_POR_INTERNAL_TIME | 开机自动重连的尝试次数和间隔时间。 |
BT_BLR_TRY_COUNTS / BT_BLR_INTERNAL_TIME | BB Lost后的自动重连尝试次数和间隔时间。 |
BT_TWS_TRY_COUNTS / BT_TWS_INTERNAL_TIME | TWS自动重连的尝试次数和间隔时间(条件启用)。 |
BT_TWS_BLR_TRY_COUNTS / BT_TWS_BLR_INTERNAL_TIME | TWS Link Loss后的自动重连尝试次数和间隔时间(条件启用)。 |
BT_FAST_POWER_ON_OFF_FUNC | 是否支持快速打开/关闭蓝牙功能(条件启用)。 |
BT_AUTO_CLEAR_LAST_PAIRING_LIST | 是否在手机端清除配对记录后,同步清理设备端的配对记录。 |
BT_MATCH_CHECK | 是否启用匹配检查(默认启用)。 |
蓝牙初始化函数解读
读懂bt_stack_service.c协议栈
这个C文件bt_stack_service.c
是蓝牙协议栈服务的实现,主要功能是初始化和运行蓝牙(包括经典蓝牙BR/EDR和低功耗蓝牙BLE)的核心服务。以下是其核心作用的逐步分析:
- 初始化经典蓝牙和BLE协议栈。
- 管理协议栈主循环,处理连接、数据传输和音频解码。
- 适配硬件层(基带、UART),确保硬件与协议栈协同工作。
- 提供调试接口,支持通过串口控制BLE通知等功能。
- 状态监控与错误处理,保障蓝牙服务稳定运行。
适用于需要同时支持经典蓝牙(如A2DP音频)和低功耗蓝牙(如通知服务)的嵌入式设备。
1. 蓝牙协议栈初始化
- BR/EDR初始化
调用BtStackInit()
初始化经典蓝牙模块。若失败,协议栈任务挂起(死循环);成功则继续初始化BLE。 - BLE初始化
通过InitBlePlaycontrolProfile()
和InitBleStack()
初始化低功耗蓝牙服务和协议栈,支持BLE通知功能(如att_server_notify
发送数据)。
2. 协议栈主循环
rw_main()
是蓝牙协议栈的主要运行函数,它是 RW (RF Wireless) IP 协议栈的核心调度函数。从代码结构来看,它主要负责处理蓝牙协议栈的各种事件和消息。
让我们分析一下相关的关键点:
- 在主循环中的调用:
while(1)
{
rw_main(); // 运行蓝牙协议栈主循环 这个函数属于底层的蓝牙基带(Baseband)API,通常这部分代码是芯片厂商提供的闭源代码。
BTStackRun(); // 运行蓝牙协议栈上层服务
A2dp_Decode(); // 处理音频解码
}
rw_main()
的主要功能:
- 处理蓝牙协议栈的底层事件
- 管理蓝牙射频(RF)相关的操作
- 处理蓝牙数据包的收发
- 调度和执行各种蓝牙协议任务(如L2CAP, ATT, SMP等)
- 相关的重要API:
void Bt_init(void* params); // 蓝牙初始化
void rw_main(void); // 蓝牙协议栈主循环
void rwip_reset(void); // 重置蓝牙协议栈
- 工作流程:
初始化
Bt_init() -> 配置蓝牙参数和初始化协议栈
运行时
硬件中断 -> 产生事件 -> rw_main()处理事件 -> 调用相应的回调函数(如att_write)
这是一个典型的事件驱动架构:
- 硬件中断触发事件
rw_main()
在主循环中轮询这些事件- 根据事件类型调用相应的处理函数
- 处理完成后返回主循环继续轮询
所以rw_main()
实际上是整个蓝牙协议栈的"心脏",它通过不断轮询和处理事件来保持蓝牙通信的正常运行。这种设计使得系统能够及时响应蓝牙通信事件,同时又不会在中断处理程序中执行过多的业务逻辑。
3. 服务管理与上下文
- 状态管理
使用BtStackServiceContext
结构体跟踪服务状态(如初始化、错误模式),确保协议栈运行稳定性。 - 内存与配置管理
- 全局内存堆
gBtHostStackMemHeap
为协议栈提供动态内存。 BT_CONFIGURATION_PARAMS
加载蓝牙配置参数(如设备地址、配对信息)。
- 全局内存堆
4. 硬件层交互
- 基带初始化
Bt_init()
配置蓝牙基带参数(BB层),确保硬件与协议栈正确通信。 - 平台接口适配
通过SetBtPlatformInterface()
设置操作系统接口(如任务调度、内存管理),实现跨平台兼容。
5. 错误处理与恢复
- 初始化异常处理
初始化失败时进入死循环,防止协议栈异常运行。 - BB层错误跟踪
记录基带错误类型(bbErrorType
),为后续诊断提供依据。
BLE的写入操作
从代码来看,BLE的写入操作确实是通过中断方式触发的。让我解释一下流程:
- 在
BtStackServiceEntrance
函数中,系统初始化了BLE栈:
#if (BLE_SUPPORT == ENABLE)
{
InitBlePlaycontrolProfile();
if(!InitBleStack(&g_playcontrol_app_context, &g_playcontrol_profile))
{
BT_DBG("error ble stack init\n");
}
}
#endif
- 在主循环中,系统通过
rw_main()
函数来处理蓝牙协议栈的事件:
while(1)
{
rw_main();
BTStackRun();
// ...
}
- 当BLE外设(比如手机)向设备写入数据时,会触发硬件中断。这个中断会被蓝牙协议栈捕获,然后在
rw_main()
的处理过程中,通过回调机制最终调用到我们之前看到的att_write
函数。
调用链大致是这样的:
硬件中断 -> 蓝牙协议栈ISR -> rw_main() -> 协议栈回调 -> att_write()
这种设计是典型的中断驱动模型:
- 底层硬件接收到BLE数据包会触发中断
- 中断处理程序将数据包放入缓冲区
- 主循环中的
rw_main()
会处理这些缓冲的数据包 - 当识别到是写入操作时,就会调用
att_write
函数来处理
这样的设计有几个优点:
- 通过中断确保及时响应BLE通信
- 通过缓冲区和主循环处理机制避免在中断上下文中执行耗时操作
- 将底层的通信细节与应用层的数据处理分离
所以,虽然att_write
本身不是直接在中断上下文中执行的,但它的触发确实源于BLE通信的硬件中断。