☰
AC692N SDK源码实战:目录启动、编译烧录与板级配置避坑
2026/10/26 11:42:30 网站建设 项目流程

简介:面向杰理692N无线通讯芯片初学者的开发入门教程与配套SDK源码包,适合准备进入蓝牙、Wi-Fi等无线应用领域的嵌入式工程师及高校学习者,帮助其梳理芯片硬件特性、开发环境搭建和SDK基本用法。压缩包共647个文件,以241个.h头文件、127个.c源码和123个.o编译中间文件为主体,另含mp3音频素材、pdf文档、bin固件、exe工具、Keil工程文件及批处理脚本等,整体约40.08MB,目录内源码、库与资料相对集中,便于按模块检索。已有5825人学习,说明其在入门实践中具备一定参考价值。资源围绕驱动、库函数、示例代码与API文档展开,涵盖工程编译、烧录验证到问题定位的完整链路,并包含蓝牙、音频解码、USB、存储等预编译库,读者可据此熟悉外设初始化、通信参数设置、数据收发、电源管理和调试排错流程,逐步建立692N SDK开发框架。

1. 解压完 692N SDK 源码,先别急着改第一行

我见过太多人拿到 AC692N 的 SDK 压缩包,解压出几千个文件,apps、cpu、include_lib、lib一排目录摊在眼前,然后花两天时间在目录里瞎逛,最后连一个 LED 都没点起来。这块芯片本身是一颗蓝牙音频 SoC,MCU、DSP、蓝牙基带、音频 codec、电源管理全塞在一颗 QFN 里,692N SDK 源码给的是整套量产级框架:蓝牙协议栈、MP3/FLAC/AAC 解码、TWS 对耳、按键状态机、充电管理、OTA 升级,全都在里面,改配置就能出一个能卖的产品。它适合做蓝牙音箱、耳机、语音模块的嵌入式开发,不适合只想点个灯练手的人——抽象层很厚,你得先认路,再动手。

2. 目录结构与启动链路:从复位向量到 app_main 的完整路径

2.1 顶层目录谁是只读区,谁是改动区

把 SDK 根目录摊开,第一件事不是读代码,是给每个目录打标签。我一般按「改不改」来分:apps/是应用层,每个子目录对应一种产品形态,soundbox是蓝牙音箱,spp_and_le是双模透传,bt_earphone是耳机,日常开发 90% 的时间待在这一个目录里;cpu/br25/是内核和片上外设驱动,GPIO、UART、IIC、SPI、ADC、音频 codec 的实现全在这,除非要改引脚复用或者加新外设,不然别碰;include_lib/是对外暴露的头文件,系统 API 像os_task_create、sys_timer_add的声明都在system/下,driver/是外设接口,bt/是蓝牙栈。

目录职责改动频率
apps/<产品名>/应用逻辑、板级配置、按键表高,天天改
cpu/br25/内核启动、外设驱动、链接脚本低,改引脚复用时才动
include_lib/系统与驱动头文件只读,别改
lib/蓝牙协议栈、音频解码静态库只读,只有.a
tools/烧录工具、配置模板、量产脚本只读,配置时引用

lib/这个目录要单独说一句,里面全是预编译好的.a,蓝牙基带、解码算法这些核心资产不给源码,你只能通过头文件里的接口去调。这一点决定了 692N SDK 的开发方式:不是从零写协议栈,而是在既有框架里做配置和业务编排。明白这一点,后面看代码就不会到处找「蓝牙是怎么连上的」这种实现了,因为它不在源码里。

apps/下面每个产品目录又分三层:board/放板级文件,引脚定义、按键表、设备初始化往里塞;include/放该应用的配置头;根目录下是app_main.c和task_config.h,任务优先级、栈大小、消息队列深度都在task_config.h里定。新手最容易犯的错是直接改cpu/下的驱动,改完发现一编译全乱,因为那些文件是多个 app 共用的,你的改动会污染别的产品形态。

2.2 上电之后代码往哪跑

复位之后先执行cpu/br25/下的启动汇编,设栈指针、清.bss、把.data从 flash 搬到 SRAM,然后跳到board_init()。这个函数在apps/soundbox/board/br25/board_ac692n_demo.c里,是整个 SDK 的分水岭,它之前的代码你基本不用管,它之后的代码才是你的战场。

