嵌入式驱动开发详解16(音频驱动开发)
文章目录
- 前言
- WM8960简介
- I2S协议
- 接口说明
- SAI音频接口简介
- 驱动框架简介
- 设备树配置
- 内核使能
- 声卡设置与测试
- 后续
- 参考文献
前言
该专栏主要是讲解嵌入式相关的驱动开发,但是由于ALSA驱动框架过于复杂,实现音频编解码芯片的驱动不是一个人能完成的,所以没有对应具体的驱动代码相关内容,包括后面的CAN,USB,WIFI,4G模块这些都是比较复杂的,都只会讲解相关的协议等基础知识
音频是我们最常用到的功能,音频也是 linux 和安卓的重点应用场合。由于音频驱动开发任务量巨大,不是一个人能全流程实现的,因此只是通过修改设备树和已写好的驱动进行修改开发,该专栏后面的USB驱动、网络驱动等都是如此,对基础感兴趣的可以参考专栏的前部分文章。处理器如果既想“听到”外界的声音,又想向外界传达自己的“心声”, 那么就需要同时用到 DAC 和 ADC 这两款芯片。为了满足声音能够进行一些处理(需要 DSP 单元)、拥有统一的标准接口,方便开发等功能,因此音频编解码芯片出现了,英文名字就是 Audio CODEC,在手机或者电脑的介绍中看到“CODEC”这个词语,一般说的都是音频编解码,后面我们将会以WM8960进行分析。
WM8960简介
WM8960 是一颗由 wolfson(欧胜)公司出品的音频编解码芯片,是一颗低功耗、高质量的立 体声音频 CODEC。集成 D 类喇叭功放,每个通道可以驱动一个 1W 喇叭(8Ω)。内部集成 3 个 立体声输入源,可以灵活配置,拥有一路完整的麦克风接口。WM8960 内部 ADC 和 DAC 都为 24 位,WM8960 主要特性如下所示:
①、DAC 的 SNR(信噪比)为 98dB,3.3V、48KHz 下 THD(谐波失真)为-84dB。
②、ADC 的 SNR(信噪比)为 94dB,3.3V、48KHz 下 THD(谐波失真)为-82dB。
③、3D 增强。
④、立体声 D 类功放,可以直接外接喇叭,8Ω负载下每通道 1W。
⑤、集成耳机接口。
⑥、集成麦克风接口。
⑦、采样率支持 8K、11.025K、12K、16K、22.05K、24K、32K、44.1K 和 48K。

①、此部分是 WM8960 提供的输入接口,作为立体声音频输入源,一共提供了三路,分别 为 LINPUT1/RINPUT1、LINPUT2/RINPUT2、LINPUT3/RINPUT3。
②、此部分是 WM8960 的输出接口,比如输出给耳机或喇叭,SPK_LP/SPK_LN 用于连接 左声道的喇叭,支持 1W 的 8Ω喇叭。SPK_RP/SPK_RN 用于连接右声道的喇叭,同样支持 1W 的 8Ω喇叭,最后就是 HP_L/HP_R,用于连接耳机。
③、此部分是数字音频接口,用于和主控制器连接,有 5 根线,用于主控制器和 WM8960 之间进行数据“沟通”。此接口支持 I2S 格式。
④、此部分为控制接口,是一个标准的 I2C 接口,WM8960 要想工作必须对其进行配置, 这个 I2C 接口就是用于配置 WM8960 的。
I2S协议
接口说明
I2S(Inter-IC Sound)总线有时候也写作 IIS,I2S 是飞利浦公司提出的一种用于数字音频设备 之间进行音频数据传输的总线。和 I2C、SPI 这些常见的通信协议一样,I2S 总线用于主控制器 和音频 CODEC 芯片之间传输音频数据。要想使用 I2S 协议,主控制器和音频 CODEC 都 得支持 I2S 协议,I.MX6ULL 的 SAI 外设就支持 I2S 协议。
I2S 接口需要 5 根信号线,如下:
WS:字段(声道)选择信号,也叫做 LRCK,也叫做帧时钟,用于切换左右声道数据,WS 为 “1”表示正在传输左声道的数据,WS 为“0”表示正在传输右声道的数据。WS 的频率等于采 样率。
SCK:串行时钟信号,也叫做位时钟(BCLK),音频数据的每一位数据都对应一个 SCK,立 体声都是双声道的,因此 SCK=2×采样率×采样位数。
SD:串行数据信号,也就是我们实际的音频数据,如果要同时实现放音和录音,那么就需 要 2 根数据线,比如 WM8960 的ADCDAT 和 DACDAT,就是分别用于录音和放音。数据最高位优先传输,数据的最高位总是出现在一帧开始后(LRCK 变化)的第2个SCK脉冲处。
MCLK:为了使音频 CODEC 芯片与主控制器之间能够更好的同步,会引入另外一个 叫做 MCLK 的信号,也叫做主时钟或系统时钟,一般是采样率的 256 倍或 384 倍。
对应的时序图如下图所示,其中SD数据相对于LRCK和SCLK位置的不同存在Left Justified(左对齐)和 Right Justified(右对齐)两种格式:

