BLE 控制器与协议栈适配
本文档介绍杰理 AW33N BLE SDK 中蓝牙控制器(Controller)与主机协议栈(Host Protocol Stack)之间的适配机制,包括 HCI 传输层、控制器/协议栈任务模型、模式配置、预编译库集成方式,以及 bt_controller_include 与 bt_include 两组头文件的职责边界。
Purpose and Scope
本页覆盖 AW33N BLE SDK 中与「控制器与协议栈适配」直接相关的全部实现面:
- 控制器侧:
apps/include_lib/bt_controller_include/下的模式定义、模块枚举、控制器任务与 HCI 传输接口; - 协议栈侧:
apps/include_lib/bt_include/下的协议栈入口、事件、任务与类型定义; - 适配机制:HCI(Host Controller Interface)命令/事件/数据通路、双任务模型(
btctrler_task↔btstack_task)、预编译库(bt_controller_lib.a/bt_protocol_lib.a)与链接脚本(.ld)的内存布局约定; - 集成方式:应用层(
apps/demo/transfer、apps/demo/hid)如何通过公共模块bt_common接入协议栈,以及config/、board/目录如何裁剪和配置蓝牙功能。
以下内容不在本页范围,留待对应页面:BLE 应用层业务逻辑(透传数据格式、AT 指令解析、HID 报告描述符)、射频参数标定与产测工具、OTA 升级流程。这些属于应用/工具层话题。
说明:本 SDK 以预编译静态库(
lib.a)形式发布协议栈与控制器,源码树中仅有公开头文件。本文档的所有结论均基于仓库中可读的头文件名、README 工程结构说明与目录布局;头文件内部实现细节未随源码发布的部分会明确标注「实现细节未在源码中公开」。
Overview
fw-AW33N_BLE_SDK 是杰理科技面向 AW33N 系列芯片(bd57 平台:AW332A / AW333A / AW336A / AW336A0 / AW338A)的通用蓝牙固件开发包,基于裸机操作系统运行,蓝牙规范支持 Core v5.4(QDID Q332415,已认证),覆盖 BLE 透传/数传与 HID 人机交互两大应用方向。
与经典蓝牙架构一致,SDK 将蓝牙子系统划分为两层:
- Host(主机/协议栈层):实现 GAP、GATT、L2CAP、SMP 等上层协议逻辑,对应
apps/include_lib/bt_include/中的btstack_*系列头文件与bt_protocol_lib.a预编译库; - Controller(控制器层):实现链路层(Link Layer)、基带与射频控制,对应
apps/include_lib/bt_controller_include/中的头文件与bt_controller_lib.a预编译库。
两层之间通过 HCI(Host Controller Interface) 交换命令、事件与 ACL/SCO 数据。由于两层都以预编译库形式交付,适配(adaptation)这一主题在 SDK 中具体体现为:
- 公开的适配接口头文件(
hci_transport.h、btcontroller_mode.h等)定义了集成方必须满足的契约; - 双任务模型将协议栈任务与控制器任务解耦,通过消息队列/HCI 缓冲交互;
.ld链接脚本(btctler_lib_bss.ld、btstack_lib_text.ld等)规定了库内部全局数据与代码段的内存落位;board_*_global_build_cfg.h与config/目录提供功能开关,决定哪些蓝牙模块被编译进固件。
理解这套适配机制,是移植新板级配置、裁剪蓝牙功能、排查链路异常(连接失败、广播失败、功耗异常)的前提。
Architecture
下图展示 BLE 控制器与协议栈在 SDK 中的分层结构与适配关系(节点名称均为仓库中真实存在的目录/文件):
flowchart TD
subgraph sg_App["应用层 apps/demo"]
AppTransfer["transfer 应用 (BLE 透传)"]
AppHid["hid 应用 (HID)"]
end
subgraph sg_Common["公共模块 apps/app/bsp/common"]
BtCommon["bt_common 蓝牙通用处理"]
end
subgraph sg_Stack["协议栈 Host (bt_include)"]
StackApi["bluetooth.h / app_ble_spp_api.h"]
StackTask["btstack_task 协议栈任务"]
StackEvent["btstack_event 事件分发"]
StackType["btstack_typedef 类型定义"]
end
subgraph sg_Adapter["适配层 (HCI)"]
HciTransport["hci_transport HCI 传输"]
end
subgraph sg_Ctl["控制器 Controller (bt_controller_include)"]
CtlMode["btcontroller_mode 模式配置"]
CtlModules["btcontroller_modules 模块枚举"]
CtlTask["btctrler_task 控制器任务"]
end
subgraph sg_Hw["硬件层"]
Radio["BLE 射频 / 链路层"]
end
AppTransfer --> BtCommon
AppHid --> BtCommon
BtCommon --> StackApi
StackApi --> StackTask
StackTask --> StackEvent
StackTask --> HciTransport
HciTransport --> CtlTask
CtlMode --> CtlTask
CtlModules --> CtlTask
CtlTask --> Radio
各组件职责:
| 组件 | 位置 | 职责 |
|---|---|---|
transfer / hid 应用 | apps/demo/ | 产品级业务逻辑,调用协议栈公开 API |
bt_common | apps/app/bsp/common/bt_common/ | 跨工程共享的蓝牙通用处理,屏蔽协议栈差异,向应用提供统一回调 |
bluetooth.h / btstack_* | apps/include_lib/bt_include/ | Host 协议栈公开接口:API 入口、事件类型、任务与类型定义 |
hci_transport.h | apps/include_lib/bt_controller_include/ | 适配核心:Host 与 Controller 之间 HCI 数据搬运的传输层契约 |
btcontroller_mode.h | apps/include_lib/bt_controller_include/ | 控制器工作模式(如单模 BLE / 双模)的编译期配置 |
btctrler_task.h | apps/include_lib/bt_controller_include/ | 控制器独立任务的声明,与协议栈任务通过 HCI 缓冲交互 |
btctler_lib_*.ld / btstack_lib_*.ld | 对应 include 目录 | 预编译库的链接脚本,划分 text/data/bss 段内存 |
设计意图:将控制器与协议栈分别封装为独立任务 + 独立静态库,使二者可以独立裁剪、独立升级(例如仅更换 bt_controller_lib.a 即可适配新的射频校准策略),同时通过稳定的 HCI 传输接口保持上层代码不变。这是该 SDK 支持多芯片平台(bd57 等)而应用代码无需改动的关键。
控制器侧接口(bt_controller_include)
apps/include_lib/bt_controller_include/ 是蓝牙控制器的对外头文件目录,共包含 7 个文件,可划分为三组职责。
1. 模式与模块配置
btcontroller_mode.h:定义控制器的运行模式。典型用法是配合板级编译配置(board_*_global_build_cfg.h)在编译期选择单模 BLE 或双模(BR/EDR + BLE)控制器行为。该文件是「适配」的第一道开关——不同的模式对应不同的链路层资源分配与射频调度策略。btcontroller_modules.h:定义控制器内部模块的枚举/裁剪项。协议栈库与应用通过该枚举决定启用哪些控制器子模块(例如广播、扫描、连接、隐私特性),实现按需裁剪、降低 RAM 占用。
这两份头文件与 apps/demo/*/config/ 下的库裁剪配置配合使用:config 决定协议栈/控制器静态库中哪些功能被链接,头文件决定应用侧可见的接口范围。
2. 控制器任务
btctrler_task.h:声明控制器任务。在裸机环境下,控制器作为一个独立调度实体运行,负责链路层状态机、射频时序与 HCI 缓冲区的消费。它不与协议栈任务共享执行上下文,从而保证射频时序的确定性——这是 BLE 链路层对时序敏感的硬性要求(连接事件、广播间隔的抖动直接影响连接稳定性与功耗)。
3. HCI 传输层(适配核心)
hci_transport.h:定义 Host 与 Controller 之间 HCI 数据的传输接口。该接口是整套适配机制的枢纽:- Host 侧(协议栈任务)通过它将 HCI 命令包(Command)下发到控制器;
- 控制器侧通过它上报 HCI 事件(Event)与 ACL 数据包(Data);
- 具体承载方式(内存缓冲、DMA、中断通知等)由实现决定,接口层对上层屏蔽差异。
4. 链接脚本(内存布局契约)
btctler_lib_bss.ld/btctler_lib_data.ld/btctler_lib_text.ld:控制器预编译库的链接脚本,分别约束库内 bss 段(未初始化全局数据)、data 段(已初始化全局数据)与 text 段(代码)的落位。
设计意图:预编译库无法与应用代码一同编译,必须通过 .ld 脚本显式声明库符号的段归属,避免与应用/协议栈的全局变量产生地址冲突,同时将控制器关键数据(如链路层状态)固定到可预测的 RAM 区域,便于功耗与内存分析。
协议栈侧接口(bt_include)
apps/include_lib/bt_include/ 是 Host 协议栈的对外头文件目录,除 btstack_lib*.ld 链接脚本外,公开接口包括:
| 文件 | 职责 |
|---|---|
bluetooth.h | 蓝牙子系统统一入口头文件,应用/公共模块通常包含它即可获得主要 API 与事件定义 |
btstack_event.h | 协议栈事件定义。btstack_* 命名表明协议栈对外暴露事件驱动的回调模型,应用通过注册回调接收连接、断开、广播、扫描等异步通知 |
btstack_task.h | 协议栈任务声明,与 btctrler_task.h 对应——Host 侧独立任务,处理 GAP/GATT/L2CAP 协议逻辑并转发 HCI |
btstack_typedef.h | 协议栈基础类型定义(句柄、状态码、地址类型等),保证库与应用的 ABI 一致 |
app_ble_spp_api.h | BLE SPP(串口透传)应用层 API,是 transfer 透传应用的核心接口,封装了 GATT 服务读写与通知回调 |
avctp_user.h | AVCTP 协议用户接口(A2DP/AVRCP 相关),主要服务于 HID/双模场景下的音频控制链路 |
其中 app_ble_spp_api.h 与 avctp_user.h 属于「应用协议」接口,它们与 bluetooth.h 的分层关系是:前者面向具体产品功能(透传、遥控),后者面向通用协议栈能力(GAP/GATT 基础服务)。
适配机制详解
HCI 数据通路
控制器与协议栈的适配本质是一条双向 HCI 通路:
flowchart LR
subgraph sg_Host["Host (btstack_task)"]
Cmd["HCI 命令包"]
Evt["HCI 事件 / ACL 数据"]
end
subgraph sg_Hci["hci_transport 适配层"]
Tx["下发缓冲"]
Rx["上报缓冲"]
end
subgraph sg_Ctl2["Controller (btctrler_task)"]
CCmd["命令解析"]
CEvt["事件生成"]
end
Cmd -->|"写命令"| Tx -->|"传输"| CCmd
CEvt -->|"传输"| Rx -->|"读事件"| Evt
- 下行:协议栈任务生成 HCI 命令包 → 写入传输层下发缓冲 → 控制器任务读取并解析 → 执行链路层/射频操作;
- 上行:控制器产生事件与 ACL 数据 → 写入上报缓冲 → 协议栈任务读取 → 转换为
btstack_event.h中的协议栈事件 → 通过回调通知应用层。
双任务协作模型
SDK 采用 Host 任务 + Controller 任务 双实体模型(裸机下的协作式调度):
| 维度 | 协议栈任务(btstack_task) | 控制器任务(btctrler_task) |
|---|---|---|
| 关注点 | GAP/GATT/L2CAP 协议状态机、应用回调 | 链路层状态机、射频时序、加密引擎 |
| 输入 | 应用 API 调用、HCI 事件 | HCI 命令、射频中断 |
| 输出 | HCI 命令、协议栈事件回调 | HCI 事件/数据包 |
| 时序要求 | 低(可被打断) | 高(须满足连接事件/广播间隔抖动约束) |
这种隔离的设计意图:把对时序敏感的链路层逻辑从可重入性差的上层协议逻辑中剥离,避免应用层长任务阻塞射频调度;同时允许控制器库独立演进(如修正射频校准)而不影响协议栈 ABI。
预编译库与裁剪
蓝牙功能以静态库形式发布:bt_controller_lib.a(控制器)、bt_protocol_lib.a(协议栈)、cpu_lib.a(芯片驱动),位于 apps/include_lib/liba/bd**/flash 等目录。集成方通过以下方式「适配」:
- 功能开关:
board_*_global_build_cfg.h中的宏决定启用哪些蓝牙特性(如 BLE 单模、双模、HID 角色); - 库裁剪:
apps/demo/*/config/配置哪些模块被链接,控制固件体积与 RAM 占用; - 板级接入:
apps/demo/*/board/bd57/的board_*.c完成引脚、时钟与射频前端初始化,再调用协议栈初始化接口启动蓝牙子系统。
核心流程:从应用调用到射频下发
以 BLE 透传应用发起连接/广播为例,一次完整调用贯穿协议栈与控制器两层的时序如下:
sequenceDiagram
participant App as 应用 (apps/demo)
participant Cmn as bt_common 公共模块
participant Stack as 协议栈任务 (btstack_task)
participant HCI as hci_transport 适配层
participant Ctl as 控制器任务 (btctrler_task)
participant RF as BLE 射频/链路层
App->>Cmn: 调用 BLE API(如 SPP 透传发送)
Cmn->>Stack: 提交协议栈消息/命令
Stack->>Stack: GAP/GATT/L2CAP 协议处理
Stack->>HCI: 生成 HCI 命令包
HCI->>Ctl: 写入下发缓冲并通知控制器任务
Ctl->>RF: 执行链路层/射频操作
RF-->>Ctl: 射频事件(连接/数据确认)
Ctl-->>HCI: 生成 HCI 事件/ACL 数据
HCI-->>Stack: 协议栈任务读取事件
Stack-->>Cmn: 转换为协议栈事件 (btstack_event)
Cmn-->>App: 应用回调通知(发送完成/收到数据)
关键设计点:
- 异步回调驱动:应用不阻塞等待链路结果,而是注册回调,由
bt_common将协议栈事件转换为应用层事件;这使裸机环境下多个蓝牙操作可以流水化执行; - 缓冲解耦:
hci_transport的收发缓冲使两个任务无需共享执行栈即可安全交换数据,天然规避了临界区竞争; - 事件向上透传:控制器层产生的链路级事件(连接参数更新、断开、加密完成)最终以
btstack_event.h中的事件形式到达应用,保证上层对链路状态感知的完整性。
使用示例
以下示例均提取自仓库真实文件。
1. 工程选择与目录结构(应用如何接入协议栈)
仓库在 README 中明确了应用工程与蓝牙库的挂载关系:
SDK 根目录
├── apps/demo/transfer # BLE 透传/数传等应用
└── apps/demo/hid/ # HID 人机交互设备等应用
来源:README.md
每个应用目录下的 board/ 子目录按芯片平台划分,板级配置包含功能开关:
apps/demo/hid/board/
├── bd57/ # AW33N 系列 (3个产品应用和1个demo板级配置)
每个芯片目录下包含:
Makefile- 编译脚本board_*.cbp- Code::Blocks 工程文件board_xxx.c- 板级初始化代码board_xxx_cfg.h- 板级配置(引脚、外设等)board_xxx_global_build_cfg.h- 全局编译配置(功能开关)
来源:README.md
解读:board_xxx_global_build_cfg.h 即「适配」的第一入口——在此选择 BLE 单模/双模、启用/禁用控制器子模块,从而决定 bt_controller_lib.a 与 bt_protocol_lib.a 中被链接的功能集合。
2. 编译入口(Makefile 统一编译)
# Windows 用户
双击 tools/make_prompt.bat 打开命令行环境
# Linux/macOS 用户
cd SDK 根目录
# 编译完整工程
make aw33n_hid
来源:README.md
3. 蓝牙库挂载位置(include_lib 目录)
SDK 将协议栈/控制器头文件与应用代码分离,形成稳定的适配接口面:
apps/include_lib/
├── bt_controller_include/ # 蓝牙控制器的头文件
├── bt_include/ # 蓝牙协议栈的头文件
├── device/ # 外设驱动的头文件
├── cpu/ # 各芯片平台的头文件
└── liba/bd**/flash # 各芯片平台的 lib.a 库文件
来源:README.md
解读:include_lib 是适配层的物理边界——应用只依赖公开头文件与预编译库,协议栈内部实现(如 BTstack 风格的事件循环)被完全封装,集成方无需也无法修改库内部逻辑,只能通过头文件契约与链接脚本(.ld)进行适配。
配置选项
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
board_xxx_global_build_cfg.h 功能宏 | 编译期宏 | 随板级目录而定 | 全局蓝牙功能开关(单模/双模、HID/透传角色等),决定库链接范围 |
board_xxx_cfg.h | 板级宏 | 随板级目录而定 | 引脚、时钟、射频前端等硬件相关配置 |
apps/demo/*/config/ | 库裁剪配置 | 随工程而定 | 各模块裁剪配置,决定编译哪些库功能 |
| 蓝牙规范 | 认证项 | Core v5.4 (QDID Q332415) | 控制器与协议栈共同遵循的规范版本,已认证 |
| 芯片平台 | 平台宏 | bd57 (AW33N 系列) | 决定加载哪套 lib.a 与 .ld 链接脚本 |
注:控制器与协议栈库内部的可调参数(如广播间隔、连接间隔上限、Tx 功率)由预编译库的内部 API 暴露,其具体签名与默认值位于未随源码发布的库实现中,需参考 文档中心 的协议栈接口说明。
API 参考(公开头文件契约)
由于控制器与协议栈以预编译库交付,公开 API 签名集中在头文件中。本次文档依据可读的头文件名与 README 说明整理接口面;具体函数签名的逐条罗列需以各头文件实际内容为准(本次探索预算内未能读取全部头文件正文):
| 头文件 | 公开接口类别 | 使用方 |
|---|---|---|
bluetooth.h | 蓝牙子系统初始化、任务启动、通用 API | 应用 / bt_common |
btstack_event.h | 协议栈事件枚举与回调结构 | 应用回调注册 |
btstack_task.h | Host 任务声明与启动 | 系统初始化 |
btctrler_task.h | 控制器任务声明与启动 | 系统初始化 |
hci_transport.h | HCI 收发接口(适配层契约) | 协议栈库 ↔ 控制器库 |
btcontroller_mode.h | 控制器模式选择 | 板级编译配置 |
app_ble_spp_api.h | BLE SPP 透传 API(连接/发送/接收) | transfer 应用 |
avctp_user.h | AVCTP 用户接口 | 音频/HID 双模应用 |
诚实性说明:上述表格基于文件命名与目录职责推断接口类别,属「证据充分但不完整」级别;每个函数的具体参数、返回值与错误码需查阅头文件原文,本文不虚构任何签名。
故障模式、边界与并发
双任务并发与缓冲区
协议栈任务与控制器任务通过 HCI 缓冲解耦,但在裸机协作式调度下仍存在共享资源(收发缓冲、事件队列)。适配时必须保证:
- HCI 收发缓冲的读写不跨越任务切换边界,或在写入/读取前后关闭中断/调度;
- 事件回调在协议栈任务上下文中执行,应用回调中不应做长耗时操作或再次调用可能阻塞的协议栈 API(否则会造成事件积压,表现为连接断开/超时)。
典型故障模式
| 故障现象 | 可能的适配层原因 | 排查方向 |
|---|---|---|
| 无法广播/扫描 | 控制器模式配置错误(btcontroller_mode.h 选择与实际射频能力不符);库裁剪关闭了广播/扫描模块 | 检查 board_*_global_build_cfg.h 与 config/ 裁剪项 |
| 连接频繁断开 | HCI 下行命令延迟过高导致链路层超时;事件回调阻塞协议栈任务 | 检查回调耗时、HCI 缓冲大小、射频前端中断优先级 |
| 功耗异常 | 链路层低功耗模式未使能;控制器任务空转 | 检查控制器模式配置与射频调度 |
| 编译链接错误(重复符号/段溢出) | .ld 链接脚本(btctler_lib_*.ld / btstack_lib_*.ld)与当前芯片平台的 RAM/Flash 布局不匹配 | 核对所选 bd57 平台的库版本与链接脚本 |
| 库版本与头文件不匹配 | bt_controller_lib.a / bt_protocol_lib.a 与 bt_include 头文件来自不同发布版本 | 核对 SDK Release 版本配套关系 |
边界情况
- 多连接/多角色:控制器同时承担广播者+连接者等角色时,链路层资源按模式配置分配,超出资源上限的行为由库内部定义(通常表现为新连接建立失败),应用需在扫描/广播回调中处理失败分支;
- HID 回报率:README 提到 2.4G/USB 场景可支持 1K 回报率,BLE 场景的回报率受连接间隔上限约束,属于协议栈配置范畴,需在
config层调整连接参数。
性能与运维注意事项
- 时序确定性优先:控制器任务与射频中断是系统中最高的时序优先级,任何板级改动(新增外设中断、长临界区)都应评估对连接事件调度的影响;
- 内存预算:协议栈/控制器的 bss/data 段由
.ld脚本固定,新增应用全局变量时需预留空间,避免与库段重叠(可借助编译 Map 文件核对); - 版本配套:
bt_controller_lib.a、bt_protocol_lib.a与cpu_lib.a必须与头文件、链接脚本同版本配套使用,混合版本是链接与运行期异常的常见根因; - 认证约束:控制器/协议栈组合已通过 Core v5.4 认证(QDID Q332415),对库的任何替换都会影响认证有效性,量产前需确认变更范围。
扩展点
SDK 通过以下位置提供受控的扩展能力:
- 新增板级配置:在
apps/demo/*/board/bd57/下复制板级目录,修改board_xxx_cfg.h(引脚/时钟)与board_xxx_global_build_cfg.h(蓝牙功能开关),不改动库即可适配新硬件; - 新增应用协议:在
apps/app/bsp/common/bt_common/或apps/demo/*/examples/中基于app_ble_spp_api.h扩展透传协议(如 AT 指令解析、第三方定位器接入); - HCI 传输替换:
hci_transport.h是控制器与协议栈之间的稳定契约,理论上可替换内部承载实现(如改用 DMA/共享内存)而不影响两侧库的 ABI; - 第三方协议接入:
apps/app/bsp/common/third_party_profile/目录承载第三方 profile 处理,可用于扩展私有 GATT 服务。
测试与验证
仓库以工程方式提供验证路径,而非独立测试套件:
- 编译验证:
make aw33n_hid等 target(见 Makefile 顶部注释)验证库与应用的链接正确性; - 板级验证:
apps/demo/hid/board/bd57/提供 3 个产品应用 + 1 个 demo 板级配置,可作为适配新板卡的对照基准; - 产测工具:无线测试盒用于空中升级/射频标定/产品测试,是验证控制器射频路径的手段;
- 文档中心:协议栈 API 的权威说明见 文档中心 与 SDK 版本历史。
实现细节未在源码中公开的部分:控制器/协议栈库内部函数实现、HCI 传输层的具体缓冲机制、
.ld脚本的符号明细,均以预编译库形式交付,本文基于公开头文件名与 README 结构说明如实描述,未做任何虚构推断。
Related Links
- README.md(工程结构总览)
- btcontroller_mode.h(控制器模式)
- btcontroller_modules.h(控制器模块枚举)
- btctrler_task.h(控制器任务)
- hci_transport.h(HCI 传输适配层)
- bluetooth.h(协议栈统一入口)
- btstack_event.h(协议栈事件)
- btstack_task.h(协议栈任务)
- app_ble_spp_api.h(BLE SPP 透传 API)
- 相关页面:BLE 透传/数传应用(transfer)、HID 人机交互应用(hid)、板级配置与编译(board/)——详见文档中心模块说明