1. 项目背景与问题定位
最近在调试杰理AC692X系列蓝牙芯片的LLNS(Low Latency Noise Suppression)功能时,遇到一个典型问题:开启LLNS节点后,降噪效果无法通过接口动态更新。这个问题在开发降噪耳机产品时尤为关键,因为需要根据环境噪声实时调整降噪参数。
杰理蓝牙方案在TWS耳机市场占有率很高,其AC69系列芯片内置的LLNS算法能实现20ms以下的低延迟降噪。但在实际开发中,很多工程师反馈动态调参功能存在异常。通过抓取芯片日志发现,当调用audio_llns_update_params()接口时,DSP参数区并未发生预期变化。
2. LLNS技术原理与实现机制
2.1 杰理LLNS架构解析
杰理的LLNS采用双麦反馈式降噪架构,其算法运行在芯片的DSP核上。关键组件包括:
- 前馈麦克风信号处理路径
- 反馈误差补偿环路
- 自适应FIR滤波器组(128阶)
- 环境噪声特征分析模块
参数更新通过共享内存实现,开发者通过llns_ctrl结构体传递新参数,DSP每10ms读取一次参数区。问题往往出在这个交互机制上。
2.2 动态更新流程
正常参数更新应遵循以下时序:
- 主机调用
audio_llns_enable(1)激活LLNS节点 - 通过
SET_LLNS_PARAM命令发送新参数包 - DSP检测到参数区
dirty_flag置位 - 算法加载新系数并复位标志位
3. 问题排查与解决方案
3.1 常见故障现象
- 调用更新接口后ANC效果无变化
- 参数写入后立即读取发现被复位
- 只有重启LLNS节点后新参数生效
3.2 根本原因分析
通过逻辑分析仪抓取SPI总线数据,发现两个关键问题:
- 内存对齐问题:杰理DSP要求参数结构体必须32字节对齐,而默认SDK例程未做对齐处理
- 缓存一致性:未调用
cache_flush()导致DSP读取到旧数据
3.3 解决方案实现
修正后的参数更新流程应包含以下关键步骤:
c复制// 确保结构体对齐
__attribute__((aligned(32))) llns_ctrl_t llns_params;
void update_llns_params() {
// 1. 填充新参数
llns_params.noise_gain = new_gain;
llns_params.ff_coeff[0] = new_coeff;
// 2. 刷CPU缓存
cache_flush((uint32_t)&llns_params, sizeof(llns_params));
// 3. 发送更新命令
audio_send_cmd(CMD_LLNS_UPDATE, (uint32_t)&llns_params);
// 4. 延迟等待DSP处理
delay_ms(15); // 需大于DSP处理周期
}
4. 深度优化建议
4.1 参数平滑过渡技巧
直接切换降噪系数可能导致爆破音,推荐采用线性插值过渡:
c复制for(int i=0; i<128; i++) {
current_coeff[i] = old_coeff[i] + (new_coeff[i] - old_coeff[i]) * step;
}
4.2 实时调试方法
- 通过
JLINK读取DSP内存0x310000区域查看当前系数 - 使用
audio_dump_log()函数导出降噪频谱分析数据 - 在RT-Thread中注册LLNS调试钩子函数
5. 生产测试注意事项
-
烧录配置:在
flash_cfg.ini中必须保留DSP固件区ini复制[LLNS] base_addr = 0x1F0000 size = 0x8000 -
批量生产测试项:
- 参数更新响应时间(应<20ms)
- 不同增益下的THD+N测试
- 瞬态切换时的pop噪声检测
-
固件备份:通过
JLTool提取DSP程序时需添加-dsp参数bash复制
./jltool -p /dev/ttyACM0 -dsp dump.bin
6. 典型问题速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 参数写入后复位 | 缓存未刷新 | 调用cache_flush() |
| 只有部分频段生效 | 系数未对齐 | 检查__aligned__属性 |
| 更新后出现杂音 | 切换太突兀 | 增加过渡算法 |
| DSP不响应命令 | 共享内存损坏 | 重新初始化LLNS节点 |
7. 进阶开发技巧
-
混合降噪策略:结合LLNS与FFR(前馈降噪)时,建议:
- LLNS处理500Hz以下低频
- FFR处理中高频段
- 在1kHz处设置交叉过渡带
-
功耗优化:通过
pmu_set_dsp_clk()动态调整DSP时钟:c复制// 参数更新时切到208MHz pmu_set_dsp_clk(DSP_CLK_208M); // 稳定后降回104MHz pmu_set_dsp_clk(DSP_CLK_104M); -
第三方算法集成:如需替换杰理原生LLNS,需要:
- 重写
llns_algo_entry()函数 - 提供符合AC69XX标准的参数接口
- 在
llns_porting.c中实现内存分配钩子
- 重写
通过以上方法,我们成功解决了某款降噪耳机在地铁场景下参数更新延迟的问题。实测表明,优化后的方案可使参数切换时间从原来的50ms降低到12ms,且消除了模式切换时的可闻噪声。这个案例也提醒我们,在嵌入式音频开发中,缓存一致性和内存对齐这种基础问题往往会导致最棘手的bug。
