资讯动态

RK3588音频调试实战:从设备树到ES8388 Codec驱动全解析

发布时间:2026/10/2 21:20:51 来源:尧图企业网站定制
1. 先看清RK3588的音频通路再谈ES8388的适配点先说结论RK3588调ES8388难点不在ES8388这颗codec本身而在于RK3588的音频通路比老平台复杂得多。如果你之前是在RK3288、RK3399上调过ES8388到了RK3588上按老套路配置大概率会遇到“设备树明明加载了驱动也probe了但就是不出声”或者“左声道正常右声道全是噪声”这类问题。RK3588平台上的音频链路大概是这样CPU侧的I2S控制器rk3588有三个I2S分别是I2S0、I2S1、I2S2通过I2S总线把音频数据送到外部codeccodec完成DAC/ADC转换再推动扬声器或者采集麦克风信号。这条链路上每一个环节有一个环节出错最后的表现都可能是一样没声音。但排查路径完全不同。CPU侧的I2S控制器配置错误表现为数据根本没有送出来用示波器量I2S的SCLK、LRCK引脚能看到时钟在跑但SDI/SDO上没有数据或者数据格式不对。设备树里dai-link的格式不匹配CPU侧配的是I2S格式codec侧配的是DSP格式两边对不上表现为时钟正常但解码出来全是噪声或者完全没有声音。MCLK频率设置不对ES8388对MCLK和采样率之间的倍频关系有明确要求配错了codec内部时钟紊乱寄存器读写正常但就是不出声或者出破音。所以我的习惯是拿到平台后先不急着写设备树先把RK3588的音频框图和数据手册里I2S控制器支持的格式、时钟路径看明白再动手。磨刀不误砍柴工这个习惯帮我避免了很多低级的重复调试。ES8388是一颗很经典的立体声codec支持I2S、左对齐、右对齐、DSP四种音频格式采样率覆盖8kHz到96kHz内置2路DAC输出和2路ADC输入。它的寄存器映射非常简单几乎所有功能都集中在0x00到0x31这几个寄存器里特别适合用来做嵌入式平台的音频方案。而且它内部集成了耳机放大器可以直接驱动32欧姆的耳机不需要额外加功放芯片这一点对于做板级设计的同学来说能省不少事。在RK3588上ES8388一般挂在I2S1上因为I2S1在RK3588的引脚复用里和普通GPIO不冲突布线相对容易。当然你用I2S0或者I2S2也可以只要引脚复用配对了就行。2. 设备树配置逐行拆解I2C地址、复位引脚与DAI LINK的绑定关系设备树是整个调试过程中的第一个硬骨头。很多人喜欢网上复制一段设备树直接改但每个板子的I2C地址、复位引脚、MCLK来源都不一样复制完大概率跑不通。我建议把设备树当成一份“硬件连接说明书”来写每个节点对应芯片手册里的一页。2.1 I2C子节点让内核找到这颗codec第一步是把ES8388挂到对应的I2C总线上。RK3588有8个I2C控制器ES8388具体挂在哪个I2C上由你的板级原理图决定。假设你的板子上ES8388的SCL/SDA接在I2C2上设备树里就这样写i2c2 { status okay; pinctrl-names default; pinctrl-0 i2c2m0_xfer; es8388: es838810 { compatible everest,es8388; reg 0x10; clocks cru MCLK_ES8388; clock-names mclk; assigned-clocks cru MCLK_ES8388; assigned-clock-rates 12288000; pinctrl-names default; pinctrl-0 es8388_mclk; spi-max-frequency 0; /* 这一行ES8388用不到别被网上代码误导 */ }; };这里的reg 0x10是ES8388的I2C地址。ES8388的7位I2C地址默认为0x10注意不是0x20也不是0x11。这个地址由芯片的CSB引脚电平决定如果你板子上CSB引脚接的是高电平地址就是0x11低电平是0x10。建议拿到板子后先用命令行工具实测一下不要光看原理图有些画板的人会把引脚标反。assigned-clock-rates 12288000是MCLK的来源频率。ES8388手册里明确写了MCLK和采样率的倍数关系对于44.1kHz采样率MCLK取256倍频就是11289600Hz对于48kHz采样率MCLK取256倍频就是12288000Hz。RK3588的CRUClock and Reset Unit通过PLL可以配置出这两组频率。如果你发现板上用的晶振是24.576MHz那MCLK频率可以配成12288000正好覆盖48kHz及其整数倍。如果项目里只用44.1kHz的音频可以配成11289600但大多数方案为了兼顾两种采样率都会用12288000。2.2 引脚复用节点MCLK这根时钟线最容易被忽略ES8388的MCLK是它的主时钟输入一般由RK3588的某个GPIO复用为I2S1_MCLK功能输出。这个引脚必须在设备树里正确配置pinctrl否则MCLK没有时钟输出codec完全不会工作。pinctrl { es8388 { es8388_mclk: es8388-mclk { rockchip,pins 1 RK_PC0 2 pcfg_output_high; }; }; };这里的含义是GPIO1_C0复用为功能2即I2S1_MCLK输出高电平作为默认状态。pcfg_output_high会让这个引脚在驱动加载前就保持高电平这样即使音频驱动还没probe外部codec也有一个确定的输入状态避免上电瞬间出现毛刺。2.3 Sound子节点把CPU和codec绑定成一条完整链路光有codec节点还不够要让内核把CPU端的I2S控制器和codec关联起来还需要一个sound节点来建立dai-link。sound { compatible simple-audio-card; simple-audio-card,format i2s; simple-audio-card,mclk-fs 256; simple-audio-card,name rk3588-es8388; simple-audio-card,cpu { sound-dai i2s1_8ch; }; simple-audio-card,codec { sound-dai es8388; }; };几个字段要特别注意simple-audio-card,format i2s定义了CPU和codec之间的数据格式。ES8388支持I2S、DSP等多种格式但RK3588的I2S控制器默认生成标准I2S格式两边统一用i2s最省事。simple-audio-card,mclk-fs 256表示MCLK是采样率的256倍。比如采样率48kHz时MCLK应该是48kHz x 256 12.288MHz。这个值必须和第一部分配置的assigned-clock-rates一致。sound-dai i2s1_8ch这里用的是I2S1的8通道控制器。ES8388是双声道codec但RK3588的I2S1_8ch控制器兼容双声道模式在高通、NXP平台切换过来的人可能不习惯这种命名方式但实际用起来没区别。写完这三段设备树层面的基本连接就完成了。很多人配完后板子还是没有声音往往不是因为设备树有问题而是内核里根本没把ES8388的驱动代码编译进去。3. 内核驱动与匹配链路从menuconfig到driver probe设备树只是描述了“硬件长什么样”真正让ES8388工作起来的是内核里的codec驱动。这个驱动在sound/soc/codecs/es8388.c老版本内核里叫es8388.c新版本里有的叫es8323.c两个文件长得几乎一模一样寄存器映射也完全一样。我在RK3588上遇到过明明编译的是es8323.c但芯片丝印写的是ES8388实际工作是正常的因为这个驱动本来就是同一个系列。3.1 内核配置项RK3588的SDK一般基于Linux 5.10内核进入内核目录后执行make ARCHarm64 menuconfig需要确认以下几项是开启的不能只开一个Device Drivers --- * Sound card support --- * Advanced Linux Sound Architecture --- [*] Sound Open Firmware (SOF) driver * ALSA for SoC audio support --- * Rockchip I2S/DMIC/TDM controller * EVEREST ES8388 CODECEVEREST ES8388 CODEC这一项编译后会生成snd-soc-es8388.ko如果选择模块编译如果是built-in方式编译则会在内核镜像里。我强烈建议调试阶段用模块方式编译这样每次改完驱动只需要重编一个ko文件推送到板子上insmod就行了不用反复烧整个boot.img或者kernel.img调试效率能提升好几倍。如果你用的是Rockchip官方SDK默认配置里多半已经打开了ES8388的支持因为很多开发板厂商的参考设计都用了这颗芯片。但如果你是自己裁剪的内核很容易漏掉。3.2 驱动匹配过程compatible字符串决定生死编译完成后内核是如何知道设备树里的es838810节点应该和哪个驱动匹配呢靠的是compatible字符串。es8388.c驱动源码里的of_match_table定义如下static const struct of_device_id es8388_of_match[] { { .compatible everest,es8388 }, {}, }; MODULE_DEVICE_TABLE(of, es8388_of_match);也就是说设备树里的compatible everest,es8388必须和驱动源码里定义的完全一致一个字母都不能差。我见过有人把设备树写成everest,es8388但驱动里写的是es8388或者everest,es8323结果驱动永远匹配不上probe函数根本不执行命令cat /proc/asound/cards里永远看不到这块声卡。检查驱动是否成功probe最快的方法是插入模块后执行dmesg | grep -i es8388正常会看到类似es8388 2-0010: ASoC: probe ES8388 done的日志如果什么都没有优先检查compatible字符串是否匹配不要急着去看寄存器。3.3 ASoC框架的绑定顺序ASoC框架的绑定逻辑是simple-audio-card节点会去遍历它引用的cpu和codec两个子节点分别拿到对应的device然后调用snd_soc_register_card注册声卡再触发各自的probe流程。这个绑定顺序有一个坑如果你把codec节点写在了某个i2c节点下面但该i2c节点的status没有设置成okay那ES8388这个device根本不会被创建simple-audio-card去绑定codec的时候就会返回-EPROBE_DEFER声卡初始化失败。很多人明明写了节点但一直拿不到声卡查了半天才发现是I2C控制器没被使能。4. 上电后的三板斧先用命令行确认硬件通路通不通设备树和内核配置都到位了声卡也出现在/proc/asound/cards里了接下来才是真正考验调试能力的地方。我在RK3588上调ES8388的时候总结了一套固定的三板斧排查流程先测I2C通路再测寄存器读写最后才看ALSA层。4.1 第一板斧i2cdetect确认I2C地址首先确认ES8388在I2C总线上能被探测到。假设挂在I2C2上在板子上执行i2cdetect -y 2正常情况下在0x10或0x11取决于CSB引脚电平位置会看到一个编号。如果你看到的是UU说明这个地址已经被内核里的某个驱动占用了这也算正常。如果显示--说明总线上根本没探测到设备这时候优先查硬件连接和I2C引脚复用是否正确不要纠结驱动问题。如果你不确定ES8388挂在哪个I2C控制器上可以逐个扫描for i in 0 1 2 3 4 5 6 7; do echo i2c$i ; i2cdetect -y $i; done在RK3588的SDK环境里i2c设备节点位于/dev/i2c-NN的编号和dts里i2c控制器的序号不一定一一对应和硬件相关的映射关系要去查RK3588的TRM手册中的I2C控制器基地址表。不过i2cdetect这个工具会直接扫描所有节点不用手动关联。4.2 第二板斧i2cget/i2cset验证寄存器读写ES8388的寄存器地址是8位数据也是8位很好操作。举个例子ES8388的0x00寄存器是主控制寄存器默认值应该是0x00。执行i2cget -y 2 0x10 0x00如果返回0x00说明I2C读写通路正常。接下来可以测试一个关键寄存器——0x02DAC电源控制给它写入0x0A意思是打开左声道DAC和右声道DAC的电源i2cset -y 2 0x10 0x02 0x0A然后再读回来确认i2cget -y 2 0x10 0x02返回0x0A说明寄存器写入生效了。这一步的意义在于如果寄存器读写都不通后续所有ALSA层的调试都没有意义。先把I2C通路夯死再往上走。4.3 第三板斧tinymix和tinyplay绕开上层框架直接发数据确认寄存器读写正常后我建议绕开上层音频框架直接用tinyalsa工具测试播放通路。Rockchip SDK里一般自带tinyalsa工具集路径在external/tinyalsa编译后会生成tinyplay、tinycap、tinymix三个可执行文件。先用tinymix查看当前声卡的控件列表tinymix -D 0在ES8388的驱动里你会看到类似DAC Volume、ADC Volume、Left DAC Mute、Right DAC Mute、Left Input Mux等控件。播放之前先把左右声道DAC的mute关掉tinymix -D 0 12 0 # 第12个控件值设为0具体编号以tinymix输出为准 tinymix -D 0 13 0 # 右声道同理然后把音量调到合适的位置tinymix -D 0 10 200 tinymix -D 0 11 200用tinyplay播放一个WAV文件tinyplay /usr/share/sounds/test.wav -D 0 -d 0如果这一步出声音了说明从设备树到驱动的链路全部正常。如果没有声音就开始进入下一节的坑位排查。我遇到过很多次这种情况设备树配了、驱动编译了、声卡也注册了但就是不出声最后发现是某个看似无关紧要的时钟参数没配好。5. 调试中踩过的坑与排查思路复盘RK3588上调试ES8388有几类问题出现频率非常高。我说几个有代表性的附带完整的排查思路不是直接给结论而是把我当时的判断逻辑写出来这样换个平台遇到类似问题也能举一反三。5.1 坑一声卡注册成功但播放没有声音这是最常见的一类问题。tinymix能拿到控件列表tinyplay执行不报错但扬声器里什么动静都没有。我的排查步骤是第一步用示波器量ES8388的MCLK引脚。如果MCLK没有波形问题出在RK3588侧的时钟配置上检查assigned-clocks有没有配错引脚复用是不是被别的功能抢占了。在RK3588上I2S1_MCLK这个引脚比较容易被调试串口或者其他外设复用掉因为它的默认功能可能不是I2S时钟。第二步如果MCLK有波形量I2S的SCLK和LRCK。这两个信号在播放时会持续输出如果SCLK没有动静说明I2S控制器没有被正确使能检查设备树里I2S节点的status okay和pinctrl-0配置。第三步量I2S的SDO引脚数据输出。如果SDO没有波形说明CPU侧没有把数据送出来可能是dai-link的格式配置不对也可能是DMA通道问题。在RK3588平台上I2S控制器一般挂在dma通道上如果设备树里I2S节点缺少dmas和dma-names属性DMA不会工作数据根本送不到I2S控制器。第四步如果SDO有波形但codec不出声问题在codec内部。用i2cset手动操作寄存器把DAC音量调到最大、解除mute再播放测试。如果手动操作寄存器后出声了说明是ASoC层的控件初始化顺序有问题或者ALSA的mixer默认值把codec静音了。5.2 坑二主从模式配置错误导致时钟对不上ES8388可以工作在master模式也可以工作在slave模式。在master模式下ES8388自己产生LRCK和SCLK在slave模式下这两个时钟由CPU侧的I2S控制器提供。在RK3588平台上我强烈建议用CPU作为masterES8388作为slave。理由很简单RK3588的I2S控制器通过CRU的PLL可以精确产生各种采样率对应的时钟而ES8388内部没有高精度的PLL如果让它做主时钟MCLK的精度直接影响音频质量而且容易出现时钟抖动导致的爆音。ASoC框架中codec的主从模式是通过set_fmt回调设置的。在simple-audio-card的写法下如果format i2s默认会把CPU设置为mastercodec设置为slave一般不需要额外配置。但如果你用了其他的machine驱动可能需要在对应的ops-set_fmt里显式指定ret snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);这里的CBS_CFS意思是codec作为slave时钟都由CPU提供。如果配反了比如CPU和codec都认为自己是master两边各自产生时钟表现就是要么完全没声音要么断断续续。5.3 坑三左右声道反了或者单声道无声有时候出声了但左右声道反了或者某个声道没声音。这种问题不算致命但非常影响用户体验。排查思路先用一个单声道测试音频分别播放只有左声道信号和只有右声道信号的WAV确定是哪一侧出了问题。如果两个声道都有声音但左右反了最简单的解决办法是在设备树的sound节点里加上左右声道交换simple-audio-card,codec { sound-dai es8388; inverted-mclk; };不对inverted-mclk不是干这个用的。左右声道交换的正确做法是通过驱动里的set_channel_map或者硬件上把DAC的LRCK接反但多数情况下不需要走到这一步。很多Linux音频驱动里有一个dai_link-invert标志或者在machine驱动里配置交换声道。对于ES8388来说最简单的方法是在应用层用ALSA的route插件做左右声道交换但这属于治标不治本。我遇到过一次右声道无声的问题当时查了很久最后发现是ES8388驱动注册左声道和右声道的widget名称有误导致ALSA混音器只管到了左声道右声道被静音了。解决方法是修改es8388.c驱动中controls的定义在ES8388_DAC_CONTROLS数组里加正确映射。5.4 坑四MCLK频率和采样率跟不上这个坑最隐蔽因为它不是完全不工作而是“某些采样率能出声某些采样率没声音”。比如播放44.1kHz的音乐正常播放48kHz的音频就没声音或者全是噪声。ES8388的MCLK支持倍频从128到512不等但对于不同的采样率MCLK和建议倍频要匹配。如果设备树里配了assigned-clock-rates 12288000那么48kHz采样率时MCLK是256倍频正常。44.1kHz采样率时MCLK大约是278倍频ES8388能容忍一定范围的偏差但表现不稳定可能会出现偶尔爆音。如果项目里必须同时支持44.1kHz和48kHz的音频推荐把MCLK配成11289600还是12288000其实很多开发板用12.288MHz44.1kHz的音频在ALSA层会被重采样到48kHz交给codec时实际上还是48kHz。如果你想在应用层避免重采样带来的音质损失可以用plughw插件强制44.1kHz播放但codec侧驱动的hw_params回调能不能正确处理取决于驱动里对采样率的支持情况。这个问题没有100%通用的答案要根据你的具体应用场景来定。我只能说在ES8388上48kHz是它的舒适区48kHz的兼容性明显好于44.1kHz。5.5 坑五播放结束后有pop噪声pop噪声是模拟音频电路很烦人的问题。ES8388有一个寄存器0x09用于控制DAC的pop-noise抑制不过效果有限真正有效的办法是从硬件设计上解决比如在耳机输出端加一个延迟开关的功放芯片。软件层面能做的事情有两件。第一在播放开始前先让DAC上电然后延时几十毫秒再解除mute第二在播放结束后先mute再给DAC断电。这套流程在驱动里叫playback_power_eventES8388的驱动里有一个ES8388_DAC_EVENT处理函数可以用SND_SOC_DAPM_POST_PMU和SND_SOC_DAPM_PRE_PMD这两个事件来控制。实际调试的时候可以先用tinymix手动模拟这个过程测试pop噪声能否消除再写进驱动里。6. 简单调音与实用优化让ES8388的声音更自然基本通路通了之后接下来就是调音阶段。这里我不讲复杂的EQ和DSP调音只讲ES8388驱动里几个直接有效的调节手段。6.1 DAC音量控制和左右平衡ES8388的DAC输出音量由寄存器0x10和0x11控制左声道和右声道分开默认值都是0x00意思是0dB增益。范围从0到255但实际上超过0xE8之后增益不会再增加反而会开始削波所以不要把音量调到最大。在ALSA层调整音量的命令是tinymix -D 0 10 180 tinymix -D 0 11 1800x180是0dB附近的值适合作为默认音量。左右声道如果存在音量差可以通过分别设置这两个寄存器来校正。我遇到过一块板子左声道比右声道声音大2dB的情况当时就是用这种方式在驱动初始化时做固定补偿不用改硬件。6.2 ADC采集增益与麦克风偏置如果你项目里还需要用ES8388采集麦克风信号需要注意几个地方。ES8388的ADC最大输入电平是2.2Vpp如果麦克风输出信号过大ADC会削波过小信号噪底太高。寄存器0x15和0x16控制左右声道ADC增益范围从0x000dB到0xCF24dB。麦克风偏置电压则是通过寄存器0x01的MICAMPL和MICAMPLR位控制的可以选2.2V或者2.4V。驻极体麦克风一般用2.2V就够了如果用的是硅麦MEMS麦克风注意看数据手册需要的偏置电压。在Linux应用层用tinycap录音之前先用tinymix把输入通路配置好。6.3 设备树里外设顺序对启动的影响聊一个比较偏但很实用的话题设备树节点的顺序会影响启动时ALSA声卡的编号。RK3588上如果板子上还有HDMI音频、DP音频等其他声卡ES8388的声卡编号不一定固定是card0有可能是card1或者card2。这会导致一些写死hw:0,0的应用无法播放。解决办法有两个。一是在设备树里调整simple-audio-card节点的注册顺序让它比HDMI音频先注册二是写一个udev规则根据/proc/asound/cards里的名字创建固定软链接KERNELcontrolC*, SUBSYSTEMsound, ATTRS{id}rk3588-es8388, SYMLINKsnd_es8388_control这个办法在很多嵌入式Linux产品里都适用比改驱动里声卡的索引号要干净得多。6.4 系统休眠唤醒后的音频恢复RK3588平台做产品的话大概率会遇到系统休眠唤醒后音频失效的问题。原因是休眠时音频相关的时钟域全部断电唤醒后ES8388的寄存器恢复到了默认值但ALSA层还认为控件状态没变两边状态不一致。解决办法是在驱动的resume回调里重新初始化codec寄存器。ES8388驱动里有一个es8388_resume函数内容一般是static int es8388_resume(struct snd_soc_component *component) { es8388_set_bias_level(component, SND_SOC_BIAS_STANDBY); es8388_set_bias_level(component, SND_SOC_BIAS_ON); return 0; }如果你发现唤醒后出声时声音很大或者哑音多半就是这个函数没有被正确调用。调试时可以手动在唤醒后执行一下tinymix重新设置音量如果这样恢复正常说明驱动里resume逻辑确实缺失了。7. 我自己平时调试RK3588 audio的几条心得文章最后说几点纯粹的个人经验不一定写在某个芯片手册里但实际开发中挺有用。第一一定要在驱动里打开debug日志。es8388.c驱动里有个DEBUG宏开关打开后每个寄存器读写操作都会打印出来。调试初期开着这个日志配合i2cget去读能少走很多弯路。第二把常用的tinyalsa命令做成一键脚本。每次调试都手动敲一遍tinymix很浪费时间我在板子上放了一个audio_test.sh里面写好了播放、录音、音量设置、通路配置等常用命令每次改动完直接执行脚本验证。第三调音阶段的波形分析工具别省。用PC声卡采集ES8388模拟输出的信号放到Audacity里看频谱能看到很多耳朵听不出来的问题比如不经意间的高频噪声和采样率偏差造成的频偏。ES8388这颗codec在RK3588上的调试本质上就是一条链路反复验证从设备树到驱动从驱动到寄存器从寄存器到模拟输出。每个环节都跑通了音频就通了。希望这篇实战记录能给正在调RK3588音频的你一些参考少踩一些我填过的坑。

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

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

免费获取报价 →
↑