void board_init(void) { /* 1. 时钟与电源:决定主频基线和低功耗底子 */ sys_clk_set(SYS_48M); /* 待机跑 48M,播放时驱动内部会再拉高 */ power_init(PWR_LDO_MODE); /* 内置充电方案要换成 CHG 模式,否则充电检测失效 */ /* 2. 调试串口:printf 重定向就靠它,必须早于其他外设 */ debug_uart_init(DEBUG_UART_PORT, 115200); /* 3. 片上外设:先 GPIO,再按依赖顺序挂载 */ gpio_init(); port_protect_init(); /* 引脚保护表,防止同一个脚被两个模块抢 */ /* 4. 板级设备:按键、LED、功放使能、充电检测 */ board_devices_init(); /* 5. 应用入口,进去就不返回了 */ app_main(); }

这段代码的关键在顺序。debug_uart_init必须排在gpio_init前面,因为串口引脚初始化时会覆写 GPIO 配置,顺序反了打印就是一堆乱码,这个坑我踩过不止一次。port_protect_init是杰理这套 SDK 比较有意思的设计,它维护一张引脚占用表,哪个模块申请了哪个脚都记着,两个模块抢同一个脚的时候能报出来,调试外设冲突的时候先看这张表。sys_clk_set改主频要连带看音频时钟分频,48M 和 120M 下 I2S 的分频系数不一样,只改主频不改音频配置,播出来的声音会变调。

app_main()里做的是任务编排,不写业务:

void app_main(void) { sysmsg_init(); /* 系统消息池,蓝牙事件、按键事件都走这里 */ sys_timer_init(); /* 软定时器池,最小 tick 1ms */ app_task_init(); /* 应用状态机任务,优先级和栈在 task_config.h 里定 */ app_main_loop(); /* 主循环,进去之后不再返回 */ }

sysmsg_init建的是全局消息池,后面所有跨任务通信都往这个池子里投消息,投递用sysmsg_push,取用在自己任务的循环里sysmsg_pop。app_task_init里用os_task_create创建业务任务,栈大小从task_config.h的宏里取。这里有个经验值:音频播放任务栈给到 2K 以上,蓝牙协议栈任务给 1.5K,业务逻辑任务 1K 起步,栈给小了症状是随机死机,而且死的位置每次都不一样,查起来非常玄学。

2.3 链接脚本决定你的 buffer 能开多大

cpu/br25/tools/下有.ld链接脚本,它规定了代码段放 flash、数据段和 bss 段放 SRAM、常量表放 flash 的只读区。你要加大的音频缓冲区、要新增的全局数组,全部吃 SRAM,而 692N 的片内 SRAM 是有数的,几十 K 的级别。改 buffer 之前先看.map文件里当前.bss占了多大,剩下的余量才敢动。我一般留 15% 余量给运行时堆,不然跑着跑着malloc返回 NULL,现象是播放到某首歌突然断,特别难定位。

3. 编译环境与固件产出:工具链、Makefile、配置三件套

3.1 工具链装好只是第一步

692N 用的是定制交叉编译器,解压后把bin目录加进PATH,然后在命令行敲一下jl-gcc -v确认能出版本号。Windows 下杰理一般还提供 Code::Blocks 工程,双击.cbp也能编,但量产和 CI 场景我还是建议走 Makefile,可控。Makefile 里几个变量决定了你编出来的是哪个产品:

# 交叉工具链前缀,指向解压后的工具链 bin 目录 CROSS_COMPILE ?= /opt/jl_toolchain/bin/jl_ CC := $(CROSS_COMPILE)gcc # 选哪个应用编,命令行可以覆盖:make APP=soundbox APP ?= soundbox # 芯片内核目录,692N 走 br25 CPU ?= br25 # 全局宏,产品形态的差异最后都收敛到这里 DEFINE := -DCONFIG_APP_SOUNDBOX \ -DCONFIG_BOARD_AC692N_DEMO \ -DCONFIG_UART_DEBUG_ENABLE

