工作室名字,seo怎么发布外链,vs做网站标签输出语言,wordpress 如何调试1. 移植前的准备#xff1a;理解AW88195与平台差异 大家好#xff0c;我是老张#xff0c;在音频驱动这块摸爬滚打了十来年#xff0c;从功能机时代的单声道喇叭做到现在的智能音箱、AR眼镜#xff0c;各种平台的驱动移植没少折腾。最近刚把一个项目上的AW88195音频Codec驱…1. 移植前的准备理解AW88195与平台差异大家好我是老张在音频驱动这块摸爬滚打了十来年从功能机时代的单声道喇叭做到现在的智能音箱、AR眼镜各种平台的驱动移植没少折腾。最近刚把一个项目上的AW88195音频Codec驱动从MTK平台成功搬到了RK的PX30平台上整个过程踩了不少坑也总结了一些通用性的经验今天就跟大家详细唠唠。AW88195是艾为电子推出的一款高性能智能音频放大器内置DSP主打的就是提升扬声器的音质和响度在手机、平板、音箱里很常见。厂商提供的驱动包比如AW88195_Driver_MTK_V0.1.6.zip顾名思义是专门为联发科MTK平台适配好的。而我们要做的就是把它“搬家”到瑞芯微RK的平台上我这次用的就是PX30系统是Android 8.1。为什么不能直接用这就好比给一辆丰田车换了个宝马的发动机发动机本身AW88195芯片没变但车架硬件平台、电路布线总线协议、行车电脑内核及框架全都不一样了。MTK和RK虽然底层都是Linux内核但芯片架构、音频子系统设计、设备树DTS的编写规范、甚至内核配置选项的命名都可能存在差异。直接照搬十有八九编译都过不了更别说跑起来了。所以动手前别急着敲代码。我的习惯是先花点时间做“侦察”对比源码目录结构分别查看MTK SDK和RK SDK里音频驱动相关文件都放在哪些路径下。比如Codec驱动通常在内核的sound/soc/codecs/目录但具体子目录命名可能不同。理清依赖关系用文本编辑器打开驱动包里的.c和.h文件快速浏览一下头文件包含#include。看看它依赖了哪些平台特有的头文件或API比如MTK可能会有mtk-soc-xxx.h之类的这些在RK平台上肯定没有需要找到对应的替代品或者自己实现。研究目标平台框架RK平台尤其是PX30这类常用的Machine驱动负责链接CPU DAI和Codec DAI的“红娘”是什么我这次遇到的就是内核自带的simple-card。你得先弄明白它是怎么工作的怎么通过设备树来配置音频链路。把这些前期功课做足了心里有个大概的迁移地图再动手移植就会有条理得多避免像无头苍蝇一样到处乱撞。记住移植的核心思路是保留芯片驱动本身的通用逻辑替换掉所有与MTK平台强绑定的“胶水代码”。2. 驱动文件移植与内核集成侦察完毕接下来就是真刀真枪地搬代码了。厂商给的驱动包解压后里面主要就是一些.c、.h文件可能还有编译脚本。我们的目标是把这些文件放到RK内核源码树的正确位置并让内核的构建系统Kbuild认识它、编译它。第一步放置驱动文件。我一般会在sound/soc/codecs/目录下为这个Codec单独创建一个文件夹比如aw88195。这样管理起来清晰不会和内核自带的其它Codec文件混在一起。把驱动包里的所有.c和.h文件都拷贝到这个aw88195目录下。第二步创建编译配置文件。光有源文件还不够需要告诉内核怎么编译它们。这需要两个文件Makefile和Kconfig直接在aw88195目录下创建。Makefile的作用是指定要编译哪些源文件以及生成什么内核模块。内容大致如下# 指定目标模块名和对应的源文件 snd-soc-aw88195-objs : aw88195.o aw88195-dsp.o aw88195-i2c.o # 根据配置选项决定是将模块编译进内核y还是编译为模块m或者不编译空 obj-$(CONFIG_SND_SOC_AW88195) snd-soc-aw88195.o这里snd-soc-aw88195-objs列出了构成这个驱动模块的所有.o文件由对应的.c文件编译而来。CONFIG_SND_SOC_AW88195就是我们即将在Kconfig中定义的配置选项。Kconfig文件则是用于在内核配置界面比如make menuconfig中生成一个配置选项让开发者可以选择是否编译该驱动。内容如下config SND_SOC_AW88195 tristate AW88195 Smart K PA with DSP depends on I2C SND_SOC help Say Y or M if you want to add support for AWINIC AW88195 Smart K PA with DSP. This driver supports I2C control interface. If unsure, say N.tristate表示三态y编译进内核、m编译为可加载模块、n不编译。depends on指明了依赖这个驱动需要I2C总线和SND_SOCALSA SoC框架的支持。help里的描述会在配置界面显示方便理解。第三步将新驱动纳入顶层构建。现在aw88195目录自己完备了但上一级目录codecs/还不知道它的存在。需要修改sound/soc/codecs/目录下的Makefile和Kconfig。在codecs/Makefile中添加上一行obj-$(CONFIG_SND_SOC_AW88195) aw88195/这行代码的意思是如果配置了CONFIG_SND_SOC_AW88195就去编译aw88195/这个子目录。在codecs/Kconfig中添加上一行source sound/soc/codecs/aw88195/Kconfig这相当于把子目录的Kconfig内容包含进来这样在顶层配置时就能看到AW88195的选项了。第四步配置内核。最后我们需要在RK平台的内核默认配置文件中打开这个选项确保编译时驱动能被包含进去。RK平台的内核配置文件通常位于arch/arm64/configs/rockchip_defconfig对于64位平台。用编辑器打开它在末尾或合适的位置添加CONFIG_SND_SOC_AW88195y这里我直接写y表示默认编译进内核。如果你希望编译成模块可以写m。做完以上四步驱动代码就已经成功“落户”到RK内核源码树了。执行内核编译命令比如make ARCHarm64 rockchip_defconfig make ARCHarm64 -j8如果一切顺利你应该能在最终的镜像中看到这个驱动被编译进去了。这是万里长征的第一步也是最基础的一步。3. 设备树DTS配置与声卡注册代码能编译通过只代表语法没问题。要让AW88195真正工作起来必须正确地向内核“描述”这块芯片在硬件上是怎么连接的。这个描述工作就是通过**设备树Device Tree DTS**来完成的。这是嵌入式Linux开发里非常关键的一环也是从MTK移植到RK变动最大、最容易出错的地方。在MTK的平台驱动里硬件信息可能部分通过代码写死部分通过DTS描述。而RK平台尤其是使用simple-card这类通用Machine驱动时更依赖DTS。我们需要在DTS里完成两件事定义AW88195这个I2C设备以及定义音频链路Dai Link。首先定义I2C设备节点。找到你的板级DTS文件通常在arch/arm64/boot/dts/rockchip/目录下文件名类似rkpx30-xxx.dts。我们需要在对应的I2C控制器节点比如i2c1下添加AW88195的子节点。假设AW88195挂在I2C1上地址是0x34具体地址要查原理图那么添加如下内容i2c1 { status okay; clock-frequency 400000; // I2C速率400kHz aw88195: aw8819534 { compatible awinic,aw88195; reg 0x34; reset-gpio gpio2 RK_PC1 GPIO_ACTIVE_LOW; irq-gpio gpio0 RK_PA5 GPIO_ACTIVE_HIGH; awinic,audio-channel 0; // 芯片工作模式根据硬件连接设置 #sound-dai-cells 0; status okay; }; };compatible属性是重中之重必须和驱动中of_device_id表里的字符串匹配。这里是awinic,aw88195。reg就是I2C设备地址。reset-gpio和irq-gpio根据实际硬件连接的GPIO来设置。RK_PC1这种是RK平台的GPIO命名方式和MTK完全不同务必对照硬件手册修改。#sound-dai-cells 0; 表示这个节点作为一个简单的sound DAI数字音频接口不需要额外的参数。其次定义音频链路Dai Link。这是连接CPU音频接口如I2S和CodecAW88195的“桥梁”。RK平台常用simple-audio-card节点来描述。这个节点可以放在DTS的根节点下或者一个有意义的位置。sound { compatible simple-audio-card; simple-audio-card,name aw88195-sound; simple-audio-card,format i2s; simple-audio-card,mclk-fs 256; // 主时钟与采样率倍数关系 simple-audio-card,widgets Speaker, Speaker; // 音频路径控件 simple-audio-card,routing Speaker, SPK; // 音频路由 simple-audio-card,dai-link0 { format i2s; cpu { sound-dai i2s0_8ch; // 指向CPU端的I2S控制器节点 }; codec { sound-dai aw88195; // 指向我们上面定义的aw88195节点 }; }; };sound-dai i2s0_8ch; 这里的i2s0_8ch是RK平台I2S控制器的节点标签需要根据你的硬件连接确认是哪个I2S。sound-dai aw88195; 这里的aw88195就是我们之前定义的AW88195节点的标签。format、mclk-fs等参数需要根据AW88195的数据手册和RK平台I2S控制器的能力来设置确保两端匹配。配置完成后编译内核并更新设备树。启动系统后你可以通过命令cat /proc/asound/cards或cat /proc/asound/pcm来查看声卡是否注册成功。如果看到类似00-00: i2s0-aw88195 aw88195-aif-0这样的输出恭喜你声卡已经成功注册驱动和硬件的基本通信链路已经打通了4. 固件加载与调试技巧AW88195是一颗带DSP的智能功放它的核心算法和调音参数通常都放在一个独立的固件文件里比如aw88195_acf.bin或aw88195_cfg.bin。驱动在初始化时需要从文件系统中读取这个固件并下载到芯片的DSP中芯片才能正常工作。这是移植过程中另一个容易卡住的地方。固件存放路径。在Android系统里固件一般放在/vendor/etc/firmware/或/system/etc/firmware/目录下。但内核默认的固件搜索路径可能不包含这些位置。我们需要确认或修改内核的固件搜索路径。查看内核源码drivers/base/firmware_class.c文件可以找到fw_path数组static const char * const fw_path[] { fw_path_para, /system/vendor/firmware, /system/etc/firmware, /vendor/firmware, /lib/firmware/updates/ UTS_RELEASE, /lib/firmware/updates, /lib/firmware/ UTS_RELEASE, /lib/firmware };通常Android系统已经添加了/vendor/firmware等路径。如果不放心可以在驱动加载早期比如probe函数里打印一下固件路径或者直接在你的板子上cat /sys/module/firmware_class/parameters/path查看当前路径。驱动中的固件加载。在AW88195驱动的初始化函数通常是aw88195_i2c_probe中会调用内核的固件请求API来加载固件。核心代码逻辑一般是这样的static int aw88195_load_cfg(struct aw88195 *aw88195) { const struct firmware *cfg_fw NULL; int ret; ret request_firmware(cfg_fw, AW88195_CFG_NAME, aw88195-dev); if (ret) { dev_err(aw88195-dev, load [%s] failed, ret%d\n, AW88195_CFG_NAME, ret); return ret; } dev_info(aw88195-dev, load [%s] success, size%zu\n, AW88195_CFG_NAME, cfg_fw-size); // 这里会将cfg_fw-data中的数据通过I2C写入芯片的特定寄存器 // ... 你的固件解析和下载代码 ... release_firmware(cfg_fw); return 0; }request_firmware()是同步请求会阻塞直到固件加载完成或超时。AW88195_CFG_NAME就是固件文件名比如aw88195_cfg.bin。加载成功后cfg_fw-data指向固件数据cfg_fw-size是数据大小。你需要按照AW88195芯片手册的协议将这些数据通过I2C总线写入芯片。确保固件被系统包含。最后别忘了在Android的编译系统中将你的固件文件打包进镜像。通常是在device/rockchip/xxx/device.mk或类似的产品配置mk文件中添加PRODUCT_COPY_FILES \ vendor/awinic/aw88195/firmware/aw88195_cfg.bin:$(TARGET_COPY_OUT_VENDOR)/etc/firmware/aw88195_cfg.bin调试技巧与问题排查。移植完成后先别急着上应用层测试。用最底层的工具验证检查设备节点系统启动后先看/dev/snd/目录下有没有生成对应的音频设备节点比如pcmC0D0p播放、controlC0控制。使用tinyplay/tinycap这是ALSA提供的小型命令行播放/录制工具不经过Android Audio HAL直接操作ALSA驱动。用tinyplay /sdcard/test.wav播放一个WAV文件。如果这里都没声音那问题肯定在驱动层或DTS配置。查看内核日志dmesg | grep aw88195或cat /proc/kmsg | grep aw88195关注驱动probe是否成功、固件是否加载、I2C通信是否正常、声卡注册信息等。错误信息通常在这里一目了然。I2C工具调试如果驱动没起来可以用i2cdetect命令扫描I2C总线看能否检测到0x34地址的设备确认硬件连接和I2C控制器配置是否正确。检查时钟和电源音频设备对时钟很敏感。确认你的DTS中相关的I2S控制器和I2C控制器的时钟clocks属性以及电源power-domains或supplies属性是否都已正确开启status “okay”。驱动移植是个细致活尤其是音频驱动涉及软硬件协同。按照以上步骤从文件移植、内核配置、DTS修改到固件加载一步步来同时善用底层调试工具大部分问题都能被定位和解决。当你能用tinyplay听到清脆的测试音时那种成就感搞过嵌入式的人都懂。剩下的就是和Audio HAL对接以及上层适配的工作了那又是另一个层面的故事。希望这篇实战记录能帮你少走些弯路。