杰理 SDK 文档中心
首页
首页
  • 概述

    • SDK 概览与产品定位
    • 支持芯片平台与蓝牙认证
    • SDK 架构与目录分层
  • 快速开始

    • 环境搭建与编译工具链
    • 编译构建系统
    • 板级工程与配置
    • 烧录与固件升级工具
  • 应用工程

    • 应用选择与工程总览
    • SPP + BLE 数传应用框架
    • 透传与 AT 指令示例
    • BLE 广播/中心与定位示例
    • 2.4G 私有协议与 Dongle 示例
    • 云平台接入示例
    • HID 人机交互应用框架
    • HID 示例工程(键盘/鼠标/遥控器/手柄)
    • Bluetooth Mesh 应用框架
    • Mesh 模型与 Mesh DFU 固件升级
    • Mesh 音频编解码演示
  • 芯片平台与硬件抽象

    • 芯片平台总览与差异
    • 音频编解码与时钟管理
    • 外设驱动接口(ADC/IIC/SPI/PWM/LED/充电)
    • 芯片配置工具与下载支持
  • 蓝牙协议栈

    • 蓝牙控制器层(btctrler)
    • 蓝牙协议栈与 Profile(btstack)
    • 蓝牙模块选择与配置
  • 媒体与音频框架

    • 音频流框架
    • 音频编解码与 A2DP 媒体
    • 音频效果处理(EQ/频谱/变调/环绕/超低音)
    • 本地 TWS 与音频同步
  • 系统服务与运行时

    • 实时操作系统与任务调度
    • 消息事件机制
    • 电源管理与低功耗
    • 存储与配置系统
    • 设备驱动框架(USB/RTC)
  • 应用公共组件

    • 音频应用组件
    • 设备外设抽象(按键/触摸/传感器/存储)
    • 蓝牙公共模块与消息联动
    • 调试与配置组件
    • 杰理关键词唤醒(jl_kws)
  • 第三方协议与云平台接入

    • 杰理 RCSP 私有协议
    • 低功耗蓝牙 Mesh 方案(llsync_mesh)
    • Sig Mesh 方案
    • 涂鸦协议接入
    • 腾讯连连接入
    • 华为 HiLink 接入
  • 固件升级与维护

    • OTA 升级机制
    • 升级补丁与版本维护
    • 升级工具链(BLE OTA / USB Dongle OTA)
  • 文档与开发资源

    • 数据手册与架构文档
    • 协议与云平台开发文档
    • 常见问题与技术支持

编译构建系统

本页介绍 fw-AC63_BT_SDK 的编译构建系统:从顶层 Makefile 的目标分发,到板级 Makefile 的工具链选择、编译参数与后处理下载脚本的完整构建链路。

Purpose and Scope

本页覆盖以下内容:

  • 顶层 Makefile 的目标(target)命名规则与芯片—板级工程映射关系
  • 板级 Makefile(以 apps/hid/board/br25/Makefile 为例)中的工具链路径、编译参数、宏定义与链接设置
  • Linux 与 Windows 两套构建环境的差异与切换逻辑
  • 构建产物(sdk.elf)的输出位置与后处理(下载/烧录)脚本
  • 常见构建失败模式与排错建议

以下内容不在本页范围,由仓库其他部分或兄弟页面覆盖:

  • 具体芯片(如 BR25/BR23)的硬件架构与外设寄存器,请参见对应芯片目录文档
  • 具体应用(spp_and_le / hid / mesh)的业务逻辑,请参见各自的目录说明
  • 固件烧录工具的使用细节,请参见 cpu/<chip>/tools/ 下的脚本与工具文档

Overview

fw-AC63_BT_SDK 是一个典型的"一个 SDK、多芯片、多应用"嵌入式蓝牙 SDK。为了让开发者用一条 make 命令即可完成任意"芯片 + 应用"组合的编译,仓库采用了两级 Makefile 结构:

  1. 顶层 Makefile(仓库根目录)—— 只做一件事:把形如 ac636n_hid 的目标名翻译成 apps/<app>/board/<board>/ 目录,并递归调用该目录下的 Makefile。
  2. 板级 Makefile(apps/<app>/board/<board>/Makefile)—— 完成真正的编译工作:选择工具链、设置编译/链接参数、编译全部源码、链接生成 sdk.elf,最后调用下载脚本。