CROSS_COMPILE前缀写错,报的是「找不到编译器」,不是代码错误,别去源码里找。APP决定编哪个产品目录,CPU决定用哪套内核驱动,这两个变量在同一个 Makefile 里是多对多的关系,一个 CPU 可以带多个 APP。DEFINE里的宏才是真正决定行为的开关,CONFIG_BOARD_AC692N_DEMO指向具体的板级文件,改了它等于换了块板子。这三个变量一旦和你的实际目标板对不上,编出来的固件能下载、能上电,但行为完全不对,这种「能跑但跑错」的失败最消耗时间。

编译命令就两条:

make clean make APP=soundbox CPU=br25 -j8

clean不能省,杰理这套 Makefile 对头文件依赖的追踪不算严密,改了app_config.h不 clean 直接编,有一半概率编进去的还是旧配置。-j8是并行编译,文件多的时候能把时间从几分钟压到几十秒。

3.2 产物里哪几个文件真正有用

编完之后输出目录里会出来一堆东西,真正要关心的就三个:app.bin是固件本体,update.ufw是给 OTA 用的升级包,app.map是内存布局清单。app.map是排查问题的黑匣子,某个函数到底有没有被链接进去、某个数组占了多大 SRAM、栈顶栈底在哪,全在里面查。我习惯每次改完配置都扫一眼.map里.bss的大小,涨得离谱就说明有东西没裁掉。

isd_config.ini是烧录配置,和固件一起交给下载工具:

[ISD_CONFIG] ; 固件在 SPI Flash 中的起始偏移,改错会覆盖蓝牙地址区 FIRMWARE_START = 0x0 ; 升级文件位置,OTA 从这里取 UPDATE_FILE = update.ufw ; 蓝牙名和地址,量产前必须换成自己申请的 BT_NAME = AC692N_DEMO BT_MAC = 11:22:33:44:55:66

FIRMWARE_START是偏移量,不同方案的分区规划不一样,有 OTA 需求的方案要给升级区留位置,这个值配错,轻则升级失败,重则把蓝牙地址区写坏,芯片变砖,只能上治具救。BT_MAC在 demo 阶段随手写没事,量产阶段每台机器必须不一样,一般由产线工具按规则烧进去,不能靠固件里写死。

3.3 配置裁剪:先减后加

apps/soundbox/include/app_config.h是编译期的总开关,里面几十个CONFIG_开头的宏。新手常见的做法是全开,结果 flash 不够、SRAM 不够、编译时间还长。正确的路径是先全关,再一个个打开验证。

/* 音频解码能力:按产品实际支持的格式开,FLAC 很吃 flash */ #define CONFIG_AUDIO_DECODER_MP3_ENABLE 1 #define CONFIG_AUDIO_DECODER_WAV_ENABLE 1 #define CONFIG_AUDIO_DECODER_FLAC_ENABLE 0 /* 不开就省十几 K */ /* 功能模块:TWS 对耳不开能省一大块协议栈 buffer */ #define CONFIG_TWS_ENABLE 0 #define CONFIG_USB_AUDIO_ENABLE 0 /* 不用 USB 声卡就关掉 */ #define CONFIG_SD_CARD_ENABLE 0 /* 调试开关:量产固件一定要关,串口输出本身会拖慢实时性 */ #define CONFIG_UART_DEBUG_ENABLE 1

每关一个宏,编一次、烧一次、跑一遍,确认功能没受影响再关下一个。批量关完再一起编,出了问题根本不知道是哪个宏引起的。CONFIG_UART_DEBUG_ENABLE这一项要特别提醒,调试阶段开着方便,量产固件必须关,串口打印在中断上下文里执行会拖慢音频线程,表现就是偶发的播放卡顿。

4. 板级配置与核心驱动:按键、音频通路、LED 的代码拆解

4.1 board_devices_init 里的注册顺序

board_devices_init()是板级设备的装配车间,顺序有讲究:先注册不依赖其他设备的(LED、功放使能),再注册需要回调的(按键),最后注册需要定时轮询的(充电检测、电池电压)。

static void board_devices_init(void) { /* 功放使能脚先拉低,避免上电瞬间的爆破音 */ gpio_set_mode(IO_PORT_A, IO_PIN_3, PORT_OUTPUT); gpio_write(IO_PORT_A, IO_PIN_3, 0); /* LED 指示:呼吸灯效果交给软定时器,不占硬件 PWM */ led_init(LED_RED_PORT, LED_RED_PIN); /* 按键:adkey 走 ADC 通道,iokey 走普通 GPIO */ adkey_init(&adkey_config); /* 充电与电池检测,需要外部电阻分压,参数按实际硬件填 */ charge_init(&charge_config); }

