简介:面向嵌入式与无线通讯开发初学者的杰理692N SDK 入门学习包,围绕这款低功耗蓝牙/Wi-Fi 芯片,把硬件特性理解、开发环境搭建、API 调用与源码调试串成一条完整的上手路径,适合刚接触杰理平台、需要快速跑通第一个工程的开发者。压缩包为 zip 格式,共 647 个文件、约 40.08MB,其中 241 个 .h 头文件与 127 个 .c 源文件构成 SDK 的接口声明与功能实现主体,123 个 .o 目标文件与多个 .a 静态库(蓝牙、MP3/AAC/WMA 解码、USB、SD 卡、文件系统、UI 等模块)省去重复编译,16 份 pdf 提供芯片与模块说明,另有若干 mp3 音频样本、exe 工具与 bat 脚本用于验证与构建。已有 5825 人学习。读者可据此熟悉 692N 的引脚与电源管理配置、驱动程序与库函数的分层关系、示例代码的组织方式,并借助 IDE 断点、单步调试与真机测试定位问题,形成可复用的开发与排错思路。
1. 692N SDK 源码包拆开看:从“能编译”到“能出声”差哪几步
很多人拿到 692N SDK 源码包,第一反应是打开工程直接编译,结果卡在头文件路径;好不容易烧进去,喇叭只有底噪。这个开发入门包真正有用的地方,不是某个现成算法,而是把蓝牙音频产品的启动顺序、板级配置、外设初始化和下载打包拆成了可对照的工程骨架。
它适合刚接触 692N 平台、需要把耳机或音箱样机跑通的嵌入式工程师,也适合想从业务层往下补驱动和协议栈细节的熟手。源码包里能直接改的多在应用层和板级配置,协议栈、音频算法常以库的形式存在,所以入门顺序应该是先对齐工具链和目录,再改板级宏,最后才碰蓝牙事件和提示音。
先别急着改业务代码。把编译链路、下载配置和音频通路逐项对齐,后面才少返工;这份资源的价值也在这里——它给了一条能复现的启动路径,而不是一堆散落的驱动文件。
2. 环境与工程骨架:工具链、目录和编译入口怎么对齐
692N SDK 源码包解压后目录很多,新手容易从lib开始翻,翻半天只看到二进制。我一般先看apps、cpu、include_lib、tools四层,因为应用入口、启动代码、头文件映射和打包脚本都在这里。选型理由很直接:协议栈和音频算法是库,先读库反汇编成本高;先把工程骨架跑通,才能判断问题出在配置还是库本身。
2.1 目录结构先读哪几层:apps、cpu、include_lib、lib、tools
常见 692N SDK 目录不会完全一样,但下面这几层基本都会出现。入门阶段不要平均用力,先把apps下的示例工程和tools下的下载配置读明白,再回头看cpu的启动文件。
| 目录 | 作用 | 入门先看什么 |
|---|---|---|
apps | 应用工程与业务入口 | main.c、app_config.h、board_config.h |
cpu | 启动文件、中断向量、时钟 | startup、irq、系统时钟初始化 |
include_lib | 公共头文件 | 类型定义、日志宏、音频接口 |
lib | 协议栈与算法静态库 | 链接顺序、库依赖关系 |
tools | 下载、打包、配置工具 | isd_config.ini、打包脚本 |
doc | 硬件与配置说明 | 板级差异、下载说明 |
apps里的示例工程通常不止一个,先挑最接近目标产品的那个,比如蓝牙音频、USB 音频或通话 Demo。打开后先找board_config.h和app_config.h:前者决定引脚和晶振,后者决定功能裁剪。isd_config.ini决定固件下载地址和校验方式,和后面 OTA 分区直接相关。库文件不要先改,改了也没有源码可编,先把它当成黑匣子,用配置和日志去判断输入输出。
2.2 编译入口与工具链怎么对齐:从 make 目标到链接脚本
常见做法是工程里提供 make 目标,或者 IDE 工程在 build log 里给出完整编译命令。如果只有 IDE 工程,就把最后一条链接命令复制出来,对照-I、-D、-T三项:头文件路径、宏定义、链接脚本。工具链版本不要混用,编译器和库不一致时,链接错误会很玄学,报错位置和真实原因经常对不上。
#!/usr/bin/env bash set -euo pipefail SDK_ROOT=$(cd "$(dirname "$0")" && pwd) export TOOLCHAIN=/opt/692n-toolchain/bin export PATH="$TOOLCHAIN:$PATH" BOARD=692N_EVB APP=bt_audio # 先清掉旧的中间文件,避免头文件依赖不全导致“改了宏但没重编” make -C "$SDK_ROOT/apps/$APP" BOARD="$BOARD" clean # 并行编译;失败时先去掉 -j,单线程看第一条错误 make -C "$SDK_ROOT/apps/$APP" BOARD="$BOARD" -j8 V=1 # 看产物段布局,防止 text/data/bss 越界 size "$SDK_ROOT/apps/$APP/out/$APP.elf"逻辑说明:脚本把工具链加入PATH,BOARD对应board_config.h里的板级宏,APP选择应用工程,V=1打开详细命令,方便确认头文件搜索路径。clean不是形式,SDK 工程常把头文件依赖写得不完整,不清理会出现“改了宏但目标文件没重编”的假象。size看text/data/bss,bss突然变大要查全局数组和缓冲区。
参数说明:TOOLCHAIN按实际安装路径改;BOARD必须与工程目录下的板级配置名一致,名字错了会走到默认板级分支;-j8按机器核数调,报错时先单线程。若工程没有 make 目标,就从 IDE 的 build log 里抄出编译和链接命令,改成脚本,后面批量编译和 CI 检查会省事。
# 查看入口地址和关键段,确认 app 没有压到 bootloader 区 readelf -h apps/bt_audio/out/bt_audio.elf | grep -E "Entry|Type" readelf -S apps/bt_audio/out/bt_audio.elf | grep -E "\.text|\.data|\.bss|\.rodata" # 从 map 文件里找较大的 bss 符号,排查 RAM 被谁吃掉 grep -E "^\s+0x[0-9a-f]+\s+.*\.bss" apps/bt_audio/out/bt_audio.map | sort -k2 -nr | head -20逻辑说明:readelf -h看入口地址是否与下载配置一致;readelf -S看段大小和加载地址;map 文件按bss排序找大数组。入口地址、下载地址、分区表三者必须一致,任何一项错位,烧录后都可能停在启动阶段。参数说明:ELF 和 map 文件名按实际工程改;grep只是过滤,不要只看第一行,重点看bss排名前几的符号是不是自己新加的缓存。
2.3 第一次编译的检查顺序:头文件、宏、库、产物
第一次编译不要从业务代码改起,按下面顺序查一遍,能少走很多弯路。先看编译命令里有没有include_lib和apps的-I路径,再看BOARD宏是否真的定义了对应板级分支,接着看库链接顺序,协议栈库一般放在应用目标文件后面,最后看产物大小和入口地址。烧录前把 flash 里原固件读回来备份,这是后面调试的后悔药。
如果编译通过但运行异常,先别怀疑库。把app_config.h里能关的功能关掉,只留最小音频通路,确认能出声后再逐项打开蓝牙、按键、LED、提示音。每打开一项就烧一次,记录现象;一次改五个宏,出了问题很难定位。这个习惯比任何调试技巧都稳。
3. 板级配置与音频通路:从 board_config.h 到喇叭出声
编译通过不代表硬件对。692N 平台把板级差异压到几个宏里,功放使能脚、晶振、串口、电池检测、音频采样率都在这里。先改板级配置再调音频,顺序反了会把软件问题当成硬件问题。我见过最多的情况是:代码没大错,功放 EN 脚电平反了,于是花半天查音频算法。
3.1 板级宏怎么落到硬件:晶振、功放使能、串口和电池检测
板级配置的第一原则是跟原理图逐脚核对,不要照抄示例。下面是一段常见写法的配置片段,引脚名和宏名要按实际 SDK 改,但检查思路一样:晶振决定时钟,功放使能决定有没有声音,串口决定能不能看日志,电池分压决定电量显示准不准。
/* board_config.h 片段:只保留入门必须对齐的几项 */ #define CONFIG_BOARD_692N_EVB 1 #define CONFIG_XOSC_HZ 24000000UL /* 按实际晶振改,不要照抄 */ #define PA_ENABLE_PIN IO_PORTA_03 #define PA_ENABLE_LEVEL 1 /* 高电平开功放,低电平关 */ #define UART_DEBUG_TX_PIN IO_PORTA_05 #define UART_DEBUG_RX_PIN IO_PORTA_06 #define BAT_DETECT_ADC_CH ADC_CH0 #define BAT_DETECT_DIV_R1 100000UL #define BAT_DETECT_DIV_R2 100000UL逻辑说明:CONFIG_BOARD_692N_EVB选择板级分支;CONFIG_XOSC_HZ影响系统时钟和音频采样,填错会出现播放速度不对、蓝牙连不上或音频断断续续;PA_ENABLE_PIN/LEVEL决定功放开关,反了就是“有波形没声音”;分压电阻用于电池电压换算,阻值填错电量会跳变。
参数说明:引脚名按实际原理图改,不要只看宏名像就填;CONFIG_XOSC_HZ用示波器或晶振丝印确认;PA_ENABLE_LEVEL用万用表量功放 EN 脚,确认是高有效还是低有效;BAT_DETECT_DIV_R1/R2按实际分压电阻填,电池电压换算公式要在代码里对一遍。
注意:先断开功放测 DAC 波形,再接功放。带功放测的时候,探头地线没接好很容易把输出短路,排查时先查电源和地,再查信号。
3.2 音频通路参数:采样率、MIC 增益、DAC 增益和 EQ
音频配置最怕一上来就开音效。采样率、MIC 增益、DAC 增益、AEC、EQ 这几项先设成直通,确认底噪和播放正常,再谈调音。蓝牙音频常用 44.1kHz 或 48kHz,通话常用 16kHz;采样率与蓝牙协商不一致会触发重采样,增加延迟,也容易听出卡顿。MIC 增益过大会削顶,DAC 增益过大会破音,EQ 先关掉是为了排除音染干扰。
| 配置项 | 入门建议 | 作用 | 改错后的现象 |
|---|---|---|---|
AUDIO_DAC_SAMPLE_RATE | 48000 | DAC 播放采样率 | 速度不对、重采样、卡顿 |
AUDIO_MIC_SAMPLE_RATE | 16000 | 通话 MIC 采样率 | 通话声音闷或断续 |
AUDIO_DAC_GAIN_DB | 0 | DAC 数字增益 | 破音或声音太小 |
AUDIO_MIC_GAIN_DB | 12 | MIC 增益 | 削顶、底噪大 |
AUDIO_AEC_ENABLE | 0 | 回声消除 | 调试时被降噪干扰 |
AUDIO_EQ_ENABLE | 0 | 均衡器 | 听不出原始底噪 |
/* audio_config.h 片段:先让通路直通,再谈音效 */ #define AUDIO_DAC_SAMPLE_RATE 48000 #define AUDIO_MIC_SAMPLE_RATE 16000 #define AUDIO_DAC_GAIN_DB 0 #define AUDIO_MIC_GAIN_DB 12 #define AUDIO_AEC_ENABLE 0 #define AUDIO_EQ_ENABLE 0 #define AUDIO_DAC_CH_NUM 2逻辑说明:DAC 48kHz 先验证喇叭和功放,蓝牙 A2DP 常见 44.1kHz 时会有重采样,入门阶段先接受这一点,确认通路正常后再统一采样率;MIC 16kHz 用于通话,AEC 先关,避免调试时被降噪干扰;DAC/MIC 增益从 0dB/12dB 起调,EQ 关闭用于听原始底噪。
参数说明:AUDIO_DAC_GAIN_DB按芯片支持的档位改,不要填任意小数;AUDIO_MIC_GAIN_DB以喊话不削顶为准,每加 3dB 听一次;AUDIO_DAC_CH_NUM单声道板子改 1,双声道改 2,改完要同步检查功放输入接法。
3.3 用测试音验证通路:从 DAC 波形到喇叭
验证音频通路不要拿一首歌反复听,用单频正弦更直接。先生成 1kHz、48kHz、16bit 的单声道 WAV,幅度从 0.2 开始,避免一开始就削顶。播放时用示波器量 DAC 输出,看峰峰值和是否有平顶;再接功放量喇叭端,扫 100Hz、1kHz、10kHz 三个点,听有没有破音和异常共振。
import math, struct, wave sr, freq, sec, amp = 48000, 1000, 3, 0.5 with wave.open("test_1k.wav", "w") as w: w.setnchannels(1) w.setsampwidth(2) w.setframerate(sr) frames = bytearray() for n in range(sr * sec): v = int(amp * 32767 * math.sin(2 * math.pi * freq * n / sr)) frames += struct.pack("<h", v) w.writeframes(frames)逻辑说明:这段脚本生成单声道 16bit 1kHz 正弦,幅度 0.5 留了余量;采样率与AUDIO_DAC_SAMPLE_RATE一致,避免测试音本身就被重采样;3 秒足够听底噪和破音。参数说明:amp从 0.2 到 0.8 逐档加,观察什么时候削顶;freq可改 100Hz、1kHz、10kHz 做扫频;如果播放速度明显不对,先查晶振和采样率,不要先改音频算法。
提示:测试音不要用 MP3,解码器、音效和蓝牙链路都会引入变量。先用 WAV 直通,把 DAC、功放、喇叭三段拆开量,再换真实音源。
4. 蓝牙连接与按键交互:协议栈事件、按键映射和提示音
音频通路通了,下一步是让产品可控。692N SDK 的蓝牙协议栈通常以库加回调形式给到应用层,应用层只处理状态机。按键和 LED 是最容易把系统拖慢的部分,因为很多新手把延时、打印和提示音播放塞进中断,最后蓝牙断连还找不到原因。把事件处理做成“只记状态、不做耗时操作”,后面查问题会轻松很多。
4.1 蓝牙事件从协议栈到应用层:连接、播放、通话状态
蓝牙回调里最忌讳两件事:一是直接写寄存器解静音,二是printf看日志。回调上下文可能很紧,串口阻塞会拖慢协议栈,表现出来就是音频断续。常见做法是回调只更新状态和置标志,音频静音、LED 切换放到主循环或任务里做。
/* app_bt_event.c:只做状态迁移,不在回调里做耗时操作 */ static bt_state_t g_bt_state = BT_STATE_IDLE; void app_bt_event_handler(bt_event_t event, void *param) { switch (event) { case BT_EVENT_CONNECTED: g_bt_state = BT_STATE_CONNECTED; led_set_mode(LED_MODE_CONNECTED); break; case BT_EVENT_A2DP_START: g_bt_state = BT_STATE_PLAYING; audio_dac_unmute(); break; case BT_EVENT_A2DP_STOP: g_bt_state = BT_STATE_CONNECTED; audio_dac_mute(); break; case BT_EVENT_SCO_OPEN: g_bt_state = BT_STATE_CALLING; audio_set_mic_path(MIC_PATH_SCO); break; case BT_EVENT_DISCONNECTED: g_bt_state = BT_STATE_IDLE; audio_dac_mute(); led_set_mode(LED_MODE_IDLE); break; default: break; } }逻辑说明:用g_bt_state记录当前状态,LED 和音频静音都从状态迁移触发;BT_EVENT_A2DP_START才解除静音,避免连接成功就出底噪;通话事件切换 MIC 通路,断开时统一静音。参数说明:事件名按 SDK 头文件改;audio_dac_mute要放在应用层,别在中断里直接写寄存器;param可能带地址或错误码,入门先不解析,但要保留打印入口,后面排查用得上。
注意:蓝牙回调里不要放
printf、延时和 flash 写操作。日志用环形缓冲异步输出,中断里只置标志,这个习惯能避开很多“日志一开就断连”的坑。
4.2 按键表与 ADC 分压:短按、长按、组合键怎么落
ADC 按键的难点不在代码,在阈值。电阻误差、电池电压变化、PCB 走线都会让分压值漂移,照抄示例表很容易出现“按音量键触发播放”。常见做法是先把每个按键的 ADC 原始值打印出来,按实测值重填表,再调消抖和长按阈值。
/* key_config.c:ADC 按键表,阈值按实测分压填 */ const key_cfg_t g_key_cfg[] = { { KEY_ID_PLAY, ADC_KEY_LEVEL_0, 10, 800, KEY_SHORT | KEY_LONG }, { KEY_ID_VOL_UP, ADC_KEY_LEVEL_1, 10, 800, KEY_SHORT | KEY_LONG }, { KEY_ID_VOL_DN, ADC_KEY_LEVEL_2, 10, 800, KEY_SHORT | KEY_LONG }, { KEY_ID_POWER, ADC_KEY_LEVEL_3, 10, 2000, KEY_LONG }, };逻辑说明:ADC_KEY_LEVEL_x对应分压档位,10是消抖毫秒,800是长按阈值;KEY_SHORT|KEY_LONG表示支持短按和长按;电源键只给长按,避免误关机。参数说明:阈值必须用实测 ADC 值重算,电阻误差和电池电压都会让档位漂移;消抖 10ms 是起点,抖动大就加到 20ms;长按 800ms 适合播放键,电源键 2000ms 更稳。
4.3 提示音与 LED 状态机:别把阻塞逻辑塞进中断
提示音和 LED 是产品体验的一部分,但也是最容易拖慢系统的部分。提示音播放要用非阻塞方式,采样率与 DAC 一致,音量单独配置;LED 用模式表,不要在按键中断里直接翻转 IO。下面这张表可以作为状态机的起点,实际项目按优先级增删。
| 系统状态 | LED 模式 | 提示音 | 优先级 |
|---|---|---|---|
| 空闲 | 慢闪 | 无 | 低 |
| 已连接 | 常亮 | 连接提示音 | 中 |
| 播放中 | 呼吸 | 无 | 中 |
| 通话中 | 快闪 | 接通提示音 | 高 |
| 低电量 | 双闪 | 低电量提示音 | 高 |
逻辑说明:状态机只根据g_bt_state和按键事件切换,提示音播放函数只负责把音频帧塞进缓冲区,不阻塞主循环。参数说明:提示音采样率必须与AUDIO_DAC_SAMPLE_RATE一致,否则会变速;音量单独用TONE_VOLUME_DB控制,不要跟音乐音量混在一起;LED 呼吸效果用定时器 PWM,不要用for循环延时。
5. 避坑与排查:五个让新手翻车的配置陷阱
692N SDK 的很多问题不是代码写错,而是配置之间不一致。下面五条是血泪经验里出现频率最高的,按“现象→原因→解决”记,比临时翻日志快。每条都建议先复现一次,再动手改,不然很容易把新
本文还有配套的精品资源,点击获取