工具链基于 LLVM/Clang 的 pi32v2 目标(杰理自研 32 位 DSP/MCU 内核),使用 LTO(链接时优化)与 -Oz 尺寸优化——这是嵌入式资源受限场景的标准选择:优先保证固件体积最小化。

flowchart TD
    subgraph sg_Root["仓库根目录 Makefile"]
        Root["Makefile<br/>目标分发器"]
    end

    subgraph sg_Board["板级 Makefile (apps/&lt;app&gt;/board/&lt;board&gt;/)"]
        Board["Makefile<br/>工具链 + 编译参数"]
    end

    subgraph sg_Toolchain["工具链 (LLVM/Clang pi32v2)"]
        CC["clang (CC/CXX)"]
        LD["lto-wrapper (LD)"]
        AR["lto-ar / llvm-ar (AR)"]
    end

    subgraph sg_Output["构建产物"]
        ELF["sdk.elf"]
        POST["download.bat / download.sh<br/>下载脚本"]
    end

    Root -->|"make ac636n_hid"| Board
    Board -->|"CFLAGS -target pi32v2 -mcpu=r3 -flto -Oz"| CC
    Board -->|"LDFLAGS"| LD
    Board -->|"SYS_LIB_DIR 系统库"| AR
    CC --> ELF
    LD --> ELF
    ELF --> POST

设计意图:将"目标名"与"构建细节"解耦。顶层 Makefile 只需维护一张目标名 → 目录的映射表,新增芯片/板级工程时无需改动任何编译逻辑;板级 Makefile 则集中了该板卡的全部构建知识(工具链、宏、库路径、下载脚本),保证"改板卡只改一处"。

构建目标与芯片映射

顶层 Makefile 支持 15 个构建目标,命名规则为 ac<芯片型号>_<应用>,同时为每个目标提供对应的 clean_<目标> 清理目标:

# 支持的目标
# 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
# ...

Source: Makefile

芯片型号与板级目录的对应关系(从顶层 Makefile 的目标实现中提取):

芯片目标应用目录板级目录对应 Makefile
ac638nspp_and_le / hid / meshapps/*/board/br34br34/Makefile
ac632nspp_and_le / hid / meshapps/*/board/bd19bd19/Makefile
ac631nspp_and_le / hid / meshapps/*/board/bd29bd29/Makefile
ac636nspp_and_le / hid / meshapps/*/board/br25br25/Makefile
ac637nspp_and_le / hid / meshapps/*/board/br30br30/Makefile
ac635nspp_and_le / hid / meshapps/*/board/br23br23/Makefile

每个目标的实现本质上只是一条递归 make 调用,例如:

ac636n_hid:
	$(MAKE) -C apps/hid/board/br25 -f Makefile

clean_ac636n_hid:
	$(MAKE) -C apps/hid/board/br25 -f Makefile clean

Source: Makefile

all 目标会依次构建全部 15 个目标,clean 目标则依次清理全部工程:

all: ac638n_spp_and_le ac632n_spp_and_le ... ac635n_mesh
	@echo +ALL DONE

clean: clean_ac638n_spp_and_le ... clean_ac635n_mesh
	@echo +CLEAN DONE

Source: Makefile

板级 Makefile:工具链与构建环境

板级 Makefile(如 apps/hid/board/br25/Makefile)是真正执行编译的入口。它以 $(MAKE) -C apps/hid/board/br25 -f Makefile 被顶层调用,自身并不关心是哪个应用在调用它——三个应用目录(spp_and_le / hid / mesh)下的同一板卡目录结构完全一致。

跨平台工具链选择(OS 分支)

Makefile 通过 $(OS) 变量区分 Windows 与 Linux,两套工具链路径、后处理脚本完全不同:

ifeq ($(OS), Windows_NT)
# Windows 下工具链位置
TOOL_DIR := C:/JL/pi32/bin
CC    := clang.exe
CXX   := clang.exe
LD    := pi32v2-lto-wrapper.exe
AR    := llvm-ar.exe
MKDIR := mkdir_win -p
RM    := rm -rf