功放使能那两行是血泪经验,很多板子上电瞬间「噗」一声,就是功放比 codec 先使能导致的,先把脚拉低、等 codec 稳定之后再拉高,声音就干净了。led_init只做引脚初始化,闪烁逻辑放到sys_timer_add的软定时器回调里,这样不占硬件资源,几十毫秒一次的呼吸效果用软件做完全够。adkey_init传进去的结构体里装着 ADC 通道号、采样周期、按键表指针,改硬件只需要改这张表。

4.2 AD 按键:一张表决定所有按键行为

AD 按键的原理是一个 ADC 引脚上串一排不同阻值的电阻,按下不同键时分压不同,ADC 采样值落进不同区间。这张表是整个按键系统的核心,配错了就是串键、误触发、按了没反应。

/* 每个元素:{ADC 采样值, 按键值, 触发属性} */ static const adkey_table_item_t adkey_table[] = { {0x0A, KEY_PLAY_PAUSE, KEY_SHORT | KEY_LONG}, /* 电阻最小,按下几乎拉到底 */ {0x4B, KEY_VOL_UP, KEY_SHORT | KEY_LONG}, {0x8C, KEY_VOL_DOWN, KEY_SHORT | KEY_LONG}, {0xC8, KEY_PREV, KEY_SHORT}, {0xFF, KEY_NONE, 0}, /* 松手兜底,这一档不能省 */ };

表里的采样值不是线性分布的,因为电阻串联之后分压比不是等差,必须实测。方法是先把表全填 0xFF,只留兜底项,然后加打印,一个个按键按下去把实际采样值打出来,再按实测值填表。每一项要留 ±8 左右的窗口,电阻本身有 5% 误差,窗口开太窄,同一批板子里有一半会串键。最后一项KEY_NONE是松手状态,没有这一项,松手瞬间会被判成最后一个按键,现象是音量一直加。

KEY_SHORT | KEY_LONG是触发属性,长短按的时间阈值在key_config结构体里配,一般短按 50ms 判定、长按 1.5s 触发。长按还要配重复触发间隔,音量键按住不放要连续加减,间隔给 200ms 比较跟手。

4.3 音频通路:DAC、解码、增益三段要分开看

音频这条链拆成三段:DAC 输出配置、解码器参数、输出增益。三段分开配,出问题好定位是哪一段。

/* 先开 DAC 再开解码,顺序反了会有明显爆音 */ audio_dac_init(48000, DAC_CH_LR); audio_dec_param_t dec_param = {0}; dec_param.channel = 2; /* 立体声,单声道方案填 1 */ dec_param.sample_rate = 44100; /* 跟音源一致,不要盲目填 48000 */ dec_param.bit_width = 16; dec_param.output_gain = 12; /* 0~31,每档约 1.5dB,别一次拉满 */ audio_dec_open(&dec_param);

audio_dac_init的第一个参数是 DAC 采样率,要和后面解码器输出的采样率对齐,DAC 配 48K、解码器出 44.1K,中间会做一次软件重采样,音质有损还多占 CPU。dec_param.sample_rate要跟音源走,MP3 大多是 44.1K,硬填 48K 等于给自己找麻烦。output_gain是数字增益,不是模拟增益,拉太满会让小信号削顶,听感上是破音而不是大声,一般给到 12 到 18 之间,剩下的响度交给外部功放的模拟增益。

5. 烧录与上电避坑:五条从产线带回来的真实排查记录

5.1 两种烧录方式和它们的适用场景

USB 下载是最常用的,板子进 USB 升级模式后,下载工具会把它识别成一个 HID 设备,然后按isd_config.ini里的分区把app.bin写进去。步骤是:板子断电、按住升级键(或者短接 USB 的 DP 脚到地)、上电、工具识别到设备、选配置文件和固件、点下载、等进度条走完、复位。串口下载慢一些,但不需要 USB 口,产线上做治具的时候更常用,前提是板子上已经有一份能跑的 boot,纯粹的空片是下不进去的。

