资讯动态

AB1568蓝牙耳机ANC调试与固件事件链路实战

发布时间:2026/10/29 20:57:16 来源:尧图企业网站定制
简介针对Airoha洛达AB1568蓝牙耳机芯片的应用开发指南面向已具备嵌入式与蓝牙协议基础的中高级开发者以及需要快速上手该平台固件的耳机项目工程师。内容围绕headset工程展开覆盖上电后执行的初始化函数、mk文件中的宏定义管理、app活动行为开启、ANC主动降噪模式与切换、LED呼吸灯样式修改、充电参数监测、超时时间设置与事件收发删除机制、Airoha API使用参考、回调函数注册调用、自动关机与配对时间配置、开机提示电量、清除配对列表及链路丢失重连等模块并延伸至UI Shell框架、SideTone设置、音频路径设置、DUT模式射频测试、硬件复位与PEQ设定、通话降噪及iGO算法。资源包为1个PDF文档体积约9.58MB按二十余个专题分章编排目录层级清晰可当作随手查阅的工程手册逐节对照代码定位实现。目前已有374人学习适合作为开发调试阶段的模块化参考资料。1. 从一次“有提示音却没降噪”的调试说起AB1568 蓝牙耳机应用开发到底拆什么AB1568 蓝牙耳机应用开发最耗时间的往往不是写一个按键回调而是把上电执行链路、mk 宏、UI Shell 事件、ANC 参数和 NVKEY 固化串成一条能验证的线。我遇到过一套 headset 工程三连击电源键有提示音耳朵里却听不到降噪变化查到最后是按键行为映射对了但声学 NVR 没写进 download 文件。这个资源适合已经能编译、想系统拆 ANC、事件、FOTA、产测链路的固件工程师新手可以照着步骤复现熟手重点看参数边界和排查顺序。2. 从 build.sh 到上电 mainAB1568 headset 工程的编译入口与宏定位2.1 先找编译命令调用的 mk 文件而不是全局搜宏AB1568 SDK 里条件编译宏很少只放在一个总头文件里尤其是 FOTA、ANC、日志这类开关常见做法是放在 GCC 目录下的 mk 文件里由编译命令决定包含哪一份。你如果直接在整个 SDK 里全局搜宏名会搜到一堆同名定义最后改错文件编译 log 里却看不到自己的-D这一步最容易翻车。我一般先让构建脚本自己把工程和板级目标列出来cd $SDK_ROOT ./build.sh list # 在输出里找 headset 参考工程对应的板级目标 # 重点看这一行调用的 feature 配置文件名 # 例如输出里会提示某个 feature_xx_evk.mk这段命令的逻辑是让构建系统告诉你“当前工程到底吃哪份配置”而不是靠猜。参数上$SDK_ROOT换成你本地 SDK 根目录list是构建脚本提供的查询子命令不同版本可能叫法略有差异但一般都会打印工程名、板级目标和 feature 文件。拿到 feature 文件名后再去 GCC 目录里打开它确认 ANC 使能宏、FOTA 宏、日志宏是否已经打开。当前头戴耳机工程如果是基于 AB1568 评估板工程改出来的就不要拿别的板级 feature 文件硬套编译命令和 mk 文件必须对得上。构建项常见位置怎么确认工程入口apps下 bootloader 与 headset 工程看build.sh list输出的工程名宏定义GCC 目录下 feature mk 文件看编译命令实际包含哪个 mkFOTA 开关bootloader 侧 mk 文件确认BL_FOTA_ENABLE是否定义ANC 开关应用侧 feature mk 文件确认 ANC 使能宏是否打开日志开关应用侧 feature mk 文件确认调试 log 宏是否打开2.2 上电执行链路bootloader main、app main 与 apps_inits上电后先跑的不是 headset 应用工程的main而是apps下 bootloader 的main。这一步很多人会忽略结果在应用侧死等一个初始化日志实际上系统还停在 bootloader 阶段。bootloader 里常见的条件是BL_FOTA_ENABLE这个宏在 GCC 目录的 mk 文件里定义后bl_fota_process函数才会成为被编译的代码宏没开函数体根本不进固件你加打印也看不到。/* bootloader 侧BL_FOTA_ENABLE 在 GCC 目录的 mk 文件里定义后 * bl_fota_process 才会被编进固件 */ int main(void) { #ifdef BL_FOTA_ENABLE bl_fota_process(); #endif boot_to_application(); } /* 应用侧headset 工程的 main 在 bootloader 之后执行 */ int main(void) { apps_inits(); /* 初始化应用模块、活动、事件组 */ ui_shell_start(); /* 启动 UI Shell 调度具体函数名以 SDK 为准 */ while (1) { ui_shell_schedule(); /* 常见主循环入口按本地工程替换 */ } }这段伪代码的重点是执行顺序不是让你照抄函数名。BL_FOTA_ENABLE控制的是 bootloader 里 FOTA 处理逻辑是否参与编译apps_inits负责把应用模块、活动、事件组初始化起来ui_shell_start之后UI Shell 才开始调度活动。调电源键开机问题时先确认串口 log 有没有过 bootloader再看应用侧apps_inits后面有没有活动注册成功。如果 log 停在 bootloader就不要去改 ANC 参数方向已经错了。2.3 宏定义放在哪feature mk 的层级与覆盖顺序GCC 目录下会有多份 mk 文件编译不同工程时调用的文件不同。常见做法是把项目自己的开关追加到项目级 feature 配置里不要直接改 SDK 公共 mk否则下次换工程或升级 SDK改动容易被覆盖。宏的本质是编译期-D写进 mk 后要重新编译才生效改完不 clean 还可能被缓存骗过去。# 在项目自己的 feature 配置里追加不要直接改 SDK 公共 mk CFLAGS -D平台ANC_ENABLE宏 CFLAGS -DDEBUG_LOG_ENABLE这里的平台ANC_ENABLE宏要换成你本地 mk 文件里实际存在的 ANC 使能宏名输入资料里这个宏带平台前缀实际以工程里的写法为准不要照抄占位符。CFLAGS -D...等价于在代码里写#define ...但作用范围是整次编译。参数上ANC 宏不开按键事件组里进入 ANC 分支的代码可能直接被条件编译掉日志宏不开ANC 切换时的anc_result就看不到排查会变成黑匣子。提示改 feature mk 前先备份原文件改完执行一次 clean build再在编译输出里搜-D确认宏真的传进去了。3. UI Shell 事件与活动把 app 行为、超时和自动关机串起来3.1 活动进程与事件组app_preproc_activity_proc 为什么能管 home screenAB1568 的 UI Shell 把每个 UI 界面抽象成活动进程。ui_shell_start_activity为活动在活动堆里申请一个 itemapp_preproc_activity_proc是主进程负责管理和调配其它子进程比如app_home_screen_idle_activity_proc。开机后系统会开启很多不同进程每个进程里有自己的事件组。系统产生事件时会把事件抛出去所有进程都能监听到但只有事件属于自己事件组时才处理。这个机制的好处是按键、ANC、充电、低电这些事件不用到处写全局判断坏处是事件 ID 和事件组一旦冲突现象会很玄学。/* 活动定义home screen 只处理自己事件组里的事件 */ static const ui_shell_activity_t app_home_screen_activity { .activity_id APP_HOME_SCREEN_ID, .event_group app_home_screen_event_group, .proc app_home_screen_proc, }; /* 事件分发返回 true 表示消费false 表示继续往上抛 */ static bool app_home_screen_proc(ui_shell_activity_t *self, uint32_t event_id, void *extra_data, size_t data_size) { switch (event_id) { case EVENT_ID_KEY: return app_home_screen_proc_key_event_group(self, extra_data, data_size); case EVENT_ID_ANC_UPDATE: return app_home_screen_process_anc_and_pass_through(self, extra_data, data_size); default: return false; } }这段代码的逻辑是“活动注册自己关心的事件组分发函数只处理认识的 event_id”。参数上activity_id要和ui_shell_start_activity注册时用的 ID 一致event_group决定哪些事件能进来proc返回值决定事件是否继续传递。常见误用是把所有事件都返回true结果别的活动收不到按键或者事件 ID 用了局部数字和别的模块撞车。我的习惯是事件 ID 统一放在一个头文件里命名带模块前缀处理函数里先打一行event_id再分支。3.2 ui_shell_send_event 与 ui_shell_init_input_msg事件发送、接收和删除ui_shell_send_event用来发事件ui_shell_init_input_msg用来接收消息ui_shell_remove_event用来删除还没触发的事件。自动关机、配对时间、开机提示电量这类延时动作最好都走事件不要在回调里直接delay阻塞主循环。下面这段是常见写法函数参数顺序以你本地 SDK 为准重点看参数含义。/* 发送一个 30000ms 后触发的自动关机事件 */ ui_shell_send_event(false, EVENT_PRIORITY_NORMAL, EVENT_GROUP_UI_SHELL_APP, EVENT_ID_AUTO_POWER_OFF, NULL, 0, 30000, 0); /* 关机前删掉未触发的事件避免重新开机被旧事件立刻关机 */ ui_shell_remove_event(EVENT_GROUP_UI_SHELL_APP, EVENT_ID_AUTO_POWER_OFF);这段代码里false通常表示不是立即发送EVENT_PRIORITY_NORMAL是优先级EVENT_GROUP_UI_SHELL_APP是目标事件组EVENT_ID_AUTO_POWER_OFF是事件 IDNULL, 0是携带数据30000是延时毫秒数最后一个参数按 SDK 定义填标志。删除事件时事件组和事件 ID 必须和发送时完全一致不然删不掉。血泪经验是自动关机事件触发后如果没删设备重新开机又会被旧事件拉去关机看起来像“开机秒关”的硬件故障。3.3 回调注册与超时参数自动关机、配对时间、开机提示电量回调注册的核心是“到点只做判断不直接干重活”。自动关机回调里要再判断一次当前是否空闲、是否在充电、是否在播放不要看到定时器到点就关机。配对时间设置也是同理超时后进入可配对状态但如果有连接或播放就不应该被配对定时器打断。开机提示电量可以延迟几百毫秒发事件等音频路径初始化完再播报避免提示音被切掉。static void app_power_off_timer_cb(void *user_data) { /* 回调里再判断一次空闲状态不要看到定时器到点就关机 */ if (app_is_idle() !app_is_charging()) { app_power_off(); } } /* 常见做法注册一次性定时回调保存 id 方便删除 */ g_power_off_timer_id ui_shell_register_timer_cb( EVENT_ID_AUTO_POWER_OFF, 300000, app_power_off_timer_cb, NULL);300000是 5 分钟配对时间常见设 90000 到 120000 毫秒开机提示电量可以设 300 到 500 毫秒延迟。参数不要拍脑袋自动关机时间要大于配对时间否则用户还没配对完设备就关了充电中要取消或暂停自动关机清除配对列表后要重启广播不要只删 NVKEY 不重启。链路丢失重连也别用死循环常见做法是用事件做退避重试2 秒、4 秒、8 秒各试一次还失败就回到可配对状态。LED 呼吸灯样式同样建议用事件切状态不要在定时器里直接翻转 GPIO否则充电、配对、低电几个状态会互相抢灯。场景建议超时事件 ID 示例注意点自动关机300000msEVENT_ID_AUTO_POWER_OFF充电、播放、配对中不关机配对时间90000msEVENT_ID_PAIRING_TIMEOUT有连接时取消定时器开机提示电量300msEVENT_ID_BATTERY_ANNOUNCE等音频路径就绪再播链路丢失重连2s/4s/8sEVENT_ID_RECONNECT退避重试不阻塞主循环4. ANC 模式切换与参数固化从 key_action 到 app_anc_service_enable 的完整链路4.1 按键行为映射KEY_SWITCH_ANC_AND_PASSTHROUGH 怎么落到 customerized_key_config.c在 home screen 状态下用按键切 ANC第一步不是调 ANC 服务而是让按键事件进入_proc_key_event_group处理并且确认 ANC 使能宏已经打开。按键行为key_action有几个关键值KEY_PASS_THROUGH是通透模式开关KEY_ANC是 ANC 开关KEY_SWITCH_ANC_AND_PASSTHROUGH是全关到通透开再到 ANC 开KEY_BETWEEN_ANC_PASSTHROUGH是通透开和 ANC 开之间切换。物理按键动作到这些行为的映射常见做法是放在customerized_key_config.c里。/* customerized_key_config.c物理按键动作到 ANC 行为的映射 */ static const key_action_map_t g_key_action_map[] { { KEY_ID_POWER, KEY_ACTION_TRIPLE_CLICK, KEY_SWITCH_ANC_AND_PASSTHROUGH }, { KEY_ID_POWER, KEY_ACTION_DOUBLE_CLICK, KEY_BETWEEN_ANC_PASSTHROUGH }, { KEY_ID_POWER, KEY_ACTION_LONG_PRESS, KEY_PASS_THROUGH }, };这段映射表的逻辑是“哪个键、什么动作、对应哪个 ANC 行为”。参数上KEY_ID_POWER是电源键KEY_ACTION_TRIPLE_CLICK是三连击。三连击后如果有提示音但没有降噪效果先别怀疑按键映射直接去 Config Tool 打开工程的 download 文件夹看 ANC 参数有没有调整。参数没导入时按键行为再对app_anc_service_enable拿到的滤波器增益也可能是空的。4.2 ANC 执行链路target_anc_type、target_filter_id 与 app_anc_service_enableANC 用 FF 麦和 FB 麦实现FBC 是 FB 的补偿。Config Tool 上常见有三类参数ANC、FBC、PassthroughANC 里面包含 FF 和 FB。硬件上会有 1 个主麦负责说话、2 个振动喇叭、2 个声音喇叭音频降噪用 FF 和 FB通话降噪用 talk 麦和 FF。按键行为改变的是target_anc_type和target_filter_id再传给app_anc_service_enable执行。/* 按键进入 ANC 处理函数后先改目标类型和滤波器 ID再调服务 */ static void app_home_screen_process_anc_and_pass_through(key_action_t key_action) { uint8_t target_anc_type; uint8_t target_filter_id; switch (key_action) { case KEY_SWITCH_ANC_AND_PASSTHROUGH: target_anc_type AUDIO_ANC_CONTROL_ANC_TYPE_FF_FB; /* ANC 开 */ target_filter_id AUDIO_ANC_CONTROL_ANC_FILTER_DEFAULT; /* 默认滤波器值为 1 */ break; case KEY_PASS_THROUGH: target_anc_type AUDIO_ANC_CONTROL_ANC_TYPE_PASS_THRU; /* 通透 */ target_filter_id AUDIO_ANC_CONTROL_PASS_THRU_FILTER_DEFAULT; /* 值为 9 */ break; default: return; } app_anc_service_enable(target_anc_type, target_filter_id); }枚举名以本地 SDK 为准重点是两个参数target_anc_type决定 ANC 还是通透target_filter_id决定用哪组滤波器。ANC 默认滤波器是值为 1 的枚举PassThrough 默认滤波器是值为 9 的枚举。声学参数里常见四组滤波器Filter 1 到 Filter 4每组包含 FF1(L/R)、FB1(L/R)、FBC1(L/R)一直到 Filter 4。切 ANC 时看 log 就过滤anc_result确认三个模式循环切换时滤波器 ID 有没有真的变。4.3 参数从 Config Tool 到固件Import NVR、Special_Export 和 nvkey.xml调 ANC 最怕“工具里调好了固件里没固化”。正确顺序是先 clean build 生成最新 download再用 Config Tool 打开 download 文件夹Import NVR 导入声学调好的参数Write NV 后 Reset循环三连击听效果。确认有效果后再把参数固化到代码Config Tool 打开 download导入 NVR用 Special_Export 导出变更到文件常见会得到 XML 和 bin 文件如果用 Save 方式保存成 download生成文件数量会少一些但syskey和 bin 文件的内容要能对上。# 参数固化顺序先 clean build 生成最新 download再导入 NVR 和导出变更 ./build.sh clean ./build.sh board_target headset_project # 用 Config Tool 打开 download 目录Import NVR 后核对 ANC 参数 # 再用 Special_Export 导出变更更新工程里的 nvkey.xml 和 filesystem.bin # 最后重新编译下载验证这段命令的逻辑是先保证 download 是当前代码编出来的避免工具打开的是旧目录。参数上board_target和headset_project用build.sh list输出里的实际名字替换。Special_Export 导出的syskey.xml里变更的 keyID要一一更新到工程用于编译的多个nvkey.xml文件里有的就替换没有的就添加。注意0xEE00到0xEEFF这段 ANC 参数 keyID 在nvkey.xml里可能没有需要补进去filesystem.bin也要同步替换。重新编译后用 Config Tool 打开新 download如果 ANC 参数变成刚才 NVR 的配置说明固化成功。NVR 里 Component Gain 的解析也容易翻车。比如0xE1E5 10FF 1400 D8DC D8DC解析时前后位反转10FF变成FF10十六进制转十进制再减 65536得到 -240对应 -2.4dB1400反转成0014十进制 20对应 0.2dB。def parse_component_gain(hex_le: str) - float: 输入 10FF 这种小端十六进制返回 dB 值 raw int(hex_le[2:4] hex_le[0:2], 16) # 10FF - FF10 if raw 32767: raw - 65536 return raw / 100.0 print(parse_component_gain(10FF)) # -2.4 print(parse_component_gain(1400)) # 0.2这段 Python 的逻辑是处理小端字节序和负数补码。参数上输入是两个字节的十六进制字符串返回值单位是 dB除以 100 是因为原始值放大了 100 倍。FOTA 更新 NVkey 时同样用 Special_Export 导出变更再通过NVKEY_Setting.c里的写 NVkey 函数或 FOTA 包写入只更新固件 bin 不更新 NV 文件升级后 ANC 参数会回到默认这是很常见的翻车点。保存方式常见产物用途风险Config Tool Savedownload 文件、少量 XML/bin本机验证容易被下一次 build 覆盖Special_Exportsyskey.xml、nvkey.xml、filesystem.bin固化到编译工程keyID 要逐个核对FOTA 更新 NVkeyNV 写函数或升级包量产升级漏写 NV 会导致参数回退5. 避坑与排查ANC、事件、宏和烧录最容易翻车的五个点5.1 ANC 类有提示音没降噪、滤波器不变、FOTA 后参数回退现象三连击 POWER 有提示音但左右耳降噪没有变化。原因key_action映射已经生效但 Config Tool 打开 download 后 ANC 参数没有调整FF/FB/FBC 滤波器增益为空或为 0app_anc_service_enable执行了也没有实际效果。解决先把声学调好的 NVR 文件 Import 到 downloadWrite NV 后 Reset循环三连击听效果确认有效果后再用 Special_Export 固化到nvkey.xml和filesystem.binclean build 后重新下载。现象log 里target_anc_type变了anc_result却一直不变。原因ANC 使能宏没开或者开了但按键事件没进入 ANC 分支也可能是target_filter_id越界。解决去 feature mk 确认 ANC 宏过滤anc_result看滤波器 ID 是否从 1 切到 9再看四组滤波器参数是否只配了 Filter 1切到 Filter 2 时没有数据。现象FOTA 升级后 ANC 参数回到默认。原因只更新了应用固件没有把 NVkey 变更打进升级包或者NVKEY_Setting.c里没有写对应 keyID。解决用 Special_Export 导出变更核对NVKEY_Setting.c写入函数FOTA 包带上filesystem.bin升级后读 NV 验证不要只看版本号。5.2 事件类自动关机重复触发、按键偶发无响应、配对时间被覆盖现象自动关机时间到了关机重新开机后马上又关机。原因一次性定时事件触发后没有ui_shell_remove_event旧事件还在队列里重新开机又被消费。解决关机流程先删事件回调里再判断app_is_idle()和充电状态不满足就重新注册不要无条件关机。现象home screen 按键偶发无响应。原因事件 ID 和别的活动冲突或者处理函数对所有事件都返回true把按键事件错误消费了。解决事件 ID 统一宏管理处理函数先打印event_id不认识的返回false让事件继续传递。现象配对时间设了 90 秒实际 30 秒就超时。原因多个定时器共用一个事件 ID后注册的覆盖前一个或者配对定时器没在连接建立后删除。解决自动关机、配对、重连各用独立事件 ID保存 timer id连接成功时删配对定时器。5.3 编译与烧录类宏改了没生效、download 被覆盖、USB log 口不对现象改了 mk 宏编译 log 里搜不到-D。原因改错 feature 文件或者没有 cleanccache 用了旧对象。解决先用build.sh list确认工程调用的 mkclean 后 build在编译输出里搜宏名还不行就看编译命令有没有包含你改的文件。现象Config Tool 打开 download 看到 ANC 参数是旧的。原因先导入 NVR 后 buildbuild 又把 download 覆盖了。解决顺序固定为 clean build、Config Tool 导入/导出、更新 nvkey.xml、再 build、最后下载验证。现象USB 口打 log 乱码或无输出。原因波特率不对、log 口复用、USB 通信模式和 ATCMD 冲突。解决先确认 USB 口通信/打 log 配置再用 RACE/RAW 指令小流量验证最后才开高速日志。5.4 产测与 RF 类DUT 模式进不去、AT 转 Race 格式错、清配对后不重连现象DUT 模式测 RF 没响应。原因产测测试模式没进对或者硬件复位时序不对。解决按产测流程先做硬件复位再发 ATCMD确认设备信息能读出来再进 DUT 测 RF。现象AT 转 Race 指令格式错。原因帧头、长度、校验没对齐。解决用 USB 抓包对照 AT 转 Race 格式先发最简单的读设备信息命令逐字节核对。现象清除配对列表后链路丢失不重连。原因NVKEY 清了但重连策略还引用旧 bond 信息或者清列表后没有重启广播。解决清列表后重启广播链路丢失重连用事件退避重试不要死等。6. 用日志和产测指令把 ANC 切换验证成可重复流程一张检查表和三个命令ANC 调完后我一般不再靠“耳朵听三连击”做唯一验证而是把日志、配置和产测指令串成固定检查表。先 clean build 生成 download用 Config Tool 读回 ANC 参数确认四组滤波器都有值再下载固件三连击切模式串口过滤anc_result、target_anc_type、target_filter_id看滤波器 ID 是否按 1、9 循环最后进 DUT 模式测 RF用 ATCMD 读设备信息确认升级或复位后参数没丢。验证层级看什么通过标准编译产物download 里的 ANC 参数FF/FB/FBC 四组滤波器有值运行时日志anc_result、target_filter_id三连击时 ID 按预期切换产测链路DUT 模式、ATCMD、RACE/RAW能读设备信息RF 测试有响应升级后FOTA 后 NVKEYANC 参数不回退串口日志存文件后用一条命令把本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