SYS_LIB_DIR := C:/JL/pi32/pi32v2-lib/r3
SYS_INC_DIR := C:/JL/pi32/pi32v2-include
EXT_CFLAGS  := # Windows 下不需要 -D__SHELL__
export PATH:=$(TOOL_DIR);$(PATH)

## 后处理脚本
FIXBAT          := ..\..\..\..\tools\utils\fixbat.exe # 用于处理 utf8->gbk 编码问题
POST_SCRIPT     := ../../../../cpu/br25/tools/download.bat
RUN_POST_SCRIPT := ..\..\..\..\cpu\br25\tools\download.bat
else
# Linux 下工具链位置
TOOL_DIR := /opt/jieli/pi32v2/bin
CC    := clang
CXX   := clang
LD    := lto-wrapper
AR    := lto-ar
MKDIR := mkdir -p
RM    := rm -rf
export OBJDUMP := $(TOOL_DIR)/objdump
export OBJCOPY := $(TOOL_DIR)/objcopy
export OBJSIZEDUMP := $(TOOL_DIR)/objsizedump

SYS_LIB_DIR := $(TOOL_DIR)/../lib/r3
SYS_INC_DIR := $(TOOL_DIR)/../include
EXT_CFLAGS  := -D__SHELL__ # Linux 下需要这个保证正确处理 download.c
export PATH:=$(TOOL_DIR):$(PATH)

## 后处理脚本
FIXBAT          := touch # Linux下不需要处理 bat 编码问题
POST_SCRIPT     := ../../../../cpu/br25/tools/download.sh
RUN_POST_SCRIPT := bash $(POST_SCRIPT)
endif

Source: apps/hid/board/br25/Makefile

关键差异与设计意图:

  • 工具链路径:Windows 固定为 C:/JL/pi32/bin,Linux 固定为 /opt/jieli/pi32v2/bin。这是 SDK 的约定——Linux 用户需要从 pkgman.jieliapp.com 下载工具链并解压到 /opt/jieli,保证 /opt/jieli/common/bin/clang 存在。
  • 链接器:Windows 用 pi32v2-lto-wrapper.exe,Linux 用 lto-wrapper——两者都是 LTO 包装器,负责把 LTO 位码链接成最终固件。
  • EXT_CFLAGS:Linux 下额外定义 -D__SHELL__,保证 download.c 在 Linux 环境下被正确处理(源码中的条件编译依赖该宏)。
  • FIXBAT:Windows 下用 tools/utils/fixbat.exe 修复 .bat 文件的 UTF-8→GBK 编码问题;Linux 下用 touch 占位,因为 shell 脚本无此问题。这体现了"同一构建逻辑、平台差异最小化"的封装思路。
  • export PATH:将工具链目录注入 PATH,使后续所有命令(包括子 make、下载脚本)都能找到 clang 等工具。

构建产物与路径常量

# 输出文件设置
OUT_ELF   := ../../../../cpu/br25/tools/sdk.elf
OBJ_FILE  := $(OUT_ELF).objs.txt
# 编译路径设置
BUILD_DIR := objs
# 工程路径前缀
ROOT_PREFIX := ../../../..

Source: apps/hid/board/br25/Makefile

  • 最终固件统一输出到 cpu/br25/tools/sdk.elf(即下载脚本所在目录),这样下载/烧录脚本可以直接引用同目录下的固件文件。
  • 中间 .o 文件输出到板级工程目录下的 objs/,clean 目标即删除该目录。
  • OBJ_FILE 记录了链接时需要的所有目标文件清单,供 LTO 链接器使用。

编译参数(CFLAGS)

BR25 板级工程的 CFLAGS 集中体现了该 SDK 的编译约束:

CFLAGS := \
	-target pi32v2 \
	-mcpu=r3 \
	-integrated-as \
	-flto \
	-Wuninitialized \
	-Wno-invalid-noreturn \
	-fno-common \
	-Oz \
	-g \
	-fallow-pointer-null \
	-fprefer-gnu-section \
	-Wno-shift-negative-value \
	-Wundef \
	-Wframe-larger-than=256 \
	-Wincompatible-pointer-types \
	-Wreturn-type \
	-Wimplicit-function-declaration \
	-fms-extensions \
	-w

