ARTICLE DETAIL

资讯详情

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

全志T527音频调试实战:从ASoC框架到设备树与DAPM路由排查

全志T527音频调试实战:从ASoC框架到设备树与DAPM路由排查 做BSP调试的人都知道音频这关说难不难说简单也绝对不简单。全志T527这个平台上我这次Audio调试前前后后花了将近一周从最开始声卡连注册都失败到最后能稳定播放和录音中间踩了不少坑。这篇就当是BSP调试系列的第15篇把T527音频调通的完整链路和排查思路捋一遍给后面接手的人留点参考。整个调试过程涉及的全志T527音频子系统、ASoC框架、设备树配置、以及alsamixer/tinymix这些用户态工具我都会讲到重点在于告诉大家遇到问题时先查哪里、怎么判断是硬件还是软件问题、哪些配置最容易出错。先说下我这次调试的平台背景。全志T527是一颗面向智能座舱、商业显示、边缘计算场景的八核处理器音频外设相当丰富I2S、PDM、DMIC、SPDIF都有还带HDMI音频。我手头这块板子用的是比较常见的方案SoC的I2S0接一颗外置CodecCodec的模拟输出再接Class-D功放驱动喇叭麦克风走Codec的模拟输入。整套东西在Linux下跑的是标准ALSA/ASoC框架设备树里挂sound card节点。听起来是不是挺标准的但就是这套“标准”的东西调起来处处有惊喜。1. 调试前的功课先把T527的音频全链路盘明白1.1 硬件侧SoC音频控制器、Codec、功放和喇叭的连接关系音频调试最忌讳上来就乱试先把硬件链路搞清楚比什么都重要。拿我这次用的T527板子举例音频数据流是这样的播放方向内存里的PCM数据 - DMA - T527的I2S0控制器 - Codec的数字音频接口 - Codec内部DAC - Codec模拟输出 - 外部功放 - 喇叭。录音方向反过来麦克风 - Codec模拟输入 - 内部ADC - Codec数字接口 - I2S0 - DMA - 内存。每一段都有独立的“坑位”。I2S0这里要确认四根线BCLK位时钟、LRCK帧时钟也叫WS、DIN、DOUT。T527的I2S0引脚是mux过的设备树里要配pinctrl否则你量不到时钟。Codec这边我这次用的是常见的一颗立体声CodecI2C地址、MCLK主时钟输入、复位脚都要检查。功放那边更直接一般就是一个GPIO控制使能脚高电平开机低电平关机。这里有个特别容易翻车的点MCLK。多数Codec需要SoC提供一个主时钟MCLKT527的I2S控制器可以输出MCLK但默认不一定打开。如果Codec没有收到MCLK它内部的PLL可能锁不住表现出来就是播放时只有微弱噪声或者完全没有声音但是tinymix里面各路的寄存器都是对的。所以硬件排查第一步先拿示波器或者逻辑分析仪量四点MCLK有没有、BCLK有没有、LRCK有没有、DOUT有没有数据。哪个没有就顺着查哪段。1.2 软件侧ASoC框架下的Machine、Platform和Codec驱动Linux音频软件栈走的是ALSA/ASoC框架这个框架在T527上被全志的BSP封装得比较完整但还是得理解它的三层结构否则出问题根本不知道去哪看代码Machine驱动负责描述整块板子的音频拓扑它决定了Codec接在哪个I2S上、采用什么采样率、有没有外部功放需要控制。对应设备树里的sound节点compatible会匹配到具体的machine驱动文件。Platform驱动在T527上就是I2S控制器驱动和DMA驱动负责把内存数据搬到I2S总线上或者反向搬回来。这块通常是SoC厂商已经写好的不太需要改但需要确认dma配置和dai format是否和Codec对上。Codec驱动描述Codec内部所有通路包括DAC、ADC、PGA、mixer、DAPM路由等。不同Codec差异巨大这是调试中改动最多的地方。三层驱动靠dai_link串起来。dai_link里指定cpu_dai、codec_dai、platform再约定formatI2S/DSP、位深、采样率等参数。调试时经常遇到的情况是三个驱动各自都probe成功了但是dai_link没连上或者format不一致导致数据不通。这类问题看dmesg往往不明显需要自己加打印或者用工具逐层验证。1.3 设备树的音频节点sound、codec、dai-link到底怎么配以我这次板子的实际设备树配置略做简化为例说明几个关键点// Codec节点挂在I2C总线下面 i2c1 { codec: audio-codec1c { compatible xxx,your-codec; reg 0x1c; #sound-dai-cells 0; AVDD-supply reg_audio_avdd; // 模拟电源 DVDD-supply reg_audio_dvdd; // 数字电源 reset-gpios pio 2 6 GPIO_ACTIVE_LOW; clocks clk_audio_mclk; clock-names mclk; status okay; }; }; // sound card节点绑定machine驱动 sound { compatible xxx,t527-sound-card; model t527_audio; // 这个会显示在/proc/asound/cards里 audio-routing Speaker, LOUT, MIC1, MICBIAS; // DAPM路由缺了会导致没声音 pinctrl-names default; pinctrl-0 i2s0_pins; // I2S引脚复用配置 simple-audio-card,cpu { sound-dai i2s0; }; simple-audio-card,codec { sound-dai codec; clocks clk_audio_mclk; }; };这个配置里最容易犯错的是audio-routing和reg。reg错了I2C根本读不到Codec驱动probe永远失败。reset-gpios如果没写Codec上电后可能处于复位状态同样读不到。audio-routing是DAPM的静态路由kernel 4.14之后如果machine驱动走simple-audio-card路由必须配全否则对应的widget不启用通路断了你在tinymix里怎么开mixer都没用。我这次就栽在routing上面后面专门讲。2. 声卡不注册的排查从dmesg到设备树匹配2.1 第一步永远是dmesg别急着改代码T527平台拿到手先把系统跑起来然后执行cat /proc/asound/cards aplay -l我这次第一次执行输出只有“no soundcards found”声卡没注册。这时候不要急着翻驱动代码先看dmesg。dmesg | grep -E asoc|snd|codec|i2s|sound常见的情况有这么几种完全没有snd相关的日志说明machine驱动的probe根本没执行。查设备树的compatible和内核里的machine驱动字符串是否对得上。T527的BSP里machine驱动做的比较“全志化”compatible的格式可能是“allwinner,t527-sound-card”之类的一定要逐字核对。有日志但是报codec相关的错误比如“ASoC: failed to instantiate card”或者“i2c transfer error”。这种多半是I2C通信问题先量电压、查复位脚、查I2C地址对不对。我遇到过代码里写0x1a实际Codec的地址跳线是0x1c改设备树就通了。有日志但是报DAI相关的错误比如无法找到dai。这种是dai_link配置里的sound-dai引用的节点不对或者#sound-dai-cells配置错误。注意T527的I2S节点和Codec节点都要有#sound-dai-cells属性缺一个就匹配不上。2.2 compatible匹配失败codec节点名字与驱动name的对应关系这里有个全志平台特有的坑。很多Codec驱动是公版改的probe函数里会读设备树或者直接把compatible作为匹配依据。比如你设备树里写的是compatible allwinner,t527-codec;但是驱动代码的of_device_id表里挂的是static const struct of_device_id xxx_codec_of_match[] { { .compatible somevendor,xxx-codec, }, { .compatible allwinner,t527-codec, }, {}, };两边不匹配驱动永远不会probe。检查方法很简单ls /sys/bus/i2c/drivers/xxx-codec/ ls /sys/bus/platform/drivers/xxx-codec/如果目录下没有你想要的设备说明of_match没对上。还有一个技巧把所有codec相关的驱动modprobe一遍之后再去看/bus/i2c/drivers很多时候驱动编成了模块但没有自动加载。2.3 注册顺序问题codec probe晚于machine probe怎么办还有一类问题特别隐蔽Codec驱动和machine驱动都在内核里但是Codec挂在I2C总线上而I2C控制器的probe比machine晚就会导致machine在绑定dai_link时找不到codec。这种在ASoC框架里应该有EPROBE_DEFER机制来处理但如果全志BSP改过probe顺序或者没正确处理返回值就会直接失败而不是挂起等待。判断方法dmesg里看是否有类似“asoc-simple-card: probe defer”的日志。如果没有可以手动验证在machine驱动的probe函数开头加一句pr_info看看它是在codec probe之前还是之后执行的。如果真的遇到顺序问题最简单的做法是把machine驱动的probe改成异步或者确保I2C控制器先注册。全志T527的BSP里I2C控制器驱动如果注册得很晚可以在machine驱动里加设备链接device_link强制顺序但我实际调下来通常检查一下Codec驱动是否编成模块而machine是built-in就可以发现问题了——模块加载时机不可控建议直接把Codec驱动编进内核。3. 播放链路点亮先让tinyplay出声再说3.1 从tinypcminfo到tinyplay把原始通路跑起来声卡注册成功只是开始接下来要让播放链路真正出声。先说工具强烈建议在板子上编译好tinyalsa这套工具包括tinypcminfo、tinyplay、tinycap、tinymix。没有它们全靠adsp或者alsa-utils会麻烦很多。第一步tinypcminfo -D hw:0,0看输出重点确认sample_rate、channels、format是否符合预期。T527这颗平台I2S0一般默认是16bit双声道如果Codec支持24bit要注意dai_link里有没有配format。如果这里显示的参数和Codec实际能力不匹配后续播放要么no sound要么爆音。第二步tinyplay /test.wav -D hw:0,0注意这里最好用标准的44.1kHz或48kHz、16bit、双声道wav文件。别一上来就用超高采样率的测试文件。如果这一步出声了说明基础链路是通的。如果没声进入下一小节。3.2 DAPM路由与mixer控件的开关顺序这是T527音频调试里最容易被卡住的地方。DAPM是ASoC的电源管理框架它不只是管电源还管音频信号的“通路”。ALSA里每个控件之间默认是断开的只有在DAPM路由里声明或者通过mixer控件动态连接之后信号才能从DAC流到输出引脚。我一开始用tinyplay播放dmesg里没有任何报错I2S的DOUT上也有数据但喇叭就是不出声。后来查/sys/kernel/debug/asoc下的DAPM图才找到问题。小技巧cat /sys/kernel/debug/asoc/t527_audio/dapm/graph逐行看每个widget的连接状态。最后发现是“OUTPUT”widget和“Speaker”之间的route没有配。我设备树里audio-routing写的是Speaker, LOUT,但Codec驱动里实际的输出widget名字可能是“LOUT”或者“SPK_OUT”我写错了名字。DAPM的route匹配对字符串完全敏感差一个字符都不会连上。正确的做法是先看codec驱动源码里snd_soc_dapm_widget数组把每个widget的名字抄下来。对照硬件原理图确认哪个widget对应哪个物理引脚。再写audio-routing。这个经验在T527上特别重要因为全志的BSP里有很多历史遗留的codec驱动widget命名跟公版不完全一致光靠猜肯定出错。3.3 功放GPIO时序与Pop音处理通路通了声音也出来了但功放那边的时序也要处理。T527板子上的功放使能脚通常挂在某个GPIO上全志BSP里一般会在machine驱动的probe里注册一个gpio_switch或者直接操作GPIO。这里最大的问题是开机/关机的Pop音。播放时如果先开功放再开DAC或者先关DAC再关功放喇叭都会“啪”一声。T527上我试过几种方案最稳的是利用ALSA的kcontrol回调在Playback Switch打开之后延时几十毫秒再拉高功放GPIO在关闭之前先拉低。说白了就是保证Codec输出稳定后再接通喇叭。如果不想改驱动也可以先在用户态用gpio sysfs导出功放脚配合tinymix手动调。但最终量产还是得在驱动里把时序做对。这里有个细节全志的GPIO操作要用gpiod_set_value_cansleep因为功放GPIO可能在I2C/slow路径上用原子版本会导致睡眠报错。3.4 音量小和失真增益分配的大坑T527平台上音频链路里有很多级增益Codec的DAC数字增益、模拟PGA、功放增益还有SoC侧DMA的衰减。每一级增益都会影响最终音量和音质。最容易犯的错误是喇叭声音小就把某个数字增益调到最大结果声音确实大了但开始削波失真低音破碎。调音量的原则我总结为“均匀分配、避免削波”。具体操作先用tinymix把PGA和DAC增益设到中间值附近比如0dB再用SoC侧的ALSA Master音量控制整体音量。如果用功放的增益跳线可以调整优先通过硬件把喇叭灵敏度匹配好。这里提供一个我实际调试T527时的参考配置tinymix DAC Playback Volume 150 # 0-255范围先设到6成 tinymix PGA Volume 12 # 模拟PGA不要超过16 tinymix Output Mixer L 1 # 使能输出通路 tinymix Output Mixer R 1如果系统里还有EQ或者DRC控件T527的BSP Codec驱动一般会暴露出来先全部关掉再逐步开不然根本不知道是EQ调坏了还是通路有问题。4. 录音链路调试从模拟输入到数据落盘4.1 麦克风偏置与输入增益怎么调播放通之后录音这边又是一个独立世界。T527的Codec录音链路通常长这样麦克风 - MICBIAS供电 - 输入引脚 - PGA - ADC - I2S0接收。录音没数据或者声音小第一步先查MICBIAS供电。驻极体麦克风需要偏置电压Codec都有MICBIAS引脚要在tinymix里使能否则麦克风就是死的。代码如下tinymix MICBIAS 1接下来是输入增益PGA。增益太低录音声音小太高就会把底噪也放大。我用T527平台调试时经验值是PGA增益放15~20dB左右具体还要看Codec的输入阻抗和麦克风灵敏度。这里有个容易忽略的点多数Codec的差分输入和单端输入的接线不同PGA的增益范围也不同。如果硬件上是单端接法PGA可能不支持高增益硬开大只会引入噪声。4.2 capture路径的DAI配置和slot对齐问题与播放不同录音方向的I2S格式配置完全独立。有时候你播放没问题但录音采回来的数据是乱的或者只有一边声道有数据。这种问题优先怀疑I2S的slot对齐。T527的I2S控制器支持TDM模式可以配置slot_width、slot_num、tx/rx_mask。如果Codec和SoC之间的slot配置不一致比如Codec发送数据在slot0但SoC配置的是只收slot1那数据就丢了。检查方法tinypcminfo -D hw:0,1如果显示channels2但实际录音文件里只有左声道有有效数据有线示波器量一下LRCK和DIN的相位关系。对比Codec的datasheet里的transmit时序图确认LRCK为低时发左声道还是右声道和SoC侧I2S控制器配置的左右声道极性是否一致。全志的I2S控制器在dai_link里一般有format和slot相关配置如果你用的是DSP/PDM格式极性错了的情况更常见。4.3 录音有数据但声音小、底噪大的常见原因如果录音文件里能看到波形但声音小、底噪大多半是增益分配的问题。这里有个不算少见的坑Codec内部从PGA到ADC之间还有一级boost或mux默认可能没开或者开了之后引入噪声。建议把PGA和ADC的增益分别调记录每一级对信噪比的影响。还有一个常见原因是参考地问题。如果麦克风地线走得不干净靠近功放的地底噪会被直接采进去。这时候软件怎么调都很难救只能用示波器看波形把地线重新走线。调试阶段可以临时用飞线把Codec的AGND和GND直接接到电源地先排除硬件问题再回来骂软件。对于T527这种多电源域的SoC尤其要注意Codec的模拟地和数字地是否最终单点接地。我在T527的板子上遇到过模拟Vref纹波很大录音底噪-60dB后来发现是Codec的AVDD滤波电容焊错位置了离引脚太远改到引脚附近之后底噪直接降到-90dB。所以说软件调的再好硬件底子不行也是白搭。5. 时钟、XRUN与低功耗进阶问题的定位思路5.1 主时钟MCLK和采样率的匹配关系播放录音都能跑之后如果你要切换采样率就会撞上MCLK这堵墙。T527的I2S控制器可以输出MCLK但MCLK频率必须和采样率、位深成倍数关系。比如48kHz采样、16bit、双声道一般MCLK用256fs也就是12.288MHz。如果切到44.1kHzMCLK可能得切换成11.2896MHz或22.5792MHz而不是直接沿用12.288MHz。如果MCLK不对Codec的解码出错的概率很高症状可能是声音明显变调、变慢、或者只有杂音。T527的BSP里时钟树一般配好了但你如果改了Codec的采样率范围或者用了非标准的rate就要检查clk_set_rate是否成功。cat /sys/kernel/debug/clk/clk_summary | grep -i audio看MCLK当前实际频率是多少再和Codec datasheet里的fs表对照。我上次做T527平台时在Codec驱动里加了set_sysclk的支持并且在machine驱动里显式调用snd_soc_dai_set_sysclk保证每次切换rate时先切MCLK再切BCLK顺序反了会出现瞬间爆音。5.2 XRUN和中断延迟用ftrace抓调度延迟如果你播放/录音过程中经常出现“underrun”或“overrun”日志说明DMA和CPU之间的协作出了问题。T527是八核处理器音频中断应该有专用CPU来处理现实常常是中断被挤到某个忙得要死的大核上导致period elapse事件没有按时处理。排查手段用ftraceecho 0 /sys/kernel/debug/tracing/tracing_on echo snd_pcm* /sys/kernel/debug/tracing/set_ftrace_filter echo function_graph /sys/kernel/debug/tracing/current_tracer echo 1 /sys/kernel/debug/tracing/tracing_on跑一段播放然后看那个period的callback执行延迟。如果延迟超过一个period的时长XRUN不可避免。优化思路把音频中断绑到某个A55小核上通过irq affinity设置避免被大核负载拖累。增大buffer_size和period_size比如默认16KB buffer4KB period可以试32KB buffer8KB period。延迟高了不到1ms但对稳定性帮助很大。检查DMA是否用了burst模式T527的DMA配置在dts里有时需要加snd_dmaengine_pcm_config的prealloc buffer。5.3 休眠唤醒后音频不复位的问题如果你的板子有低功耗模式音频休眠唤醒后大概率会出现“出声失败”或者“只有一边声道出声”的怪毛病。原因通常是Codec在suspend时进了低功耗状态但resume时没有完全恢复到工作状态。T527平台因为电源域多SoC在休眠时会关掉音频相关的电源域而Codec是独立芯片两边一旦对不上DAPM状态就乱了。调试方法在Codec驱动里加resume回调打印关键寄存器值和正常播放时的寄存器值对比。如果发现某些寄存器漂了可以在resume里重新初始化一遍Codec。还有一种做法是suspend时不要完全关闭Codec保留某个最低功耗的idle状态。但这就涉及功耗预算了产品不敏感的话直接把ALSA的runtime pm关掉也okecho on /sys/devices/platform/sound/power/control这个命令在调试阶段很有用它会让sound设备一直保持active状态。但量产一定要注意功耗。我遇到的情况是T527的audio codec挂在i2c1上suspend时i2c总线先断了codec的resume被跳过因为i2c的pm_runtime状态没恢复。修法是加设备链接让codec的resume依赖i2c控制器先resume这个思路对全志BSP的坑很实用。6. 调试工具与实战技巧汇总6.1 tinymix、tinyplay、tinycap、tinypcminfo三板斧的完整用法T527平台上强烈建议把这几个工具编译进rootfs。它们轻量、无依赖、源码在external/tinyalsa里编译一次就都有。常用指令总结# 列出所有PCM设备 tinypcminfo -l # 查看某个PCM设备的具体参数 tinypcminfo -D hw:0,0 # 播放wav文件 tinyplay /data/test.wav -D hw:0,0 # 录音10秒48k 16bit双声道 tinycap /data/rec.wav -D hw:0,1 -c 2 -r 48000 -b 16 # 查看所有混音控件 tinymix # 查看单个控件当前值或者设置值 tinymix DAC Playback Volume tinymix DAC Playback Volume 150tinymix的输出非常重要可以在调试中随时确认通路上每个控件的状态比如PGA有没有开、mux选的是哪一路输入。出问题时先tinymix把输出贴出来跟正常板子的输出做diff问题定位又快又准。6.2 procfs、debugfs检查运行时状态除了用户态工具内核侧的几个接口也是必看的# PCM设备状态 cat /proc/asound/card0/pcm0p/sub0/hw_params cat /proc/asound/card0/pcm0p/sub0/status # status里会显示running还是stoppedhw_params会显示当前rate/format/channels # DMA位置指针 cat /proc/asound/card0/pcm0p/sub0/positionDAPM调试接口更关键# DAPM widget/route状态图全志BSP这边路径一般在这 ls /sys/kernel/debug/asoc/ cat /sys/kernel/debug/asoc/t527_audio/dapm/graphgraph输出是文本形态的widget连接图能看出来哪些route是active的哪些是off。这个对排查DAPM问题非常有用。还有一个经常被忽略的codec寄存器dump。cat /sys/kernel/debug/regmap/xxx-codec/registers如果没有regmap调试入口可以在Codec驱动里加一个读寄存器的debugfs文件。我调试时会对比正常状态和异常状态的寄存器差异找到是哪个寄存器在播放过程中被谁改了。T527的BSP里有些Codec驱动会带上自动增益控制AGC它偷偷改PGA增益播放过程中音量突然变化查寄存器才发现是AGC没关。6.3 一些很难查的问题用示波器、逻辑分析仪兜底软件层面都查完了还是不行就该上硬件工具了。T527的I2S信号都是1.8V或3.3V电平调试时直接用逻辑分析仪的杜邦线夹住BCLK、LRCK、DOUT三根线就能抓到波形。重点看几组参数BCLK频率是否符合预期。比如48kHz 16bit双声道BCLK应该等于48k1621.536MHz。如果BCLK偏差太大问题在时钟配置。LRCK频率是否等于采样率。LRCK应该恰好是48kHz如果差一点音频会变调。DOUT数据是否在LRCK对应的相位上。拿示波器对比LRCK下降沿到DOUT有效数据的bit delay看是否符合I2S标准格式。MCLK稳定性。如果MCLK波形有明显抖动Codec内部时钟会跟着抖声音会“发毛”。如果这些波形都是对的但声音还是不对那就要怀疑Codec本身的寄存器配置。这时候只能对照Codec datasheet逐位检查寄存器。别嫌麻烦音频调试里最耗时的就是这种“全链路都对但就是不出声”的悬案静下心来逐段排除才是最省时间的路线。这次T527的音频调试最大的体会就是音频链路每一级都有坑但每一级也都有对应的检查方法。从上电看dmesg、用tinypcminfo确认参数、tinymix打通DAPM路由、tinyplay验证播放、tinycap验证录音、再进阶到查MCLK/XRUN/休眠唤醒整个思路跑通之后大部分音频问题都能在半小时内定位到具体层级。如果你现在也在搞全志T527或者类似平台的音频调试建议先把我上面列的工具和排查顺序都过一遍至少能少走一半弯路。
返回列表