ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

全志T527音频调试实战:从设备树到ALSA链路排查指南

全志T527音频调试实战:从设备树到ALSA链路排查指南 BSP调试系列总算写到音频了。说实话Audio这个模块在BSP里是最让人又爱又恨的爱的是它不像显示、触摸那样涉及复杂的驱动框架恨的是不出问题则已一出问题就是“无声”“杂音”“断断续续”这类高度相似的现象定位起来非常磨人。这次拿全志T527这个平台来梳理是因为它在智能座舱、工业HMI、边缘计算盒子里用得越来越多而它的音频链路足够完整——I2S、PDM、Codec、功放、蓝牙、HDMI都可能出现在一台设备上非常适合当典型案例来拆。这篇文章适合刚接手BSP音频调试的驱动工程师、做方案硬件选型和集成的软硬件工程师以及写产测音频脚本的开发同学。我会尽量把整条音频链路的每个环节都讲清楚包括设备树怎么配、用户空间工具怎么用、无声和杂音到底怎么一步步定位最后再放一张速查表和几段踩坑记录。哪怕你不做全志平台这套排查思路换到任何Linux音频栈上都一样适用。1. 动手之前先搞清楚音频链路1.1 一段声音从App到喇叭到底经过了多少环节很多人拿到音频问题就急着改驱动、改设备树结果越改越乱根本原因是没把“声音从哪来、要往哪去”的链路画清楚。我把这条链路拆成七个环节你可以把它想象成一条物流线。应用层调用ALSA库的write()接口把PCM数据交给内核这是第一环节。内核的PCM设备层负责管理缓冲区应用写入的数据先暂时存在DMA buffer里这是第二环节。Platform驱动也叫DAI驱动控制DMA控制器把内存里的音频数据搬到SoC内部I2S控制器的FIFO里这是第三环节。I2S控制器按照格式化的时序把数据串行发到Codec芯片这是第四环节。Codec芯片完成数字到模拟的转换、模拟增益调节、混音、通路切换这是第五环节。之后信号进入功放功放把模拟信号放大到能够驱动喇叭的功率级别这是第六环节。最后喇叭发声这是第七环节。这条链路上任何一环断了现象都可能是同一个没声音。比如应用没写数据、DMA没搬运、I2S格式不对、Codec通路没打开、功放没使能全都表现为“喇叭不响”。如果不把链路装在脑子里排障就只能瞎试。1.2 为什么Audio在BSP里最容易让人“束手无策”音频调试难不是因为代码量巨大而是“现象收敛、原因发散”。网络问题还能ping一下看通不通显示问题还能肉眼看到花屏还是黑屏唯独音频问题喇叭不响就是三个字但背后的原因可能有十几种。而且关键的是硬件层面的很多因素也会直接表现成软件时序问题比如Codec的MCLK频率偏了听起来就像采样率不对功放的供电纹波大听起来就是底噪I2S数据和地的接触不良直接就是劈里啪啦的杂音。再加上很多工程师习惯用“试”的方式去解决问题改一个寄存器测一次不行再改回去。这种方式在音频上效率极低因为一次改动可能涉及Codec内部多条通路改A影响了B现象反而更复杂。正确做法是先建立完整的链路认知再逐个节点去探而不是上来就乱动。1.3 全志T527音频平台的软硬件构成全志T527采用标准的内核ALSA/ASoC音频框架。所谓ASoC是ALSA在嵌入式SoC上的扩展把音频驱动拆成三个部分Machine驱动板级音频拓扑、Platform驱动SoC的I2S控制器和DMA、Codec驱动音频编解码芯片。这个拆分是理解T527音频调试的总钥匙。T527的音频硬件形态取决于具体硬件设计一般有两种一种是直接用SoC内部Audio Codec链路比较短不太容易出硬件时序问题另一种是外挂Codec搭配独立功放这在智能座舱产品里很常见因为外部Codec的DAC信噪比更高、支持的通路更多。这两种形态在软件上对应同一个ASoC框架区别主要体现在设备树节点和Codec驱动上。无论哪种形态你手里必备的调试工具就三样tinymix、tinyplay、tinycap。这三个命令会贯穿整篇调试文章。2. 设备树里的音频配置细节全在这里2.1 sound节点把CPU、Codec、DAI串起来的关键在设备树里音频相关配置的核心是sound节点。它的作用是把Machine驱动需要的信息串在一起告诉内核“我这个板子上I2S控制器接的是哪个Codec用什么格式通信”。一旦这个节点的配置错了后面的调试全白做。以T527 SDK中常见的simple-audio-card风格的节点为例实际节点名和属性以你的SDK为准sound: sound { compatible simple-audio-card; simple-audio-card,name t527-audio; simple-audio-card,format i2s; simple-audio-card,mclk-fs 256; simple-audio-card,widgets Speaker, Speaker, Headphone, Headphone; simple-audio-card,routing Speaker, SPK, Headphone, HP; status okay; simple-audio-card,cpu { sound-dai i2s0; }; simple-audio-card,codec { sound-dai codec; }; };这里重点看几个属性。simple-audio-card,format定义的是DAI数据格式常见取值是i2s、left_justified、right_justified、dsp_a、dsp_b。Codec和SoC的I2S控制器必须工作在完全相同的模式下否则信号虽然能传过去但数据位错位表现就是播出来的声音沙哑、变调甚至只有刺耳噪声。simple-audio-card,cpu里的sound-dai引用SoC的I2S控制器节点simple-audio-card,codec里的sound-dai引用Codec节点这两个引用必须和你实际硬件走线一一对应。我见过一个项目PCB上音频数据走的是I2S0设备树里却引用了I2S1结果系统也能出声但采样率一高就错乱查了很久才发现是引用错了。这种低级错误最容易在赶进度的时候出现。2.2 Codec节点与MCLK时钟没时钟神仙也难救Codec节点是音频调试的另一个重灾区。以一颗典型的外挂Codec为例设备树里通常要配供电、时钟、I2C地址、复位和中断引脚。这里我要重点讲MCLK主时钟它是Codec正常工作的大前提。Codec芯片内部要做Σ-Δ调制、数字滤波、时钟分频这些都必须依赖一个主时钟MCLK。MCLK频率不是随便给的它必须是音频采样率的整数倍业界通常用256倍或者512倍。比如采样率48kHzMCLK该给12.288MHz采样率44.1kHzMCLK该给11.2896MHz。在simple-audio-card配置里mclk-fs 256的意思就是让内核自动把MCLK配置成采样率的256倍。全志T527的时钟框架一般会自动处理这部分但前提是Codec节点的clocks属性正确指向了可用的时钟源。调试时一定要学会看时钟树在shell里执行cat /sys/kernel/debug/clk/clk_summary | grep -i mclk然后一边播放不同的采样率文件一边观察这个频率是否跟着变。如果MCLK始终是某个固定值或者直接为0就说明时钟配置没对上Codec自然无法正常解码。很多“播放有杂音”“播放变调”的问题根源都是MCLK没到位。2.3 GPIO控制功放使能、耳机检测比想象中更重要在BSP音频调试里GPIO控制常常被忽视但这里其实埋着最多的隐性故障。功放使能脚通常叫PA_EN或SPK_EN、耳机检测脚HP_DET、按键检测脚耳机的音量加减键都会接到SoC的GPIO上设备树里必须把这些GPIO正确配置并关联到驱动里。功放使能是最容易出问题的地方。有的硬件设计是高电平使能功放有的却是低电平使能DTS里的GPIO_ACTIVE_HIGH和GPIO_ACTIVE_LOW一旦写反功放就不会工作。更隐蔽的是时序问题开机时如果功放比Codec先上电Codec还在初始化、输出端有不稳定电平功放就会把这段噪声放大产生“开机爆音”。解决思路通常是把功放使能延后到Codec输出稳定之后或者利用Codec的Mute控制脚先静音再开功放。耳机检测也有类似细节。耳机插入时HP_DET引脚电平会变化触发SoC的中断或轮询机制Codec驱动通过jack检测上报事件上层再切换音频路由。如果DTS里GPIO极性配反就会出现“插入耳机反而外放”“拔出耳机还显示耳机模式”的怪现象。排查这类问题先在shell里看这个GPIO的当前电平和中断是否触发cat /sys/kernel/debug/gpio在播放音乐的状态下插拔耳机观察对应引脚的电平变化比直接看代码高效得多。2.4 一段可参考的DTS配置模板上面讲了一堆理论这里给一个综合的配置模板涵盖了I2S节点、Codec节点和sound节点之间的关系。注意T527不同版本SDK的节点组织方式会有差异模板提供的是思路不是能直接编译的成品。i2s0 { pinctrl-names default; pinctrl-0 i2s0_pins; status okay; }; codec { #sound-dai-cells 0; status okay; }; sound { compatible simple-audio-card; simple-audio-card,name t527-audio; simple-audio-card,format i2s; simple-audio-card,mclk-fs 256; simple-audio-card,widgets Speaker, Speaker; simple-audio-card,routing Speaker, SPK; status okay; simple-audio-card,cpu { sound-dai i2s0; }; simple-audio-card,codec { sound-dai codec; }; };pinctrl配置要注意I2S的引脚功能必须复用正确否则BCLK、LRCK、DATA根本没有输出到芯片外部。全志平台的pinctrl设置一般在SoC dtsi里已经定义好板级只需要选择对应的pinctrl-0即可。如果这一步配错示波器测量I2S引脚会没有任何波形但内核不会报任何错误很容易让人误判硬件故障。3. 三板斧排查工具tinymix、tinyplay、tinycap3.1 tinymix把音频通路上的水龙头全部拧开音频调试三个命令里tinymix是使用频率最高的。它的作用就是查看和设置Codec内部的混音器控件相当于控制音频通路上的所有“水龙头”。Codec内部有DAC开关、ADC开关、各种Mixer通路、音量寄存器这些全部通过tinymix暴露出来。刚上板的第一件事先跑一个裸命令看看有哪些控件tinymix输出会列出所有控件的名称和当前的数值。比如你会看到DAC Playback Volume、Speaker Volume、PGA Capture Volume、MICBIAS Switch这类名字。很多无声问题的直接原因就是某个关键的开关没有打开或者音量被设置成了0。对于全志T527这类平台常见的操作是把播放通路的开关先全部打开# 打开DAC播放开关 tinymix DAC Playback Switch 1 # 设置DAC音量为合适值 tinymix DAC Playback Volume 150 # 打开喇叭功放通路开关 tinymix Speaker Switch 1 # 设置喇叭音量 tinymix Speaker Volume 120注意不同Codec的控件名称差异很大必须先用裸命令确认实际名称再写脚本固化下来。我调试时习惯把整条通路的“水龙头”状态全部记录下来作为问题排查的基准快照。有了这个快照后续改了什么、动了哪里一目了然。3.2 tinyplay播放链路的照妖镜tinymix负责把通路打开tinyplay则负责验证整条播放链路是否真的能出声。tinyplay需要的是一个标准WAV文件建议平时就准备好44.1kHz和48kHz两种采样率、16bit位宽、双声道的测试文件放到开发板/data目录下。基本用法# 播放48kHz/16bit双声道WAV文件指定声卡0、PCM设备0 tinyplay /data/speaker_test.wav -D 0 -d 0如果播放没声音第一步去看tinyplay能正常播放完成还报错。如果报错“unable to set hw params”通常是采样率、通道数、位宽和PCM设备能力不匹配或者I2S和Codec的格式协商出了问题。如果tinyplay正常播放但喇叭无声问题就基本锁定在Codec路由、功放使能、硬件通路这三块。判断播放链路是否工作还有一招很实用直接在播放时抓I2S信号。用示波器探头量SoC的I2S引脚如果BCLK和LRCK有时钟翻转、DATA有数据脉冲就说明SoC侧数据已经正确发送出来了问题必然在Codec到喇叭这一段。这个判断方法能瞬间把排查范围缩小一半建议每个人调试时都养成这个习惯。3.3 tinycap录音链路的问题一眼看穿录音链路调试同样有专用命令tinycap。基本格式是# 录制5秒音频采样率16k、16bit、双声道 tinycap /data/test.wav -D 0 -d 0 -c 2 -r 16000 -b 16 -T 5录完以后用tinyplay播放这个文件就能判断录音链路是否正常。如果录制下来的文件是空白的或者只有电流声按我的经验90%的可能是两个原因MICBIAS偏置电压没开或者PGA增益通道被静音了。MICBIAS是给驻极体麦克风供电的偏置电压常见值为1.8V或2.8V。麦克风没有这个偏置电压根本不会工作就像话筒没装电池。通过tinymix打开MICBIAS开关再用万用表量Codec的MICBIAS引脚电压就能确认是否正常。PGA是麦克风前置放大器Codec内部通常有PGA Capture Volume和PGA Capture Switch两个控件如果Switch没有打开即使麦克风有供电ADC也采不到信号。数字麦克风DMIC的情况又不同它走的是PDM接口需要检查PDM时钟和数据引脚的配置。从排查思路上说先确认物理引脚电压再检查Codec内部通路最后看DMA数据是否产生三步走下来基本不会漏。3.4 procfs与debugfs那些看不见的ALSA状态除了三个tinys命令还有一组命令是任何BSP工程师都绕不开的那就是看ALSA内核状态。先看声卡是否被正确注册cat /proc/asound/cards正常输出会列出声卡索引和名字比如“0 [t527audio]”。如果这里为空说明设备树或驱动加载就有问题。接着看PCM设备cat /proc/asound/pcm这个能看到每个PCM设备的类型播放还是录音、支持的采样率范围、通道数和位宽信息。当播放或录音失败时这里的信息能帮你快速判断是不是硬件参数不匹配。DAPM状态是另一个关键信息。ALSA/ASoC的DAPM机制会根据音频通路自动管理Codec内部各个模块的上电下电如果某个widget没有处于power on状态音频通路就是断的。通过debugfs查看cat /sys/kernel/debug/asoc/soc:sound/dapm它会列出每个音频组件widget的电源状态和连接关系。看到某个关键节点显示“off”排查方向就有了。内核里还可以开ALSA的调试打印echo 4 /proc/sys/kernel/printk echo file soc-dapm.c p /sys/kernel/debug/dynamic_debug/control开启后dmesg会打印DAPM通路的切换过程能很直观地看到哪个节点在打开、哪个节点被跳过。4. 实战记录五个典型音频问题的完整排查过程4.1 完全无声从上到下逐级摸一遍完全无声是遇到最多的问题。我在T527项目上第一次遇到无声当时的处理路径非常有代表性。先把声卡和PCM设备确认了都正常直接跑tinyplay播放测试文件命令正常结束、无任何报错但喇叭就是没声音。这就把问题范围缩小到了Codec路由和功放这一层。然后用tinymix列出所有控件发现DAC播放开关确实打开了音量也设置得很高但功放模块的电源控制位一直是关闭状态。通过tinymix把功放通路开关打开再试声音出来了。这个例子说明Codec内部往往会有多个层级的开关看起来DAC开了但通往功放的通路还关着整条链路照样不通。调试时不能只看一两个控件要把从DAC到功放的每一个开关都过一遍特别是那些名字里带“Mixer”“Switch”“Mux”的控件。另外功放使能GPIO的默认状态也值得怀疑。硬件设计上有些功放的EN脚悬空时默认就是高电平功放一上电就开始工作但驱动GPIO一旦被初始化成低电平反而把功放关了。这类“配置前有声、配置后无声”的反直觉问题往往就是因为GPIO默认状态和设计预期不符。4.2 底噪与杂音先分清噪声类型再动手底噪问题最怕一上来就调软件增益越调越糊涂。我的习惯是先断开信号源做对比测试把I2S的DATA引脚从Codec断开或者直接用tinymix关闭DAC输出然后听喇叭里是否还有噪声。如果断开后噪声依然存在说明噪声来自功放或电源环路。常见原因包括功放供电纹波过大、模拟GND和数字GND没有单点接地、喇叭线形成了地环路。这类问题软件基本救不回来要从硬件布线改。如果断开后噪声消失了那噪声源在Codec之前或Codec内部就要重点检查PGA增益是不是过高Mixer通路里是否混入了未使用的输入信号。还有一种常见的“杂音”其实是开关机瞬间的爆破音这种不属于白噪声。爆音的根源是功放上电瞬间前面一级的DAC输出还没有稳定直流偏置被放大后冲击喇叭。处理办法是在驱动里调整时序先初始化Codec、打开DAC并让输出稳定再去拉高功放EN脚。全志平台通常可以在驱动里通过GPIO操作顺序和延时来控制这个时序稍微加几十毫秒延时往往就能解决。比如关声音的顺序和开声音是反过来的先关功放EN再关DAC这样喇叭不会在DAC工作状态切换时发出爆破声。这个顺序看似很简单但很多产品出厂后才发现开关机爆音问题就是因为没有严格处理时序。4.3 录音异常先看MICBIAS再看PGA录音问题整体比播放问题更难查因为看不见摸不着。我在T527板子上调过一次麦克风完全录不到声音整个排查过程挺典型的。一开始用tinycap录音5秒播放录音文件完全空白。我先用万用表量Codec的MICBIAS引脚发现电压为0。于是通过tinymix把MICBIAS相关的控件打开tinymix MICBIAS Switch 1 tinymix MIC1 Boost 1再量电压MICBIAS引脚正常输出了2.8V但仍然录不到声音。继续查看PGA相关控件发现“PGA Capture Switch”被默认静音了音量也为0。把PGA打开、音量设置到合适值后录音正常。总结下来录音排查的优先级就是先看偏置电压再看PGA增益和开关最后查DMA和数据搬运。很多新手一上来就怀疑Codec驱动有问题实际上三分之二的录音问题都出在这几个简单的控件配置上。另外还有一个高频问题录制出来的文件只有单声道有声音另一个声道是静音或噪声。这通常是因为麦克风输入接到了Codec的MIC1但录音通路配置只开了MIC2通道通路和硬件接法不匹配。4.4 播放卡顿与恢复异常DMA和电源管理的锅播放过程中断断续续也就是常说的xrununderrun/overrun在BSP里也经常遇到。先搞清楚是持续性的还是偶发性的。持续性卡顿多半和DMA buffer配置有关。如果buffer太小应用来不及填数据DMA就跑空了声音自然一卡一卡。可以通过增大PCM buffer size解决但DMA buffer不是越大越好过大会增加播放延迟具体取值要根据应用场景平衡。偶发性卡顿很多时候跟系统的电源管理和CPU频率调节有关。系统在播放音频时如果触发了降频CPU来不及处理音频数据也会产生underrun。可以通过设置CPU为performance模式来验证是不是这个原因。如果切换模式后卡顿消失说明是CPU调频策略过于激进需要调整调频阈值或者把音频线程绑定到大核上。还有一种“播放暂停后恢复不正常”的问题发生在系统suspend/resume之后。T527这类平台支持深度睡眠系统唤醒后如果Codec的寄存器没有完全恢复音频通路就会异常。常规现象是唤醒后第一次播放无声第二次播放又正常。遇到这种问题重点检查Codec驱动的resume回调确保regmap缓存和GPIO状态都正确恢复。在内核日志里打开Codec驱动的调试输出能看到resume时有没有报错。4.5 插拔检测失灵从中断到上报的完整链路耳机插拔检测这问题现象多样有的插入耳机没反应外放还在响有的拔出耳机还停在耳机模式有的插拔几次后检测完全失效。排查思路是沿着“物理电平变化→中断触发→驱动处理→事件上报”这条链路逐级查。先在插入耳机时用示波器或万用表量HP_DET引脚的电压确认电平有没有变化。没有变化那就是硬件连接问题比如耳机座引脚虚焊。有变化但系统没反应就要看这个GPIO的中断有没有在DTS里配置正确。有的方案用的不是GPIO中断而是通过Codec的ADC采集耳机座的电阻值来判断插拔全志方案里也常见这时要检查ADC阈值配置是否合理。驱动处理正常后系统会通过input子系统上报耳机插拔事件。在应用层可以用getevent观察getevent然后插拔耳机看是否有事件上报。如果事件上报了但声音路由没切换那是上层音频策略的问题和BSP驱动无关。如果事件根本不上报就回到驱动层查。我碰到过一个极性配反的案例DTS里配置HP_DET为高电平触发实际上硬件在插入耳机时引脚是从高电平变低电平结果系统每次上电认为耳机已经插入一直处于耳机模式外放永远没声音。5. 常见问题速查表与避坑笔记5.1 音频问题快速定位速查表把上面讲过的典型问题汇总成一张表方便大家现场排查时快速对照。问题现象大概率原因快速排查方法完全无声DAPM通路未完全开启、功放GPIO未使能或极性反tinymix列出全部控件依次打开DAC、Mixer、功放通路测功放EN脚电平示波器抓I2S引脚确认SoC侧有数据开机/关机爆音功放使能时序早于Codec输出稳定调整驱动时序先开DAC后开功放关断时先关功放后关DAC必要时加50-200ms延时播放有底噪模拟电源纹波、PGA增益过高、地回路关闭DAC输出对比听感减小PGA增益检查电源和接地设计声音沙哑、变调I2S格式不匹配、MCLK频率不对核对DTS中format与Codec数据手册播放时查看clk_summary确认MCLK频率播放卡顿DMA buffer过小、CPU降频、xruncat /proc/asound/card0/pcm0p/sub0/status 查看underrun计数切换performance模式验证录音无声MICBIAS未供电、PGA被静音万用表量MICBIAS电压tinymix打开PGA Switch并设置音量耳机插入不切换耳机检测GPIO极性反、中断未配置getevent观察插拔事件量HP_DET电平检查DTS中断配置唤醒后第一次播放无声Codec寄存器resume未恢复打开Codec驱动调试打印检查regmap缓存和GPIO恢复逻辑5.2 我在T527项目里踩过的几个坑第一个坑是GPIO极性想当然。原理图里功放EN画的是低电平有效DTS里也配了GPIO_ACTIVE_LOW按道理没问题实际上一量引脚默认竟然是高电平功放从上电起就一直开着。原因在于SoC这个GPIO的默认复位状态是带上拉的驱动还没初始化时电平就已经是高了。这个问题的教训是凡是涉及功放使能、耳机检测这类和实际硬件电平强相关的GPIO必须用万用表实测静态电压不能只看原理图。第二个坑是MCLK父时钟选错。T527的时钟框架里I2S模块可以选择不同的上游时钟默认的父时钟可能不是为音频专门优化的。我遇到的情况是播放44.1kHz音频时MCLK被自动配置成了11.2896MHz但实际输出频率却差了好几十kHz导致声音变调。最终在时钟驱动里给I2S模块指定了正确的父时钟源才解决。建议新板子调试时播放之前先看一遍clk_summary确认各音频相关时钟的实际输出频率。第三个坑是tinymix操作顺序。有一次我想解决开机爆音直接在驱动里初始化时就把功放EN拉高结果爆音更严重了。后来加了Codec的Mute控制时序才明白爆音的根源不是功放上电早而是功放上电时前面DAC输出本身就不稳定。光是延迟功放上电没用还得确保DAC输出处于mute状态。这个问题的正确做法是先打开Codec电源和时钟把DAC输出静音等输出稳定后再放开Mute最后使能功放。关声音的时序反过来先关功放再mute DAC最后下电。第四个坑是产测脚本里音频文件格式不匹配。产线测试时为了图省事随便找了个MP3转成WAV结果采样率变成了44.1kHz但脚本里tinyplay指定的声卡PCM设备只支持48kHz一播放就报错。所以建议在板子上固定放一个标准48kHz/16bit/双声道WAV文件产测脚本里也统一用这套参数不要指望产线工人去分辨格式差异。产测要多通道测试时还要注意WAV文件的声道映射左右声道反了在产线上很难被发现。第五个坑是DTS里同时挂了HDMI音频和Codec音频时sound节点容易配串。T527如果接HDMI会有独立的I2S对应HDMI音频通道加上板载Codec设备树里可能出现多个sound节点。我在一个项目里把两个sound节点的simple-audio-card,cpu都配置成了同一个I2S结果一个节点出声另一个节点无声内核还不报错。排查时用debugfs看一下每个sound节点的dai link是否指向了正确的I2S比自己翻DTS效率高很多。做音频调试这行最忌讳的就是拿着示波器一路瞎量量不到波形就开始怀疑硬件或者反过来代码里一顿乱改碰运气。我做T527音频调试时最受益的习惯是把“DTS配置→ALSA声卡注册→PCM设备协商→DAPM通路状态→Codec控件值→功放GPIO电平→喇叭输出”这条链路背下来每次遇到问题先判断在哪一层然后再动手查。音频链路再长也是一环扣一环的只要链路认知清晰排查就是顺藤摸瓜的事。希望这篇分享能让你少走点弯路。
返回列表