编译指南与工程选择
本页面是 fw-AW33N_BLE_SDK 的编译与工程选择参考:说明如何根据产品形态选择正确的应用工程(TRANSFER / HID)与板级配置(bd57),如何在 Windows / Linux / VS Code 三种环境下完成编译,以及顶层 Makefile 的 target 体系、产物定位、功能裁剪配置与常见编译错误的处理方法。
Purpose and Scope
本文档面向需要开始 AW33N 系列蓝牙产品开发的工程师,覆盖从选工程 → 搭环境 → 编译 → 找产物 → 烧录的完整链路:
- 工程选择:TRANSFER 与 HID 两个应用工程的区别与适用场景,
apps/demo/*/board/bd57板级目录的选取原则; - 编译环境:杰理编译工具链的安装、Windows(Code::Blocks / make_prompt.bat)、Linux(Makefile)、VS Code 三种编译方式的入口;
- 编译体系:顶层 Makefile 如何递归调用各板级子工程,
make的 target 一览与清理策略; - 配置与裁剪:
config/目录下的lib_*_config.c功能裁剪文件、board_xxx_cfg.h板级配置与board_xxx_global_build_cfg.h全局编译开关; - 产物与烧录:
.hex固件产物的定位、isd_download.exe首次烧录流程。
以下内容不在本页范围,将由其他目录页覆盖:蓝牙协议栈与 HID/TRANSFER 的模块级开发细节(参见 HID 开发文档 / TRANSFER 开发文档)、OTA 升级机制(参见烧录与升级相关页面)、SDK 模块架构总览(参见工程结构页面)。
Overview
fw-AW33N_BLE_SDK 是杰理科技为 AW33N 系列芯片提供的通用蓝牙 SDK 固件开发包,基于裸机操作系统,内置完整的 BLE 协议栈。仓库发布的是 Release 版本代码与示例工程,本身不携带全部二进制依赖——编译时需要配合按命名规则发布的库文件(lib.a)与子仓库一起工作(见 README.md)。
SDK 覆盖两类应用形态:
| 应用类型 | 典型产品 |
|---|---|
| BLE 透传/数传 | 透传、数据传输、扫描设备、广播设备、适配器、AT 模组、定位器(Findmy & Find Hub)等 |
| HID 人机交互 | 媒体播放控制、遥控器、自拍器、翻页器、3 模鼠标(2.4G/USB 支持到 1K 回报率)等 |
芯片平台方面,当前仓库仅支持 bd57 一个平台,对应芯片型号为 AW332A / AW333A / AW336A / AW336A0 / AW338A(见 README.md)。蓝牙协议栈已通过 Core v5.4 认证(QDID: DN:Q332415)。
编译链路的本质是两层 Makefile 委托:顶层 Makefile 只负责把 make <target> 翻译成对 apps/demo/<app>/board/bd57/Makefile 的递归调用;真正的编译、链接动作发生在板级子工程中,依赖杰理 clang 工具链,最终产出 .hex 固件文件。理解这一委托关系是排查编译问题的基础。
Architecture
下图展示了从产品需求到固件产物的完整编译架构。顶层 Makefile 是统一入口,它通过 -C 参数递归进入板级子工程;板级子工程内部同时承载了 Code::Blocks(.cbp)工程与 Makefile 两套构建描述,二者共享同一套板级源码与配置头文件。
flowchart TD
subgraph sg_Product["产品需求层"]
Req["产品形态:透传 / HID 设备"]
end
subgraph sg_Select["工程选择层"]
AppTransfer["apps/demo/transfer(TRANSFER 应用)"]
AppHid["apps/demo/hid(HID 应用)"]
Board["board/bd57(板级目录)"]
end
subgraph sg_Build["编译入口层"]
TopMake["顶层 Makefile(统一入口)"]
CbProject["board_*.cbp(Code::Blocks 工程)"]
VscodeTask[".vscode/tasks.json(VS Code 任务)"]
MakePrompt["tools/make_prompt.bat(Windows 命令行)"]
end
subgraph sg_Toolchain["工具链层"]
Clang["杰理编译工具链<br/>/opt/jieli/common/bin/clang"]
BoardMake["板级 Makefile(递归调用)"]
Config["config/ 功能裁剪<br/>board_*_cfg.h 板级配置"]
LibA["预编译库 lib.a<br/>apps/include_lib/liba/bd**/flash"]
end
subgraph sg_Output["产物层"]
Hex[".hex 固件文件"]
Download["烧录工具 isd_download.exe"]
end
Req --> AppTransfer
Req --> AppHid
AppTransfer --> Board
AppHid --> Board
Board --> CbProject
Board --> TopMake
Board --> BoardMake
TopMake --> BoardMake
MakePrompt --> BoardMake
VscodeTask --> TopMake
BoardMake --> Clang
BoardMake --> Config
BoardMake --> LibA
Clang --> Hex
Hex --> Download
架构要点说明:
- 顶层 Makefile 是唯一推荐的命令行入口:所有 target(
aw33n_transfer/aw33n_hid/all/clean)都在根目录 Makefile 中定义,内部通过$(MAKE) -C <板级目录> -f Makefile委托执行,因此无论编译哪个应用,命令都固定在 SDK 根目录发出。 - 板级目录同时是工程选择的落点:
apps/demo/<app>/board/bd57/下同时存在Makefile、board_*.cbp、board_xxx.c、board_xxx_cfg.h、board_xxx_global_build_cfg.h(见 README.md),Code::Blocks 与命令行编译共享同一套配置,保证两种方式产物一致。 - 工具链是编译的外部依赖:Linux 下要求
/opt/jieli/common/bin/clang存在(见 Makefile);Windows 下通过tools/make_prompt.bat注入utils目录到PATH,从而获得预配置的make环境(见 tools/make_prompt.bat)。 - 预编译库与裁剪配置共同决定固件内容:
lib.a静态库提供协议栈/驱动/CPU 二进制,config/下的lib_*_config.c决定链接哪些模块,二者不匹配时会出现undefined reference类错误(见 README.md)。
工程选择指南
选择正确工程是编译成功的前提。SDK 将工程选择拆成两层:应用层(做什么产品)与板级层(跑在哪块板子上)。
应用层选择:TRANSFER 与 HID
SDK 根目录下仅有两个应用工程(见 README.md):
SDK 根目录
├── apps/demo/transfer # BLE 透传/数传等应用
└── apps/demo/hid/ # HID 人机交互设备等应用
| 维度 | TRANSFER(apps/demo/transfer) | HID(apps/demo/hid) |
|---|---|---|
| 适用场景 | 透传、数据传输、扫描设备、广播设备、适配器、AT 模组、定位器(Findmy & Find Hub) | 媒体播放控制、遥控器、自拍器、翻页器、3 模鼠标 |
| 关键特性 | 透传、数据传输、支持 AT 指令控制、接入第三方定位器 | 通用 HID、3 模鼠标、高回报率(2.4G/USB 1K) |
| 参考文档 | TRANSFER 开发文档 | HID 开发文档 |
选择依据(设计意图):两个工程共享同一套
apps/app/bsp/common公共模块与协议栈库,差异体现在examples/示例代码与config/裁剪配置上。HID 工程为键盘/鼠标类设备预置了高回报率与 3 模切换逻辑;TRANSFER 工程预置了透传通道与 AT 指令解析。不要跨应用混用 examples 代码,否则裁剪配置与库功能不匹配。
板级层选择:bd57 板级目录
每个应用目录下的 board/ 子目录按芯片平台划分(见 README.md):
apps/demo/hid/board/
└── bd57/ # AW33N 系列(3 个产品应用和 1 个 demo 板级配置)
当前 Release 版本仅发布 bd57 平台,对应芯片型号 AW332A / AW333A / AW336A / AW336A0 / AW338A。每个芯片目录内的文件分工:
| 文件 | 作用 |
|---|---|
Makefile | 命令行编译脚本(顶层 Makefile 递归调用它) |
board_*.cbp | Code::Blocks 工程文件(Windows IDE 编译入口) |
board_xxx.c | 板级初始化代码 |
board_xxx_cfg.h | 板级配置(引脚、外设、时钟) |
board_xxx_global_build_cfg.h | 全局编译配置(功能开关、内存配置) |
自定义板卡的推荐做法(来自官方 FAQ,见 README.md):复制与自身硬件最接近的板级目录,然后修改 board_xxx_cfg.h 中的引脚与外设配置即可,不要从零创建工程。
工程选择决策流程
flowchart TD
Start([开始]) --> Q1{"产品形态?"}
Q1 -->|"透传/数传/AT 模组/定位器"| AppT["apps/demo/transfer"]
Q1 -->|"键盘/鼠标/遥控器/自拍器"| AppH["apps/demo/hid"]
AppT --> Q2{"芯片型号?"}
AppH --> Q2
Q2 -->|"AW332A/AW333A/AW336A/AW336A0/AW338A"| Bd["board/bd57"]
Bd --> Q3{"编译环境?"}
Q3 -->|"Windows + IDE"| CB["打开 .cbp,Code::Blocks 编译"]
Q3 -->|"Windows + 命令行"| MP["双击 tools/make_prompt.bat"]
Q3 -->|"Linux/macOS"| MK["根目录 make <target>"]
Q3 -->|"VS Code"| VS["Ctrl+Shift+B 选择任务"]
CB --> Out[".hex 产物"]
MP --> MK
MK --> Out
VS --> Out
编译环境搭建
工具链安装(两种平台)
| 系统 | 方式 | 关键要求 |
|---|---|---|
| Windows | 安装杰理编译工具链(下载链接),配合 Code::Blocks IDE | 使用 tools/make_prompt.bat 进入预配置命令行,脚本会自动把 utils 目录加入 PATH(见 tools/make_prompt.bat) |
| Linux | 从 pkgman.jieliapp.com 下载工具链,解压到 /opt/jieli | 必须保证 /opt/jieli/common/bin/clang 存在(目录层次敏感,见 Makefile) |
安装后验证:
# 验证工具链是否安装成功
clang --version
设计意图(为什么是
/opt/jieli):板级 Makefile 通过约定路径定位 clang 工具链,路径一旦变化会导致clang: command not found。Windows 下make_prompt.bat通过SET SCRIPT_PATH=%~dp0%\取得脚本自身所在目录,再以相对方式追加utils并cd ..回到 SDK 根目录(见 tools/make_prompt.bat),因此该脚本必须从tools/目录双击运行,移动位置会破坏相对路径。
Linux 编译前置条件
链接阶段需要打开大量文件,若文件描述符限制过小会报 Too many open files(见 Makefile):
# 确保文件描述符限制足够大(建议大于 8096)
ulimit -n 8096
烧录工具准备
| 工具 | 用途 | 获取方式 |
|---|---|---|
| USB 升级工具(isd_download.exe) | 将固件烧录到目标板 | 申请链接 · 使用文档 |
| 生产烧写工具 | 量产/裸片烧写 | 使用文档 |
| 无线测试盒 | 空中升级/射频标定/产品测试 | 申请链接 · 使用文档 |
编译体系:顶层 Makefile 详解
顶层 Makefile 是全部命令行编译的枢纽,全文如下:
# 总的 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 aw33n_transfer
# make aw33n_hid
.PHONY: all clean aw33n_transfer aw33n_hid clean_aw33n_transfer clean_aw33n_hid
all: aw33n_transfer aw33n_hid
@echo +ALL DONE
clean: clean_aw33n_transfer clean_aw33n_hid
@echo +CLEAN DONE
aw33n_transfer:
$(MAKE) -C apps/demo/transfer/board/bd57 -f Makefile
clean_aw33n_transfer:
$(MAKE) -C apps/demo/transfer/board/bd57 -f Makefile clean
aw33n_hid:
$(MAKE) -C apps/demo/hid/board/bd57 -f Makefile
clean_aw33n_hid:
$(MAKE) -C apps/demo/hid/board/bd57 -f Makefile clean
Source: Makefile
逐段解读(设计意图):
.PHONY声明:六个 target(all、clean、aw33n_transfer、aw33n_hid、clean_aw33n_transfer、clean_aw33n_hid)全部声明为伪目标,避免目录下同名文件干扰 make 的依赖判断;- 聚合 target:
all依赖两个应用 target,clean依赖两个清理 target——这是"统一入口、分而治之"的典型 make 委托模式; -C递归:$(MAKE) -C <dir> -f Makefile让 make 切换工作目录后读取该目录下的 Makefile。这意味着编译动作真正发生在板级子工程,顶层只是"翻译官";- 命名约定:
<app>_<platform>(如aw33n_hid)与clean_<app>_<platform>一一对应,后续新增应用/平台只需在此追加两行委托,扩展成本极低。
编译命令速查表
以下命令统一在 SDK 根目录执行(见 README.md):
| 目标 | 芯片 | 应用 | 命令 | 说明 |
|---|---|---|---|---|
| AW33N | bd57 | transfer | make aw33n_transfer | 编译透传应用 |
| AW33N | bd57 | hid | make aw33n_hid | 编译 HID 应用 |
| 全部 | 全部 | 全部 | make all | 依次编译两个应用 |
| 全部 | 全部 | 全部 | make clean | 清理全部编译产物 |
| — | — | transfer | make clean_aw33n_transfer | 仅清理透传产物 |
| — | — | hid | make clean_aw33n_hid | 仅清理 HID 产物 |
三种编译入口对比
| 方式 | 适用平台 | 入口 | 特点 |
|---|---|---|---|
| Code::Blocks | Windows(推荐) | 双击 board_*.cbp → Build → Build (Ctrl+F9) | 图形化、断点调试方便;先 cd apps/demo/hid/board/bd57/ 再打开工程 |
| Makefile 命令行 | Linux / macOS / Windows | 根目录 make <target>;Windows 先双击 tools/make_prompt.bat | 可并行(-j)、可脚本化、CI 友好 |
| VS Code | 跨平台 | Ctrl+Shift+B 选择预配置任务 | 仓库已内置 .vscode/tasks.json,无需手写编译命令 |
核心编译流程
一次完整的 make aw33n_hid 调用在系统内部按如下顺序展开:
sequenceDiagram
participant Dev as 开发者
participant Top as 顶层 Makefile
participant Sub as 板级 Makefile (bd57)
participant Tool as 杰理 clang 工具链
participant Cfg as config/ + board_*_cfg.h
participant Lib as lib.a 预编译库
participant Out as .hex 产物
Dev->>Top: make aw33n_hid(SDK 根目录)
activate Top
Top->>Sub: $(MAKE) -C apps/demo/hid/board/bd57
deactivate Top
activate Sub
Sub->>Cfg: 读取功能裁剪与板级配置
Cfg-->>Sub: 宏定义/裁剪清单
Sub->>Tool: 编译 .c 源码(clang)
Tool-->>Sub: 目标文件 .o
Sub->>Lib: 链接预编译静态库
Lib-->>Sub: 协议栈/驱动/CPU 符号
Sub->>Sub: 生成固件并校验
Sub-->>Out: 输出 .hex
deactivate Sub
Dev->>Out: 在 board 目录定位 .hex
流程要点:
- 配置先行:板级 Makefile 在编译前先解析
config/下的lib_*_config.c(决定链接哪些库模块)与board_*_cfg.h(决定引脚、外设、内存布局),这些宏通过编译参数注入所有源文件; - 编译 + 链接分离:源码先由 clang 编译为目标文件,再与
apps/include_lib/liba/*/flash下的lib.a静态库链接。cannot find -lxxx与undefined reference两类错误分别对应"库缺失"与"裁剪配置漏模块"; - 产物定位:编译完成后
.hex文件生成在对应 board 目录下(如apps/demo/hid/board/bd57/),README 与顶层 Makefile 注释均明确此约定(见 README.md)。
并行编译
# Linux 下按 CPU 核数并行,显著缩短编译时间
make aw33n_transfer -j`nproc`
# Windows 下指定并行度
make aw33n_transfer -j4
-j 参数作用于顶层委托的递归 make,子工程同样受益;但需注意文件描述符限制(Linux 下 ulimit -n 8096),否则并行链接时更易触发 Too many open files。
配置与裁剪:影响编译结果的关键文件
编译产物(固件体积与功能集合)由三类配置文件决定,均位于应用工程目录内(见 README.md)。
功能裁剪配置(config/ 目录)
每个应用工程的 config/ 目录下按模块划分裁剪文件,例如 HID 工程:
apps/demo/hid/config/
├── lib_btctrler_config.c # 蓝牙控制器配置
├── lib_btstack_config.c # 蓝牙协议栈配置
├── lib_driver_config.c # 驱动模块配置
├── lib_profile_config.c # 蓝牙 Profile 配置
├── lib_system_config.c # 系统模块配置
├── lib_update_config.c # 升级模块配置
└── log_config.c # 日志输出配置
| 配置文件 | 控制内容 | 裁剪不当的后果 |
|---|---|---|
lib_btctrler_config.c | 蓝牙链路层/控制器功能 | 链接报 undefined reference |
lib_btstack_config.c | 蓝牙协议栈(GAP/GATT 等) | 协议行为异常或链接失败 |
lib_driver_config.c | UART/SPI/I2C/GPIO 等驱动模块 | 外设不可用 |
lib_profile_config.c | Profile 功能(HID/透传等) | 对应 Profile 无法注册 |
lib_system_config.c | 系统任务、内存池 | 资源不足或启动异常 |
lib_update_config.c | 升级模块 | OTA 不可用 |
log_config.c | 日志输出等级与通道 | 日志缺失或过多 |
设计意图:SDK 采用编译期裁剪而非运行时开关——裁剪文件决定哪些模块参与链接,从根上控制 ROM/RAM 占用。修改裁剪配置后必须重新完整编译,仅增量编译可能残留旧模块符号。
板级配置(board_xxx_cfg.h 与 board_xxx_global_build_cfg.h)
| 头文件 | 内容 | 典型修改场景 |
|---|---|---|
board_xxx_cfg.h | 引脚映射(UART/SPI/I2C/GPIO)、外设使能、时钟配置(CPU 频率、外设时钟源) | 换板子/换引脚时必改 |
board_xxx_global_build_cfg.h | 功能开关(按需启用/禁用)、内存配置(堆栈大小、缓冲池大小) | 调内存布局、裁剪功能时改 |
新建自定义板卡时,复制最接近的板级目录并修改上述两个头文件即可(官方 FAQ 推荐做法,见 README.md)。
烧录与升级
首次烧录流程
- 连接硬件:开发板通过 USB 或 UART 连接 PC;
- 进入编程模式:按住烧录按键,复位或重新上电;
- 打开 USB 升级工具:启动
isd_download.exe; - 选择固件:选择编译生成的
.hex文件; - 开始烧录:点击下载,等待完成。
⚠️ 烧录前确保工具正确连接且目标板已进入编程模式。下载脚本的 INI 配置位于
apps/app/post_build/bd**/flash/isd_config_ini.c,详见下载脚本配置文档(见 README.md)。
OTA 升级
支持单备份与双备份蓝牙 OTA 升级,机制细节参见 OTA 开发文档——本页聚焦编译与工程选择,OTA 的协议与分区细节属于升级模块页面范畴。
失败模式与常见错误
编译错误速查表
| 错误提示 | 根因 | 解决方法 |
|---|---|---|
clang: command not found | 未安装杰理工具链,或 /opt/jieli/common/bin 未在 PATH / 目录层次不对 | 安装工具链;Linux 下确认 /opt/jieli/common/bin/clang 存在(见 Makefile) |
Too many open files | Linux 文件描述符限制过小,链接阶段打开文件过多 | ulimit -n 8096(见 Makefile) |
cannot find -lxxx | 缺少对应 .a 库文件 | 检查 apps/include_lib/liba/*/flash 目录是否存在该库 |
undefined reference to ... | 功能裁剪配置未包含对应模块 | 检查 lib_*_config.c 是否启用对应模块(见 README.md) |
Windows 下 make 不是有效命令 | 未进入预配置命令行环境 | 双击 tools/make_prompt.bat 启动(自动配置 PATH,见 tools/make_prompt.bat) |
边界情况与注意事项
- 根目录执行约束:所有
make命令必须在 SDK 根目录执行——顶层 Makefile 的-C委托依赖相对路径,从其他目录执行会因找不到apps/demo/*/board/bd57而失败; make_prompt.bat位置敏感:脚本用%~dp0%取自身目录并cd ..,必须保持位于tools/下运行;- 全量 vs 增量:修改
config/裁剪文件后建议先make clean_<target>再编译,避免增量编译残留旧符号导致链接错误; - 并行度与文件描述符:
-j并行越高,链接期同时打开的文件越多,Linux 下务必先提高ulimit -n; - 跨平台产物差异:Code::Blocks 与 Makefile 共享同一套板级配置与源码,产物行为一致;但工程文件(
.cbp)与命令行 Makefile 是两套构建描述,修改构建参数时需两边同步。
性能与操作注意事项
- 并行编译:
make aw33n_transfer -j4或-jnproc`` 可成倍缩短编译时间(见 README.md); - 固件体积控制:通过
config/裁剪未用模块是减小固件的首要手段,优先裁剪lib_*_config.c中的可选 Profile 与驱动; - 日志分级:
log_config.c控制输出等级与通道,量产固件建议调低日志等级以节省 RAM 与串口带宽; - 重复构建的确定性:
make clean与单工程清理(clean_aw33n_transfer/clean_aw33n_hid)可确保从零构建,适合 CI 流水线使用。
扩展点
- 新增产品应用:在
apps/demo/下复制现有应用目录,修改 examples 与 config;如需独立 target,在顶层 Makefile 追加.PHONY声明与委托规则; - 新增板卡:复制
board/bd57/下最接近的板级目录,修改board_xxx_cfg.h引脚/外设与board_xxx_global_build_cfg.h功能开关; - 新增芯片平台:在
cpu/下创建平台目录并提供liba/库文件与tools/烧录工具,再在apps/demo/*/board/下添加对应板级目录(见 README.md); - 自定义构建任务:仓库已内置
.vscode/tasks.json,可仿照现有任务添加新的编译/清理任务(VS CodeCtrl+Shift+B)。
Related Links
- README.md(仓库总览与快速开始)
- Makefile(顶层编译入口)
- tools/make_prompt.bat(Windows 编译命令行)
- 工程结构(SDK 目录布局详解)
- HID 开发文档
- TRANSFER 开发文档
- OTA 开发文档
- SDK 在线文档中心
编译产物验证与调试
编译成功并不等于功能正确,建议按以下顺序验证(对应 README 调试技巧,见 README.md):
- 确认产物存在:在对应 board 目录(如
apps/demo/hid/board/bd57/)找到生成的.hex文件; - 烧录冒烟测试:用
isd_download.exe烧录后,观察系统是否正常启动、蓝牙是否可被发现/连接; - 串口日志:通过
config/log_config.c配置日志输出等级与通道,用串口抓取系统运行日志定位初始化失败或异常复位; - GPIO 波形测量:利用空闲 GPIO 输出调试波形测量时序,适合排查外设时序类问题(如 I2C/SPI 通信);
- 更多问题:查阅 Gitee Issues 或加入钉钉群
90400000565交流。
常见 FAQ 摘要
| 问题 | 答案 |
|---|---|
| 如何创建自己的工程? | 复制最接近的板级目录,修改 board_xxx_cfg.h 引脚与外设配置(见 README.md) |
| 如何添加新的芯片型号支持? | 在 cpu/ 下创建平台目录,提供 liba/ 库与 tools/ 烧录工具,再添加对应板级目录 |
Windows 下 make 报错? | 使用 tools/make_prompt.bat 进入预配置命令行环境(见 tools/make_prompt.bat) |
| 如何加快编译速度? | 使用 -j 并行编译,如 make aw33n_transfer -j4 |