量产阶段还有个技巧:把BT_MAC的烧录做成单独一步,固件里写死一个默认值,产线工具按顺序递增改写地址区,这样同一个固件可以给所有机器用,不用每台机器重编。

提示:下载工具认的是 HID 设备,USB 线只通电源不通数据的时候,工具里看不到设备,先换线再怀疑板子。

5.2 五条踩坑记录

第一条:编过了,下载了,上电没反应。

现象是下载工具显示成功,复位后 LED 不亮、串口也不打印。原因基本是DEFINE里的宏和实际目标板对不上,编进去的是另一块板子的board_init,引脚定义全错。排查方法是翻.map文件,看board_init、board_ac692n_demo.o是不是真的被链接进去了。解决就是make clean之后带完整宏重编,别指望增量编译能救。

第二条:串口有输出,但全是乱码。

现象是能收到数据,但内容对不上。两个原因:一是debug_uart_init的引脚被按键或者 adkey 占用了,port_protect_init那张表里能看到冲突记录;二是改过主频之后波特率分频没跟着改。解决是把调试串口换到没被占用的引脚,或者在port_protect初始化时把调试串口排除在外,让保护机制跳过它。

第三条:按键串键,按音量加触发的是上一曲。

现象不稳定,有的板子好有的板子坏。原因是 AD 按键表的区间太窄,电阻误差叠加之后采样值漂到了隔壁区间。解决办法是逐板实测采样值,把每档窗口放宽到 ±8 到 ±12,兜底项的0xFF一定不能省。批量生产前至少抽十块板子验证按键表。

第四条:播放音乐偶发卡顿,蓝牙也断。

现象是播几分钟卡一下,距离远一点直接断连。原因通常是两个:中断里做了耗时操作,比如在按键中断里直接发蓝牙消息;或者音频缓冲区太小,.bss里给 decoder 的 buffer 不够。解决是把耗时逻辑从裸中断挪到任务里,通过消息池投递;缓冲区按.map里的余量往上加,一般 4K 起步。

第五条:下载工具报芯片未识别。

现象是工具里一直转圈或者直接报错。先换 USB 线,再确认驱动装了没有,最后确认板子是不是进了深休眠没复位。深休眠状态下 USB 模块是关的,必须先断电再上电重新进升级模式。这三步按顺序排除,九成的「芯片未识别」都能解决。

6. 二次开发改造:把 demo 板改成自己板子的三步走

拿到一块自己画的板子,改 SDK 的顺序我固定成三步,顺序反了会来回返工。

第一步改引脚。把board_ac692n_demo.c里所有IO_PORT_x、IO_PIN_x换成自己原理图上的实际引脚,包括 LED、功放使能、充电检测、按键 ADC 通道。改完先只验证 GPIO:让 LED 闪,串口能打印,别的全不管。

第二步改按键表。这一步必须上板实测,把adkey_table全填0xFF只留兜底项,加打印把每个按键的实际 ADC 值打出来,再按实测值填回去。窗口宽度按电阻精度留,5% 精度的电阻给 ±10,1% 的给 ±5。

第三步裁剪配置。在app_config.h里关掉所有用不到的功能,每关一个编一次烧一次跑一遍。关到不能再关为止,剩下的就是你的产品基线。

改动内容位置验证方法
引脚定义board/br25/board_ac692n_demo.cLED 闪烁 + 串口打印
按键表同目录adkey_table逐键实测 ADC 值
功能裁剪include/app_config.h编译后看.map的.bss大小
蓝牙名与地址isd_config.ini手机搜索到的设备名
输出增益audio_dec_param满音量播 1KHz 正弦波看是否削顶

验证增益有个笨办法但很好用:灌一个 1KHz 的正弦波文件进去,满音量播放,用示波器看功放输出,波形顶部平了就是削顶,把output_gain往下调两档再测。这个动作比用耳朵听靠谱得多。

从那以后我每次接手一块新板子,都强制走一遍「先点灯、再打印、最后上音频」的顺序,不管多急都不跳步。跳过点灯直接调音频,出了问题你连是硬件焊接、引脚配错还是解码参数错都分不清,最后花的时间反而更多。希望这套顺序帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询