嵌入式驱动开发详解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结合。

设备树配置

  1. 首先配置一下 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 时钟才会关闭。

  1. 其次就是配置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 支持耳机插入检测,这样当耳机插入以后就会通过耳机播放音乐,当耳机拔出来以后就会通过喇叭播放音乐。

  1. 最后就是板载硬件(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 这两 个东西。

声卡设置与测试

在测试时我们可以用amixer工具,对驱动接口直接进行配置,该工具依赖两个工具alsa-lib和alsa-utils,需要把这两个源码编译好后将生成的部分文件移植到嵌入式平台上,随后即可利用amixer的配置指令对驱动进行配置,也可以将其写成脚本配置;使用aplay指令进行音频播放,由于每次重启之后都要重新配置,因此可以使用alsactl指令保存当前配置信息,并设置为开机自动执行该配置信息。
最后还有一个比较好用的工具是mplayer可以直接进行音视频的播放,它需要依赖与zlib和alsa-lib两个库,因此需要安装好zlib后再安装mplayer,将安装生成的脚本移植到嵌入式平台即可使用mplayer指令。
应用上的设置与测试这里就不再赘述,都按照别人写好的流程依葫芦画瓢,大家可以参考正点原子的教材进行开发。

后续

本人对嵌入式行业兴趣浓厚,但是发现驱动开发越学越迷茫,听有些up主驱动开发就算去芯片原厂或者模组原厂也是做缝缝补补或者移植的工作,一般需要要求对某一个领域,比如音频、网络、蓝牙等领域研究特别深入才可能有能力做驱动开发工作,目前本人处于学习阶段,不太可能深耕某一个领域,因此当前阶段就仅仅只是了解驱动是如何实现底层工作的,后期可能会继续研究MCU的RTOS开发和Linux从bootloader->linux内核裁剪->驱动修改->应用开发,并将自己所学的皮毛用于开发一个小项目。
希望对此方向感兴趣的伙伴能一起评论交流!!!!

参考文献

  1. 个人专栏系列文章
  2. 正点原子嵌入式驱动开发指南
  3. 对代码有兴趣的同学可以查看链接https://github.com/NUAATRY/imx6ull_dev

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/939082.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenGL ES 03 加载3张图片并做混合处理

OpenGL ES 02 加载3张图片并做混合处理 什么是纹理单元纹理单元的作用使用纹理单元的步骤详细解释加载图片并绑定到到GPU纹理单元采样器的设置1.设置采样器变量的纹理单元编号&#xff0c;目的是为了告诉纹理采样器&#xff0c;从哪个纹理单元采集数据2.如果你没有显式地设置采…

JAVA没有搞头了吗?

前言 今年的Java程序员群体似乎承受着前所未有的焦虑。投递简历无人问津&#xff0c;难得的面试机会也难以把握&#xff0c;即便成功入职&#xff0c;也往往难以长久。于是&#xff0c;不少程序员感叹&#xff1a;互联网的寒冬似乎又一次卷土重来&#xff0c;环境如此恶劣&…

短视频矩阵贴牌:打造品牌新势力的策略与实践

在数字化浪潮席卷全球的今天&#xff0c;短视频以其独特的魅力迅速崛起&#xff0c;成为连接用户与品牌的重要桥梁。企业为了快速抢占市场&#xff0c;提升品牌影响力&#xff0c;纷纷探索短视频矩阵贴牌这一新兴模式。本文将深入探讨短视频矩阵贴牌的概念、优势、实施流程及注…

视频生成Sora的全面解析:从AI绘画、ViT到ViViT、TECO、DiT、VDT、NaViT等

前言 真没想到&#xff0c;距离视频生成上一轮的集中爆发(详见《Sora之前的视频生成发展史&#xff1a;从Gen2、Emu Video到PixelDance、SVD、Pika 1.0》)才过去三个月&#xff0c;没想OpenAI一出手&#xff0c;该领域又直接变天了 自打2.16日OpenAI发布sora以来(其开发团队包…

简易记事本项目(基于Vue 3 + Element Plus + SSM 个人事件管理系统)

项目简介 点滴365是一个基于 Vue 3 Element Plus SSM 开发的个人事件管理系统,旨在帮助用户高效管理 个人日程 和 待办事项。系统支持日记撰写、待办事项管理、数据统计分析、图片上传、定时提醒、实时天气等功能,让用户可以更好地记录生活点滴、规划工作任务。 核心技术栈…

【C语言】头文件

所有学习过C语言的朋友都熟悉这样一段代码&#xff1a; #include <stdio.h>int main(int argc, char *argv[]) {return 0; }那么&#xff0c;你真的了解 <stdio.h> 吗&#xff1f; <stdio…

ChatGPT Search开放:实时多模态搜索新体验

点击访问 chatTools 免费体验GPT最新模型&#xff0c;包括o1推理模型、GPT4o、Claude、Gemini等模型&#xff01; ChatGPT Search&#xff1a;功能亮点解析 本次更新的ChatGPT Search带来了多项令人瞩目的功能&#xff0c;使其在搜索引擎市场中更具竞争力。 1. 高级语音模式&…

概率论得学习和整理31: 连续型随机变量的概率本质是求面积,均匀分布等

目录 1 连续性随机变量 2 连续性随机变量和 离散型随机变量&#xff0c;分布的区别 3 不要混淆概念 4 均匀分布的相关 4.1 定义 4.2 例子 1 连续性随机变量 连续性随机变量最大的特点&#xff0c;单个点上的概率0多了一个分布函数&#xff0c;因为从1维变2维了&#xff…

跟沐神学读论文-论文阅读管理

摘要 近期有读论文的需求&#xff0c;就需要去了解一下论文到底要怎么读&#xff0c;同一个系列之间的论文如何作整理和归纳&#xff0c;之前也有了解过市面上有成熟的论文阅读工具&#xff0c;但是对于学生党来讲没什么性价比&#xff0c;在B站上看到沐神有讲解他的思路Typor…

java_断点调试(debug)

按照如下配置好后&#xff0c;即可点击“F7”,进入相应的方法&#xff0c;查看源码 package com.hspedu.debug_;//debug对象创建的过程&#xff0c;加深对调试的理解 public class Debug01 {public static void main(String[] args) {//创建对象的流程//&#xff08;1&#xff…

c++数据结构算法复习基础--13--基数算法

基数排序 - 桶排序 时间复杂度 O(n*d) – d为数据的长度 每次比较一位&#xff08;个位、十位。。。&#xff09;&#xff0c;所以取值范围就为0-9。 根据该特点&#xff0c;设计桶的概念 – 0号桶、1号桶… 1、思想 1&#xff09;找出最长的数字&#xff0c;确定要处理的…

微信小程序TTS解决方案

微信小程序原生语音合成 API&#xff08;基础且简单&#xff09; 介绍&#xff1a;微信小程序提供了基础的语音合成能力。通过wx.createInnerAudioContext()等相关API&#xff0c;可以实现简单的语音播放功能。不过它主要是用于音频播放&#xff0c;对于完整的文本到语音&#…

matlab绘图时设置左、右坐标轴为不同颜色

目录 一、需求描述 二、实现方法 一、需求描述 当图中存在两条曲线&#xff0c;需要对两条曲线进行分别描述时&#xff0c;应设置左、右坐标轴为不同颜色&#xff0c;并设置刻度线&#xff0c;且坐标轴颜色需要和曲线颜色相同。 二、实现方法 1.1、可以实现&#xff1a; 1…

Vue3动态表单实现

实现方法&#xff1a;通过<component />标签动实现动态表单渲染 component标签&#xff1a; 在vue中 component 标签用于动态组件标签的渲染。它允许在同一个挂载点上条件渲染不同的组件&#xff0c;通过is属性可以渲染指定的属性 在上面的例子中&#xff0c;通过调用…

[C++]C++工具之对异常情况的处理(throw、catch、try)以及用命名空间避免同名冲突

一、C 异常处理&#x1f60a; 1.1 定义 C 中的异常处理用于应对程序运行中的异常情况&#xff08;如除零、数组越界等&#xff09;&#xff0c;通过 try-catch 机制捕获和处理错误&#xff0c;防止程序崩溃。 异常是程序运行时意外发生的事件&#xff0c;可以通过抛出&#xf…

游戏引擎学习第53天

仓库: https://gitee.com/mrxiao_com/2d_game 回顾 现在我们正进行游戏结构的重构&#xff0c;目的是为了更合理地安排游戏的组织方式&#xff0c;模拟玩家周围的实体。我们将这些实体分为两类&#xff1a;一类是当前正在屏幕上显示的实体&#xff0c;另一类是被映射到低频更…

【六足机器人】04上位机开发

图&#xff1a;QT界面效果图 一、主要功能介绍 1.1 登录界面 登录界面&#xff0c;用来判断是否账号密码输入正确&#xff0c;错误将会弹出消息框。 void first::on_enroll_clicked(){if(ui->account->text()"共创芯未来"&&ui->password->text…

RockyLinux9编译安装MySQL5.7

原文链接&#xff1a;RockyLinux9编译安装MySQL5.7 - Liu Zijians Blog | 刘子健的博客 本文最后更新于 2024年12月15日 使用源码编译安装MySQL5.7 1.下载 打开MySQL-Community-Server官方下载页面:https://downloads.mysql.com/archives/community/ 筛选出要下载的版本&…

什么是3DEXPERIENCE SOLIDWORKS,它有哪些角色和功能?

将业界领先的 SOLIDWORKS 3D CAD 解决方案连接到基于单一云端产品开发环境 3DEXPERIENCE 平台。您的团队、数据和流程全部连接到一个平台进行高效的协作工作&#xff0c;从而能快速的做出更好的决策。 目 录&#xff1a; ★ 1 什么是3DEXPERIENCE SOLIDWORKS ★ 2 3DEXPERIE…

OpenCVE:一款自动收集NVD、MITRE等多源知名漏洞库的开源工具,累计收录CVE 27万+

漏洞库在企业中扮演着至关重要的角色&#xff0c;不仅提升了企业的安全防护能力&#xff0c;还支持了安全决策、合规性要求的满足以及智能化管理的发展。前期博文《业界十大知名权威安全漏洞库介绍》介绍了主流漏洞库&#xff0c;今天给大家介绍一款集成了多款漏洞库的开源漏洞…