SAI音频接口简介
在 STM32 中就是通过 SAI 接口来连接音频 CODEC,I.MX6ULL 也提供了一个叫做 SAI 的外设,全称为 Synchronous Audio Interface,翻译 过来就是同步音频接口。
SAI 是一个全双工、支持帧同步的串行接口,支持 I2S、AC97、TDM 和音频 DSP,SAI 主要特性如下:
①、帧最大为 32 个字。
②、字大小可选择 8bit 或 32bit。
③、每个接收和发送通道拥有 32×32bit 的 FIFO。
④、FIFO 错误以后支持平滑重启。


根据上面两个原理图可以看出,SYNC和BCLK只需要连接L或者R的其中一个即可。
驱动框架简介
前面对声卡WM8960,I2S协议以及ASI的I2S接口都做了一定的解释,如果需要更深入的了解可以网上查阅与之相关的资料,这里不在做过多的分析。
WM8960 与 I.MX6ULL 之间有两个通信接口:I2C 和 SAI,因此设备树中会涉及到 I2C 和 SAI 两个设备节点。
- 需要一个WM8960驱动文件,I2C框架, 用于配置 WM8960
- 需要一个SOC端SAI外设的驱动文件用于音频数据传输
- 需要一个驱动文件,将WM8960和SOC联系起来
因为第三点的需要,ALSA、ASoC驱动应运而生:ASoC是在ALSA基础上,针对SOC另外改进的ALSA音频驱动框架,目前ARM处理的音频驱动框架都是ASoC,ASoC包含三个部分:SOC(platform)、Codec部分、板载硬件(Machine):
- SOC:具体的SOC音频接口驱动,SAI接口,是由半导体厂商编写好的
- Codec:具体的音频芯片,比如WM8960,IIC驱动,也不需要我们编写,Codec芯片厂商会写好
- 板载硬件(Machine):将具体的SOC与具体的Codec结合,与具体的硬件设备相关,也就是我们要处理的部分,使用ASOC驱动框架将SOC于Codec结合。
设备树配置
- 首先配置一下 I2C 接口,WM8960 连接到了 I2C1 上,因此需要在设备树中的“i2c1”节点下需要添加 wm8960 信息。设备树的绑定手册:Documentation/devicetree/bindings/sound/wm8960.txt,文档给出历程如下:
codec: wm8960@1a {compatible = "wlf,wm8960";reg = <0x1a>;wlf,shared-lrclk;
};
compatible属性值可以找到Codec厂商写好的对应的驱动文件,在sound/soc/codecs/wm8960.c里面。
reg设置 WM8960 的 I2C 地址
wlf,shared-lrclk是一个 bool 类型的属性,如果添加了此属性,WM8960 的 R24 寄存器 的 LRCM 位(bit2)就会置 1。当 LRCM 为 1 的时候只有当 ADC 和 DAC 全部关闭以后 ADCLRC 和 DACLRC 时钟才会关闭。
- 其次就是配置sai2的控制器驱动,在设备树下面可以找到如下内容:
/{soc {aips1: aips-bus@02000000 {spba-bus@02000000 {sai2: sai@0202c000 {compatible = "fsl,imx6ul-sai","fsl,imx6sx-sai";reg = <0x0202c000 0x4000>;interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6UL_CLK_SAI2_IPG>,<&clks IMX6UL_CLK_DUMMY>,<&clks IMX6UL_CLK_SAI2>,<&clks 0>, <&clks 0>;clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";dma-names = "rx", "tx";dmas = <&sdma 37 24 0>, <&sdma 38 24 0>;status = "disabled";};
……
在另外一个文档追加了以下内容
&sai2 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_sai2 &pinctrl_sai2_hp_det_b>;assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>,<&clks IMX6UL_CLK_SAI2>;assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;assigned-clock-rates = <0>, <12288000>;status = "okay";
};
compatible属性可以找到对应的驱动文件为sound/soc/fsl/fsl_sai.c。
pinctrl_sai2_hp_det_b描述的是耳机插入检测引脚,wm8960 支持耳机插入检测,这样当耳机插入以后就会通过耳机播放音乐,当耳机拔出来以后就会通过喇叭播放音乐。
- 最后就是板载硬件(Machine),sound节点,sound节点主要起到链接Codec和sai的作用,具体内容如下:
/{sound {compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";model = "wm8960-audio";cpu-dai = <&sai2>;audio-codec = <&codec>;asrc-controller = <&asrc>;codec-master;gpr = <&gpr 4 0x100000 0x100000>;/** hp-det = <hp-det-pin hp-det-polarity>;* hp-det-pin: JD1 JD2 or JD3* hp-det-polarity = 0: hp detect high for headphone* hp-det-polarity = 1: hp detect high for speaker*/hp-det = <3 0>;
// hp-det-gpios = <&gpio5 4 0>;
// mic-det-gpios = <&gpio5 4 0>;audio-routing ="Headphone Jack", "HP_L","Headphone Jack", "HP_R","Ext Spk", "SPK_LP","Ext Spk", "SPK_LN","Ext Spk", "SPK_RP","Ext Spk", "SPK_RN","LINPUT2", "Mic Jack","LINPUT3", "Mic Jack","RINPUT1", "Main MIC","RINPUT2", "Main MIC","Mic Jack", "MICB","Main MIC", "MICB","CPU-Playback", "ASRC-Playback","Playback", "CPU-Playback","ASRC-Capture", "CPU-Capture","CPU-Capture", "Capture";};
};
compatible属性可以找到对应的驱动文件为sound/soc/fsl/imx_wm8960.c,理论上这个文件是需要我们自己编写的,刚好NXP的板子也是用的WM8960这个音频解码芯片,可以直接用。
model:最终用户看到的此声卡名字,这里设置为“wm8960-audio”
cpu-dai:CPU DAI(Digital Audio Interface)句柄,这里是 sai2 这个节点。
audio-codec:音频解码芯片句柄,也就是 WM8960 芯片,这里为“codec”这个节点。
asrc-controller:asrc 控制器,asrc 全称为 Asynchronous Sample Rate Converters,翻译过来 就是异步采样频率转化器。
hp-det:耳机插入检测引脚设置,第一个参数为检测引脚,3 表示 JD3 为检测引脚。第二个 参数设置检测电平,设置为 0 的时候,hp 检测到高电平表示耳机插入;设置为 1 的时候,hp 检 测到高电平表示是喇叭,也就是耳机拔出了。
audio-routing:音频器件一系列的连接设置,每个条目都是一对字符串,第一个字符串是 连接的 sink,第二个是连接的 source(源)。
内核使能
利用图形化配置界面,取消 ALSA 模拟 OSS,使能WM8960 驱动(Asynchronous Sample Rate Converter (ASRC) module support 和 SoC Audio support for i.MX boards with wm8960),驱动使能以后重新编译 linux 内核,编译完成以后使用新的 zImage 和.dtb 文件启动。
驱动挂载成功之后会在/dev/snd 目录生成对应的节点:
controlC0:用于声卡控制,C0 表示声卡 0。
pcmC0D0c 和 pcmC0D1c:用于录音的 pcm 设备,其中的“COD0”和“C0D1”分别表示 声卡 0 中的设备 0 和设备 1,最后面的“c”是 capture 的缩写,表示录音。
pcmC0D0p 和 pcmC0D1p:用于播放的 pcm 设备,其中的“COD0”和“C0D1”分别表示 声卡 0 中的设备 0 和设备 1,最后面的“p”是 playback 的缩写,表示放音。
timer:定时器。
音频驱动使能以后还不能直接播放音乐或录音,我们还需要移植 alsa-lib 和 alsa-utils 这两 个东西。
声卡设置与测试
应用上的设置与测试这里就不再赘述,都按照别人写好的流程依葫芦画瓢,大家可以参考正点原子的教材进行开发。
后续
本人对嵌入式行业兴趣浓厚,但是发现驱动开发越学越迷茫,个人感觉就是驱动开发就算是去芯片原厂或者模组原厂也是做一些缝缝补补或者移植的工作,且需要对某一个领域,比如音频、网络、蓝牙等领域研究特别深入才可能有能力做驱动开发工作,目前本人处于学习阶段,不太可能深耕某一个领域,因此当前阶段就仅仅只是了解驱动是如何实现底层工作的,后期可能会继续研究MCU的RTOS开发和Linux从bootloader->linux内核裁剪->驱动修改->应用开发,并将自己所学的皮毛用于开发一个小项目吧!!!
希望对此方向感兴趣的伙伴能一起评论交流!!!!
参考文献
- 个人专栏系列文章
- 正点原子嵌入式驱动开发指南
- 对代码有兴趣的同学可以查看链接https://github.com/NUAATRY/imx6ull_dev
相关文章:
嵌入式驱动开发详解16(音频驱动开发)
文章目录 前言WM8960简介I2S协议接口说明 SAI音频接口简介驱动框架简介设备树配置内核使能声卡设置与测试 后续参考文献 前言 该专栏主要是讲解嵌入式相关的驱动开发,但是由于ALSA驱动框架过于复杂,实现音频编解码芯片的驱动不是一个人能完成的…...
【嵌入式软件】跑开发板的前置服务配置
在嵌入式开发中,通常需要在 开发板和主机之间共享、传输和挂载文件。 这篇文章是关于如何在 Ubuntu 中配置 Samba、TFTP 和 NFS 协议的详细步骤。这些协议分别用于远程文件共享、文件传输和内核挂载文件系统。 如何安装协议: 参考:ubuntu18配置:详细的内容我手写了一份文档。…...
如何高效实现进程间通信
实现进程间通信(IPC)有多种高效的方法,以下是一些常见的技术及其简要说明: 1. 共享内存: 共享内存是一种高效的进程间通信机制,允许多个进程共享同一块内存区域以实现快速的数据交换。与其他IPC机制相比&a…...
scala基础学习_变量
文章目录 scala中的变量常量 val(不可变变量)变量 var变量声明多变量声明匿名变量 _ 声明 变量类型声明变量命名规范 scala中的变量 常量 val(不可变变量) 使用val关键字声明变量是不可变的,一旦赋值后不能被修改 对…...
Java 身份证校验工具类(15位校验、18位校验与15转18)
文章目录 身份证简介(一)身份证号码的组成(二)一代和二代身份证一代身份证二代身份证 检验思路分析(一)15位身份证号码(二)18位身份证号码(三)校验算法示例&a…...
HTML+CSS+Vue3的静态网页,免费开源,可当作作业使用
拿走请吱一声,点个关注吧,代码如下,网页有移动端适配 HTML <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width…...
【FAQ】HarmonyOS SDK 闭源开放能力 —Push Kit(8)
1.问题描述: 在AGC中,推送服务的消息回执新建成功后,有一个有效期 1,这个有效期是什么意思,过期后,会影响什么呢? 2,这个有效期是否可以修改成一直不过期? 解决方案&…...
HCIA-Access V2.5_2_2_2网络通信基础_IP编址与路由
网络层数据封装 首先IP地址封装在网络层,它用于标识一台网络设备,其中IP地址分为两个部分,网络地址和主机地址,通过我们采用点分十进制的形式进行表示。 IP地址分类 对IP地址而言,它细分为五类,A,B,C,D,E,…...
音频客观测评方法PESQ
一、简介 语音质量感知评估(Perceptual Evaluation of Speech Quality)是一系列的标准,包括一种用于自动评估电话系统用户所体验到的语音质量的测试方法。该标准于2001年被确定为ITU-T P.862建议书[1]。PESQ被电话制造商、网络设备供应商和电…...
前后端分离的项目使用nginx 解决 Invalid CORS request
我是这样打算的,前端用nginx代理,使用80 转443 端口走https 前端的地址就是http://yumbo.top 或https://yumbo.top 后端服务地址是:http://yumbo.top:8081 下面是我的完整配置,功能是正常的,加了注释 user nginx; …...
回归预测 | MATLAB实现SVM-Adaboost集成学习结合支持向量机多输入单输出回归预测
回归预测 | MATLAB实现SVM-Adaboost集成学习结合支持向量机多输入单输出回归预测 目录 回归预测 | MATLAB实现SVM-Adaboost集成学习结合支持向量机多输入单输出回归预测基本介绍程序设计基本介绍 SVM-Adaboost集成学习是一种将支持向量机(SVM)与AdaBoost算法相结合的集成学习…...
常见排序算法总结 (五) - 堆排序与堆操作
堆排序(借助 API) 算法思想 利用堆能够维护数组中最大值的性质,根据数组元素建立最大堆,依次弹出元素并维护堆结构,直到堆为空。 稳定性分析 堆排序是不稳定的,因为堆本质上是完全二叉树,排…...
kubernetes的三种探针ReadinessProbe、LivenessProbe和StartupProbe,以及使用示例
前言 k8s中的Pod由容器组成,容器运行的时候可能因为意外情况挂掉。为了保证服务的稳定性,在容器出现问题后能进行重启,k8s提供了3种探针 k8s的三种探针 为了探测容器状态,k8s提供了两个探针: LivenessProbe和ReadinessProbe L…...
掌握线性回归:从简单模型到多项式模型的综合指南
目录 一、说明 二、简单线性回归 三、线性回归的评估指标 3.1 线性回归中的假设 四、从头开始的简单线性回归代码 五、多元线性回归 六、多元线性回归代码 七、多项式线性回归 八、多项式线性回归代码 九、应用单变量多项式回归 十、改变多项式的次数 十一、多列多项式回归 一、…...
Java:183 基于SSM的高校食堂系统
项目介绍 基于SSM的食堂点餐系统 角色:管理员、用户、食堂 前台用户可以实现商品浏览,加入购物车,加入收藏,预定,选座,个人信息管理,收货信息管理,收藏管理,评论功能,…...
光谱相机
光谱相机是一种能够同时获取目标物体的空间图像信息和光谱信息的成像设备。 1、工作原理 光谱相机通过光学系统将目标物体的光聚焦到探测器上,在探测器前设置分光元件,如光栅、棱镜或滤光片等,将光按不同波长分解成多个光谱通道,…...
AI绘图:开源Stable Diffusion 3 ComfyUI下载安装方法
AI绘图:开源Stable Diffusion 3 ComfyUI下载安装方法 安装好后软件运行效果: 第一步:安装ComfyUI的最新版本 1、请从下面的地址下载压缩包,并解压缩到硬盘 https://github.com/comfyanonymous/ComfyUI/releases/download/late…...
一区向量加权算法优化INFO-CNN-SVM卷积神经网络结合支持向量机多特征分类预测
一区向量加权算法优化INFO-CNN-SVM卷积神经网络结合支持向量机多特征分类预测 目录 一区向量加权算法优化INFO-CNN-SVM卷积神经网络结合支持向量机多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现INFO-CNN-SVM向量加权算法优化卷积神经网络结…...
AES笔记整理
文章目录 1. 简介2. 密钥加法层2. 字节代换层3. 行位移 - ShiftRows4. 列混淆 - MixColumn5. 其他5.1列混淆矩阵乘法运算5.2 AES密钥生成 6. 参考资料 以下内容为信息安全开发过程中,AES对称加密算法的笔记,大部分内容转载其他文章,若描述不清…...
Jmeter 性能压测-Tomcat连接数
1、影响性能的线程状态 ①BLOCKED,如果线程中有BLOCKED,就代表有阻塞情况,需要进行排查 ②TIMED_WAITING,如果线程中有TIMED_WAITING,就代表有等待的情况,要分情况来排查 系统线程在等待(如果…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...