Source: apps/hid/board/br25/Makefile

逐项解读:

参数含义
-target pi32v2指定编译目标为杰理 pi32v2 内核
-mcpu=r3CPU 变体为 r3(对应 BR25 芯片核)
-integrated-as使用 Clang 内置汇编器,避免外部 as 版本不匹配
-flto开启链接时优化,配合 lto-wrapper 在链接阶段做跨文件优化
-Oz以"最小化代码尺寸"为优化目标——嵌入式 Flash 有限,这是默认策略
-g生成调试信息,便于用 objdump/调试器分析
-fno-common禁止公共块合并,避免未初始化全局变量跨文件意外合并
-fprefer-gnu-section偏好 GNU section 布局,配合 LTO 做函数级裁剪
-Wframe-larger-than=256警告栈帧超过 256 字节的函数——嵌入式栈空间紧张,用于早期发现深栈风险
-fms-extensions允许 MSVC 扩展语法(匿名 struct/union 等),兼容部分历史代码
-w最后关闭警告(前面的 -W... 项与 -w 配合,实际只保留显式启用的诊断)

设计意图:-Oz + -flto + -fprefer-gnu-section 三件套是嵌入式固件"压尺寸"的核心手段——编译器在链接期做全局优化、丢弃未引用的 section,从而让最终固件只包含实际用到的代码。-Wframe-larger-than 则是一个主动的栈安全哨兵。

宏定义(DEFINES)

板级 Makefile 还通过 DEFINES 注入芯片与功能开关宏:

DEFINES := \
	-DSUPPORT_MS_EXTENSIONS \
	-DCONFIG_RELEASE_ENABLE \
	-DCONFIG_CPU_BR25 \
	-DCONFIG_PRINT_IN_MASK \
	-DCONFIG_EQ_SUPPORT_ASYNC \
	-DCONFIG_MIXER_CYCLIC \
	-DCONFIG_FREE_RTOS_ENABLE \
	-DCONFIG_MMU_ENABLE \
	-DCONFIG_SBC_CODEC_HW \
	-DCONFIG_MSBC_CODEC_HW \
	-DCONFIG_AEC_M=256 \
	-DCONFIG_AUDIO_ONCHIP \
	-DCONFIG_MEDIA_DEVELOP_ENABLE \
	-D__GCC_PI32V2__ \
	-DCONFIG_NEW_ECC_ENABLE \
	-DEVENT_HANDLER_NUM_CONFIG=2 \
	-DEVENT_TOUCH_ENABLE_CONFIG=0 \
	-DEVENT_POOL_SIZE_CONFIG=256 \
	-DCONFIG_EVENT_KEY_MAP_ENABLE=0 \
	-DTIMER_POOL_NUM_CONFIG=10 \
	...

Source: apps/hid/board/br25/Makefile

这些宏是"配置即代码"的体现:CONFIG_CPU_BR25 决定芯片相关代码分支;CONFIG_FREE_RTOS_ENABLE / CONFIG_MMU_ENABLE 开启 FreeRTOS 与 MMU;CONFIG_SBC_CODEC_HW / CONFIG_MSBC_CODEC_HW 选择硬件编解码器;EVENT_POOL_SIZE_CONFIG、TIMER_POOL_NUM_CONFIG 等则静态配置事件/定时器资源池大小——在无动态内存管理(或受限)的 MCU 场景,资源池大小必须在编译期确定。修改这些宏即可裁剪功能与内存占用,而无需改动业务源码。

核心构建流程

从执行 make ac636n_hid 到生成固件,完整链路如下:

