SDK 架构与目录分层
fw-AC63_BT_SDK 是杰理科技为 AC63 系列蓝牙芯片提供的通用 SDK 固件开发包。本页从顶层视角解析 SDK 的分层架构、目录组织方式与编译体系,帮助开发者快速理解"代码放在哪里、模块如何协作、工程如何构建"。
Purpose and Scope
本页覆盖以下内容:
- SDK 整体架构分层(应用层 → 公共模块层 → 平台/库层 → 硬件抽象)
- 顶层目录结构与各目录职责(
apps/、cpu/、include_lib/、tools/、doc/) - 编译体系与 target 命名规则(顶层
Makefile与板级Makefile的递归关系) - 板级配置目录(
board/)的作用与配置文件类型
以下内容属于兄弟页面,不在本页展开:
- 具体应用的业务逻辑开发(SPP+BLE 透传、HID、Mesh),参见对应应用开发文档
- 单个模块的 API 细节(音频、按键、蓝牙协议栈等),参见各自模块页面
- 环境搭建、烧录与升级工具的详细操作,参见 README 与工具文档
本文档基于仓库根目录的
README.md、顶层Makefile以及apps/目录的实际结构编写。
Overview
fw-AC63_BT_SDK 基于 Zephyr RTOS 实时操作系统,提供完整的蓝牙协议栈(已通过 Bluetooth Core v5.4 认证,QDID 222830)和丰富的应用示例。SDK 面向三类典型应用场景:
| 应用类型 | 典型产品 |
|---|---|
| SPP + BLE 透传/数传 | 数据采集、智能设备、FindMy、Dongle |
| HID 人机交互 | 蓝牙键盘、鼠标、遥控器、自拍器、游戏手柄 |
| Bluetooth Mesh | 智能照明、传感器网络、天猫精灵/涂鸦/腾讯连连接入 |
SDK 采用"一个 SDK、多芯片平台、多应用工程"的组织策略:
- 芯片平台维度:
bd19(AC632N 系列)、bd23(AC635N 系列)、br25(AC636N 系列)、br34(AC638N 系列)等,各平台拥有独立的lib.a预编译库与工具脚本; - 应用维度:
spp_and_le、hid、mesh三个应用工程,分别对应三类产品形态; - 交叉组合:通过编译 target 名称
ac{芯片型号}_{应用名}选择任意"芯片 × 应用"组合,例如ac632n_hid、ac638n_mesh。
这种设计的核心意图是复用最大化:公共模块(apps/common/)与预编译库(cpu/*/liba/)跨工程共享,应用目录只保留差异化的业务代码与板级配置,使新增产品只需"复制一个板级目录 + 修改配置头文件",而无需改动 SDK 主体。
Architecture
SDK 的分层架构如下(各层名称与目录一一对应):
flowchart TD
subgraph sg_AppLayer["应用层 apps/"]
SPP["apps/spp_and_le/"]
HID["apps/hid/"]
MESH["apps/mesh/"]
BOARD["apps/*/board/ 板级配置"]
end
subgraph sg_CommonLayer["公共模块层 apps/common/"]
AUDIO["audio/ 音频编解码"]
BTC["bt_common/ 蓝牙通用接口"]
DEV["device/ 按键/USB/传感器驱动"]
MUSIC["music/ 音乐播放"]
UPDATE["update/ 固件升级"]
KWS["jl_kws/ 关键词唤醒"]
TP["third_party_profile/ 涂鸦/腾讯连连等"]
end
subgraph sg_LibLayer["平台库层 cpu/ + include_lib/"]
LIBA["cpu/*/liba/ 预编译 .a 静态库"]
HDR["include_lib/ 协议栈/驱动头文件"]
end
subgraph sg_HwLayer["硬件层"]
HW["AC63 系列芯片"]
end
subgraph sg_ToolsLayer["构建与工具层"]
MK["顶层 Makefile"]
CB["Code::Blocks 工程 .cbp"]
VS["VS Code tasks.json"]
TOOLS["cpu/*/tools/ 烧录工具"]
end
SPP --> BOARD
HID --> BOARD
MESH --> BOARD
SPP --> AUDIO
SPP --> BTC
HID --> DEV
MESH --> TP
BOARD --> MK
MK --> CB
MK --> VS
AUDIO --> HDR
DEV --> HDR
TP --> HDR
HDR --> LIBA
LIBA --> HW
TOOLS --> HW
分层设计意图
- 应用层(
apps/):每个应用目录是一个可独立编译的工程骨架,包含app_main.c(应用入口)、version.c(版本信息)、board/(板级配置)、examples/(参考示例)、include/(模块接口)与config/(库功能裁剪配置)。应用之间互不依赖,只依赖公共模块层。 - 公共模块层(
apps/common/):跨工程共享的可复用代码,包括音频、蓝牙通用接口、外设驱动、JSON 解析(cJSON)、调试、固件升级与第三方协议(SigMesh、涂鸦、腾讯连连、HiLink)。这一层是"一次编写、三应用复用"的关键。 - 平台库层(
cpu/+include_lib/):以预编译静态库(btctrler、btstack、media等.a文件)形式提供底层能力,头文件集中在include_lib/。SDK Release 版本不开放协议栈源码,这一设计隔离了底层实现,同时通过头文件保持接口稳定。 - 构建与工具层:顶层
Makefile作为统一编译入口,把 target 映射到各板级目录的Makefile;同时支持 Code::Blocks(Windows 推荐)与 VS Code 两种 IDE 编译方式。
目录分层详解
仓库根目录的工程结构如下(摘自 README.md 第五节):
fw-AC63_BT_SDK/
├── apps/ # 应用层代码
│ ├── common/ # 公共模块(跨工程共享)
│ │ ├── audio/ # 音频编解码、音量控制
│ │ ├── bt_common/ # 蓝牙通用接口
│ │ ├── cJSON/ # JSON 解析库
│ │ ├── debug/ # 调试工具
│ │ ├── device/ # 外设驱动(按键、USB、传感器等)
│ │ ├── jl_kws/ # 杰理关键词唤醒
│ │ ├── music/ # 音乐播放
│ │ ├── update/ # 固件升级
│ │ └── third_party_profile/ # 第三方协议(SigMesh、涂鸦、腾讯连连、HiLink)
│ ├── spp_and_le/ # 📌 SPP + BLE 应用
│ ├── hid/ # 📌 HID 应用(键盘/鼠标/遥控器/游戏手柄)
│ └── mesh/ # 📌 Mesh 应用
├── cpu/ # CPU 相关代码与库文件
│ ├── bd19/ → br34/ # 各芯片平台的 lib.a 库文件 + 工具脚本
│ └── br34/
├── include_lib/ # 头文件(bt协议栈、驱动、媒体、系统等)
├── doc/ # 文档资源
│ ├── datasheet/ # 芯片数据手册
│ ├── architure/ # SDK 架构文档
│ ├── FAQ/ # 常见问题
│ └── .../
├── tools/ # 编译工具与脚本
│ └── make_prompt.bat # Windows 编译命令行入口
├── Makefile # 顶层 Makefile(统一编译入口)
├── default.workspace # Code::Blocks 工作空间
└── .vscode/ # VS Code 配置(tasks.json 预定义编译任务)
来源:README.md
apps/ — 应用层
apps/ 是开发者日常接触最多的目录,包含三个应用工程与一个公共模块集合:
| 子目录 | 职责 | 典型内容 |
|---|---|---|
apps/common/ | 跨工程共享的公共模块 | 音频(audio/)、蓝牙通用接口(bt_common/)、设备驱动(device/,含 adkey/iokey/irkey/触摸按键等)、cJSON、debug、jl_kws、music、update、third_party_profile |
apps/spp_and_le/ | SPP + BLE 透传/数传应用 | app_main.c(应用入口)、version.c(版本号)、board/、examples/ |
apps/hid/ | HID 人机交互设备应用 | 鼠标/键盘/游戏手柄/语音遥控器等示例 |
apps/mesh/ | Bluetooth Mesh 物联应用 | 智能照明、传感器网络示例 |
以 apps/spp_and_le/ 为例,应用目录内包含 app_main.c(主入口)与 version.c(版本信息),其业务代码通过调用 apps/common/ 中的公共模块实现功能。这种"入口薄、复用厚"的结构降低了各应用工程的维护成本。
apps/common/ — 公共模块层的代码风格
公共模块采用标准 C 语言编写,每个源文件头部带注释说明模块用途与接口约定。例如 audio_utils.c 是"数字信号处理常用模块合集",其中包含数字反相器等 DSP 工具函数:
/*
************************************************************
* Audio Utils
* 数字信号处理常用模块合集
*
************************************************************
*/
#include "audio_utils.h"
/*
*********************************************************************
* Audio Digital Phase Inverter
* Description: 数字反相器,用来反转数字音频信号的相位
* Arguments : dat 数据buf地址
* len 数据长度(unit:byte)
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void digital_phase_inverter_s16(s16 *dat, int len)
{
for (int i = 0; i < len / 2; i++) {
dat[i] = (dat[i] == -32768) ? 32767 : -dat[i];
/* dat[i] = -1 - dat[i]; */
}
}
这段代码体现了公共模块的两点设计约定:每个文件有明确的模块归属注释(便于快速定位功能归属),每个函数有参数/返回值/注意事项注释(因为公共模块被多个工程引用,接口文档必须内联在源码中)。函数对 -32768 的特殊处理(翻转为 32767 而非 +32768)是定点音频处理的经典边界防护——s16 正数域无法表示 32768。
板级配置目录 apps/*/board/
每个应用目录下都有 board/ 子目录,按芯片平台划分(示例为 apps/hid/board/):
apps/hid/board/
├── bd19/ # AC632N 系列 (32个板级配置)
├── br23/ # AC635N 系列
├── br25/ # AC636N 系列
└── br34/ # AC638N 系列
每个板级目录包含四类文件:
| 文件 | 作用 |
|---|---|
Makefile | 板级编译脚本(顶层 Makefile 递归调用的目标) |
board_*.cbp | Code::Blocks 工程文件(Windows 下双击编译) |
board_xxx.c | 板级初始化代码(引脚、外设初始化) |
board_xxx_cfg.h | 板级配置(引脚定义、外设参数) |
board_xxx_global_build_cfg.h | 全局编译配置(功能开关) |
来源:README.md
cpu/ 与 include_lib/ — 平台库层
| 目录 | 内容 | 说明 |
|---|---|---|
cpu/{bd19,br23,br25,br34,...}/liba/ | 预编译静态库 *.a | btctrler(蓝牙控制器)、btstack(协议栈)、media(媒体)等 |
cpu/*/tools/ | 烧录工具 | download.bat、fw_add.exe、isd_download.exe 等 |
include_lib/ | 头文件 | 蓝牙协议栈、驱动、媒体、系统的公开接口 |
设计意图:库文件按芯片平台隔离在 cpu/ 下,头文件统一收敛在 include_lib/,实现了"接口与实现分离"。上层应用只依赖头文件编译,链接时按 target 选择的平台注入对应的 .a 库——这正是"一个 SDK 支持多芯片"在二进制层面的支撑。
tools/ 与 doc/ — 工具与文档
tools/make_prompt.bat:Windows 下打开带编译环境的命令行窗口;doc/:包含芯片数据手册(datasheet/)、SDK 架构文档(architure/)、FAQ 等资源。
构建体系与编译流程
编译 target 命名规则
顶层 Makefile 是统一编译入口,其支持的目标即"芯片 × 应用"矩阵:
| target 前缀(芯片型号) | 映射平台目录 | 应用后缀 |
|---|---|---|
ac632n | apps/*/board/bd19 | _spp_and_le / _hid / _mesh |
ac631n | apps/*/board/bd29 | _spp_and_le / _hid / _mesh |
ac636n | apps/*/board/br25 | _spp_and_le / _hid / _mesh |
ac637n | apps/*/board/br30 | _spp_and_le / _hid / _mesh |
ac635n | apps/*/board/br23 | _spp_and_le / _hid / _mesh |
ac638n | apps/*/board/br34 | _spp_and_le / _hid / _mesh |
来源:Makefile
顶层 Makefile 的递归委托机制
顶层 Makefile 本身不含任何编译规则,只负责把 target 委托给对应板级目录的 Makefile($(MAKE) -C ... 递归调用)。例如 ac632n_spp_and_le 与 ac638n_mesh 的定义:
ac632n_spp_and_le:
$(MAKE) -C apps/spp_and_le/board/bd19 -f Makefile
clean_ac632n_spp_and_le:
$(MAKE) -C apps/spp_and_le/board/bd19 -f Makefile clean
来源:Makefile
ac638n_mesh:
$(MAKE) -C apps/mesh/board/br34 -f Makefile
clean_ac638n_mesh:
$(MAKE) -C apps/mesh/board/br34 -f Makefile clean
来源:Makefile
这种"顶层薄委托 + 板级全量规则"的设计使新增芯片或新增板级配置时只需在顶层追加一个 target 别名,所有真实构建逻辑(源文件收集、库链接、固件打包)都留在板级 Makefile 中,避免了顶层规则膨胀。
编译流程
flowchart TD
START([开发者执行 make ac632n_spp_and_le]) --> ROOT["顶层 Makefile<br/>解析 target 名称"]
ROOT --> MAP{"芯片型号 → 平台目录映射"}
MAP -->|"ac632n → bd19"| RECURSE["$(MAKE) -C apps/spp_and_le/board/bd19"]
RECURSE --> BOARD_MK["板级 Makefile<br/>收集源码 + 链接 lib.a"]
BOARD_MK --> LIBA["cpu/bd19/liba/ 预编译库"]
BOARD_MK --> INCLUDE["include_lib/ 头文件"]
LIBA --> LINK["编译链接生成固件"]
INCLUDE --> LINK
LINK --> HEX["输出 .hex 固件文件"]
HEX --> FLASH["USB 升级工具/生产烧写工具烧录"]
FLASH --> HW2["目标芯片"]
BOARD_MK -.->|"clean 目标"| CLEAN["清理编译产物"]
各步骤说明:
- 开发者执行
make ac632n_spp_and_le(或make ac632n_hid等任一 target); - 顶层
Makefile通过 target 名确定芯片型号与应用组合,查表映射到平台目录; - 递归调用板级
Makefile,由它完成真正的源码收集、预编译库链接与固件打包; - 链接时依赖
cpu/*/liba/的.a静态库与include_lib/的头文件; - 产物
.hex位于对应 board 目录,通过 USB 升级工具或生产烧写工具烧录到芯片。
编译完成后,Code::Blocks 用户可直接双击 board_*.cbp 工程文件构建;Linux 用户在 SDK 根目录执行 make {target} 即可。仓库还预配置了 VS Code 任务(.vscode/tasks.json),按 Ctrl+Shift+B 可选择编译目标。
Usage Examples
示例一:选择工程并编译(命令行方式)
按产品需求选择应用工程,然后编译对应 target:
# 进入 SDK 根目录
cd fw-AC63_BT_SDK
# 编译完整工程(示例:AC632N 的 SPP+BLE 工程)
make ac632n_spp_and_le
# 编译完成后,在对应 board 目录下找到生成的 .hex 文件
# 清理该工程的编译产物
make clean_ac632n_spp_and_le
示例二:查看所有可用编译目标
顶层 Makefile 开头的注释列出了全部受支持的 target,并给出了 Linux 环境的前置要求:
# 总的 Makefile,用于调用目录下各个子工程对应的 Makefile
# 注意: Linux 下编译方式:
# 1. 从 http://pkgman.jieliapp.com/doc/all 处找到下载链接
# 2. 下载后,解压到 /opt/jieli 目录下,保证
# /opt/jieli/common/bin/clang 存在(注意目录层次)
# 3. 确认 ulimit -n 的结果足够大(建议大于8096),否则链接可能会因为打开文件太多而失败
# 可以通过 ulimit -n 8096 来设置一个较大的值
# 支持的目标
# make ac638n_spp_and_le
# make ac632n_spp_and_le
# make ac631n_spp_and_le
# make ac636n_spp_and_le
# make ac637n_spp_and_le
# make ac635n_spp_and_le
# make ac638n_hid
# make ac632n_hid
# ...
来源:Makefile
示例三:Windows 下使用 Code::Blocks 编译
# 1. 进入对应的板级目录
cd apps/hid/board/bd19/
# 2. 双击打开 .cbp 工程文件(如 AC632N_hid.cbp)
# 3. 在 Code::Blocks 中点击 Build → Build (Ctrl+F9)
# 4. 编译成功后,使用 USB 升级工具烧录生成的 .hex 文件
来源:README.md
示例四:在公共模块层新增 DSP 工具函数
开发者若需扩展音频处理能力,可在 apps/common/audio/ 下仿照既有函数风格新增实现,接口头文件同步声明,三个应用工程即可共享:
void digital_phase_inverter_s16(s16 *dat, int len)
{
for (int i = 0; i < len / 2; i++) {
dat[i] = (dat[i] == -32768) ? 32767 : -dat[i];
/* dat[i] = -1 - dat[i]; */
}
}
Configuration Options
SDK 的配置分布在两个层面,均为编译期配置(修改后需重新编译):
板级配置(apps/*/board/ 目录)
| 配置文件 | 类型 | 作用 |
|---|---|---|
board_xxx_cfg.h | 引脚/外设配置 | 定义引脚复用、外设参数(I/O、SPI、I2C、UART 等) |
board_xxx_global_build_cfg.h | 功能开关 | 全局编译配置,决定哪些功能编译进固件 |
board_xxx.c | 初始化代码 | 板级初始化逻辑,调用配置头文件中的宏 |
Makefile | 编译选项 | 源文件列表、编译宏、链接选项 |
board_*.cbp | IDE 工程 | Code::Blocks 工程,与 Makefile 等价 |
库功能裁剪配置(apps/*/config/)
| 配置项 | 说明 |
|---|---|
| 模块裁剪配置 | 决定编译哪些库功能(蓝牙协议栈特性、媒体功能等),影响固件体积与 RAM 占用 |
编译环境配置
| 配置项 | 默认值 | 说明 |
|---|---|---|
| 工具链路径 | /opt/jieli/common/bin/clang(Linux) | 杰理编译工具链,需保证该路径存在 |
| 文件描述符上限 | ulimit -n > 8096(建议) | 链接阶段打开文件数较多,不足会导致链接失败 |
| Windows 编译环境 | tools/make_prompt.bat | 双击打开带工具链环境的命令行 |
Failure Modes, Edge Cases & Concurrency
编译环境的常见失败模式
| 失败现象 | 根因 | 处理方式 |
|---|---|---|
| 链接报"打开文件太多" | ulimit -n 过小(Makefile 注释建议 >8096) | 执行 ulimit -n 8096 后再编译 |
clang 命令找不到 | 工具链未安装或目录层级不对 | 解压工具链到 /opt/jieli,确保 /opt/jieli/common/bin/clang 存在 |
找不到 lib.a | target 与平台目录映射错误 | 核对 target 命名 ac{芯片型号}_{应用名} 与平台目录对应关系 |
| 固件功能与预期不符 | 板级 global_build_cfg.h 功能开关未开启 | 检查板级配置头文件中的功能宏 |
来源:Makefile
分层引入的边界约束
- 二进制接口约束:
include_lib/头文件是应用与预编译库之间的唯一契约。SDK Release 不提供协议栈源码,因此不能修改库内部行为,只能通过头文件暴露的接口与config/裁剪配置来调整功能; - 并发/线程模型:SDK 基于 Zephyr RTOS,应用层与协议栈运行在不同任务上下文中。公共模块(如
apps/common/中的音频、设备驱动)被多个应用共享,新增代码需遵循 Zephyr 的线程安全约定(如使用消息队列/信号量而非裸全局变量跨任务通信)——这是扩展公共模块时的隐性约束。
Performance & Operational Notes
- 固件体积控制:通过
apps/*/config/的模块裁剪配置按需编译,避免默认全量编译导致固件超限; - 编译效率:顶层
Makefile采用递归委托,单板级目录可独立增量编译,make clean_{target}可单独清理某个工程,避免全量清理; - 多 target 并行:
make all会依次编译所有支持的 target(约 18 个),适用于 CI 全量验证,日常开发建议只编译目标 target 以节省时间。
Extension Points
SDK 的分层设计提供了三条明确的扩展路径:
- 新增板级配置(最常用):在
apps/{应用}/board/{平台}/下复制一个既有板级目录,修改board_xxx_cfg.h(引脚/外设)与board_xxx_global_build_cfg.h(功能开关)即可得到新产品固件,无需改动 SDK 主体; - 新增公共模块:在
apps/common/下新增子目录(如新的传感器驱动),遵循"文件头模块注释 + 函数接口注释"的代码风格,三个应用工程均可引用; - 新增编译 target:在顶层
Makefile追加形如ac{芯片型号}_{应用}: $(MAKE) -C apps/{应用}/board/{平台} -f Makefile的规则,即可扩展"芯片 × 应用"矩阵。
Related Links
- README.md(仓库总览与快速开始)
- Makefile(编译 target 定义)
- apps/common/audio/audio_utils.c(公共模块代码示例)
- 杰理 AC63 文档中心
- 相关目录:
apps/spp_and_le/(SPP+BLE 应用)、apps/hid/(HID 应用)、apps/mesh/(Mesh 应用)