sequenceDiagram
    participant U as 开发者
    participant R as 顶层 Makefile
    participant B as 板级 Makefile (br25)
    participant T as 工具链 (clang/lto-wrapper)
    participant P as 后处理脚本 (download.sh/bat)

    U->>R: make ac636n_hid
    R->>B: $(MAKE) -C apps/hid/board/br25 -f Makefile
    B->>B: 检测 OS → 选择工具链路径与脚本
    B->>T: clang -target pi32v2 -mcpu=r3 -flto -Oz<br/>编译全部 .c/.cpp → objs/*.o
    T->>T: lto-wrapper 链接 objs/*.o + SYS_LIB_DIR 系统库
    T-->>B: 生成 cpu/br25/tools/sdk.elf
    B->>P: RUN_POST_SCRIPT (download.sh / download.bat)
    P-->>U: 固件下载/烧录完成
    U->>R: make clean_ac636n_hid (可选)
    R->>B: $(MAKE) -C apps/hid/board/br25 -f Makefile clean
    B->>B: 删除 objs/ 等中间产物

流程要点:

  1. 目标解析:顶层 Makefile 把 ac636n_hid 映射为 apps/hid/board/br25,执行递归 make;clean_ac636n_hid 则递归执行 make clean。
  2. 环境选择:板级 Makefile 读取 $(OS),Windows_NT 走 Windows 分支(C:/JL/pi32/bin),否则走 Linux 分支(/opt/jieli/pi32v2/bin),并 export PATH 注入工具链。
  3. 编译:clang 以 -target pi32v2 -mcpu=r3 -flto -Oz 编译所有源文件,中间文件落入板级工程目录的 objs/。
  4. 链接:lto-wrapper(Windows 下 pi32v2-lto-wrapper.exe)读取 sdk.elf.objs.txt 中的目标文件清单,结合 SYS_LIB_DIR(pi32v2-lib/r3 系统库)完成 LTO 链接,输出 cpu/<chip>/tools/sdk.elf。
  5. 后处理:自动执行 download.bat(Windows)或 bash download.sh(Linux)下载固件;Windows 下先用 fixbat.exe 修正 bat 编码,Linux 下用 touch 占位。

使用示例

编译指定芯片 + 应用组合

# 编译 HID 应用(AC636N → br25 板卡)
make ac636n_hid

# 编译 SPP 与 LE 双模应用
make ac638n_spp_and_le

# 编译 Mesh 应用
make ac635n_mesh

# 显示编译详细过程
make VERBOSE=1

Source: apps/hid/board/br25/Makefile

清理与全量构建

# 清理单个工程(删除 objs/ 中间产物)
make clean_ac636n_hid

# 全量清理所有 15 个工程
make clean

# 依次构建全部芯片×应用组合
make all

Source: Makefile

Linux 环境准备(首次使用)

# 1. 从 http://pkgman.jieliapp.com/doc/all 下载工具链并解压到 /opt/jieli
#    确保 /opt/jieli/common/bin/clang 存在(注意目录层次)

# 2. 调大文件描述符上限,防止链接时"打开文件太多"失败
ulimit -n 8096

# 3. 然后正常编译
make ac636n_hid

Source: Makefile

配置选项

构建系统的可配置项分为三层:

层级配置项取值示例默认/说明
顶层目标构建目标名ac636n_hid规则:ac<型号>_<应用>,见芯片映射表
顶层目标清理目标名clean_ac636n_hid每个构建目标都有对应的 clean 目标
板级工具链TOOL_DIRC:/JL/pi32/bin / /opt/jieli/pi32v2/bin按 $(OS) 自动选择
板级工具链CC / CXX / LD / ARclang / lto-wrapper / lto-arWindows 下带 .exe 后缀
板级工具链SYS_LIB_DIRC:/JL/pi32/pi32v2-lib/r3系统运行库目录
板级工具链SYS_INC_DIRC:/JL/pi32/pi32v2-include系统头文件目录
板级编译CFLAGS-target pi32v2 -mcpu=r3 -flto -Oz编译参数,可追加定制
板级编译DEFINESCONFIG_CPU_BR25、CONFIG_FREE_RTOS_ENABLE 等功能开关与资源池大小宏
板级输出OUT_ELF../../../../cpu/br25/tools/sdk.elf固件输出路径
板级输出BUILD_DIRobjs中间文件目录
后处理POST_SCRIPT / RUN_POST_SCRIPTdownload.sh / download.bat下载/烧录脚本,平台相关
后处理FIXBATfixbat.exe / touchWindows 下修正 bat 文件编码

失败模式与边界情况

基于 Makefile 源码中的注释与实现,以下是已知的典型失败场景及原因:

失败现象根因解决建议
clang: command not foundLinux 工具链未安装或目录层次不对,/opt/jieli/common/bin/clang 不存在按注释从 pkgman 下载并解压到 /opt/jieli,确认目录层次
链接阶段报 "too many open files"ulimit -n 过小,LTO 链接需要打开大量文件执行 ulimit -n 8096(或更大)后重试
Windows 下 bat 脚本乱码/执行失败.bat 文件编码问题(UTF-8 与 GBK 混用)构建系统已通过 fixbat.exe 自动处理;手动修改脚本后需保持编码一致
download.c 行为异常(Linux)缺少 -D__SHELL__ 宏Linux 分支的 EXT_CFLAGS 已自动加上该宏,请勿删除
make all 中某个目标失败该芯片工具链/库不匹配(如 SYS_LIB_DIR 指向的 r3 库与 -mcpu 不符)单独执行对应目标,检查板级 Makefile 的 SYS_LIB_DIR 与 -mcpu 是否匹配
栈溢出/运行期崩溃深栈函数未被发现关注 -Wframe-larger-than=256 警告,检查 EVENT_POOL_SIZE_CONFIG 等资源池宏是否过小

边界情况:

  • 平台分支判定:仅依据 $(OS) 是否为 Windows_NT 决定平台。若在 Windows 下使用 MinGW/MSYS 环境,$(OS) 可能不精确匹配,导致误入 Linux 分支——建议在原生 Windows cmd 或符合该判定的环境中构建。
  • 路径硬编码:Windows 工具链路径硬编码为 C:/JL/pi32/bin,Linux 硬编码为 /opt/jieli/pi32v2/bin,不可自定义;更换工具链版本需整体替换目录内容。
  • make 与 make clean 的组合:clean 只删除板级 objs/ 中间产物,sdk.elf 位于 cpu/<chip>/tools/ 下,不会被 clean 删除,可避免误删已验证固件。

性能与运维注意事项

  • LTO 编译较慢:-flto 在链接期做全程序优化,首次全量编译耗时明显高于普通编译。增量编译时 Makefile 依赖时间戳判定,改动单个文件只会重编相关目标文件。
  • 并发构建:未在顶层 Makefile 中使用 -j,各目标串行执行;用户可自行传入 make -jN ac636n_hid 加速单工程编译,但需注意 LTO 链接阶段的内存占用。
  • 产物位置约定:所有板卡的 sdk.elf 统一输出到对应 cpu/<chip>/tools/ 下,便于 CI 脚本与下载工具按固定路径取用。
  • 磁盘空间:objs/ 中每个源文件对应一个 .o,15 个目标全量构建会产生较多中间文件;make clean 可及时回收。

扩展点

构建系统为以下扩展场景预留了清晰的插入位置:

  1. 新增应用:在 apps/ 下复制现有应用目录结构(如 apps/xxx/board/<board>/Makefile),顶层 Makefile 增加对应的 <芯片>_<应用> 与 clean_<芯片>_<应用> 目标即可,无需改动板级构建逻辑。
  2. 新增芯片/板卡:在 apps/*/board/ 下新增板级目录,参考现有板卡 Makefile 设置 -mcpu、SYS_LIB_DIR、OUT_ELF 与下载脚本;同时在顶层 Makefile 注册目标。
  3. 裁剪功能与内存:通过修改板级 Makefile 的 DEFINES(如关闭 CONFIG_* 功能宏、调小 EVENT_POOL_SIZE_CONFIG / TIMER_POOL_NUM_CONFIG)即可调整固件体积与 RAM 占用,无需改动业务代码。
  4. 定制编译参数:追加 CFLAGS(如 -Werror、额外 include 路径)或自定义 DEFINES 覆盖默认配置。

相关链接

  • 根构建入口:Makefile
  • 板级构建示例:apps/hid/board/br25/Makefile
  • 其他板级 Makefile:apps/spp_and_le/board/br23/Makefile、apps/mesh/board/br30/Makefile
  • 下载/烧录脚本目录:cpu/<chip>/tools/(如 cpu/br25/tools/download.sh)
  • 工具链获取:pkgman.jieliapp.com
  • 相关目录:应用入口请参见 apps/spp_and_le、apps/hid、apps/mesh 各自的说明页面
Prev
环境搭建与编译工具链
Next
板级工程与配置