I.MX6ULL_Linux_驱动篇(51)linux 音频驱动

音频是我们最常用到的功能,音频也是 linux 和安卓的重点应用场合。 I.MX6ULL 带有 SAI接口,正点原子的 I.MX6ULLALPHA 开发板通过此接口外接了一个 WM8960 音频 DAC 芯片,本章我们就来学习一下如何使能 WM8960 驱动,并且通过 WM8960 芯片来完成音乐播放与录音。

音频接口简介

为何需要音频编解码芯片?

处理器要想“听到”外界的声音必须要把外界的声音转化为自己能够理解的“语言”,处理器能理解的就是 0 和 1,也就是二进制数据。 所以我们需要先把外界的声音转换为处理器能理解的 0 和 1,在信号处理领域,外界的声音是模拟信号,处理器能理解的是数字信号,因此这里就涉及到一个模拟信号转换为数字信号的过程,而完成这个功能的就是 ADC 芯片。同理,如果处理器要向外界传达自己的“心声”,也就是放音,那么就涉及到将处理器能理解的 0 和 1 转化为外界能理解的连续变化的声音, 这个过程就是将数字信号转化为模拟信号,而完成这个功能的是 DAC 芯片。

现在我们知道了,处理器如果既想“听到”外界的声音,又想向外界传达自己的“心声”,那么就需要同时用到 DAC 和 ADC 这两款芯片。那是不是买两颗 DAC 和 ADC 芯片就行了呢?
答案肯定是可以的,但是音频不单单是能出声、能听到就行。我们往往需要听到的声音动听、录进去的语音贴近真实、可以调节音效、 对声音能够进行一些处理(需要 DSP 单元)、拥有统一的标准接口,方便开发等等。将这些针对声音的各种要求全部叠加到 DAC 和 ADC 芯片上,那么就会得到一个专门用于音频的芯片,也就是音频编解码芯片,英文名字就是 Audio CODEC,所以我们在手机或者电脑的介绍中看到“CODEC”这个词语,一般说的都是音频编解码。既然音频 CODEC 的本质是 ADC 和 DAC,那么采样率和采样位数就是衡量一款音频CODEC 最重要的指标。比如常见音频采样率有 8K、 44.1K、 48K、 192K 甚至 384K 和 768K,采样位数常见的有 8 位、 16 位、 24 位、 32 位。采样率和采样位数越高,那么音频 CODEC 越能真实的还原声音,也就是大家说的 HIFI。因此大家会看到高端的音频播放器都会有很高的采样率和采样位数,同样的价格也会越高。当然了,实际的效果还与其他部分有关,采样率和采样位数只是其中重要的指标之一。

WM8960 简介

前面我们已经分析了为何需要音频编解码芯片,那是因为专用的音频编解码芯片提供了很多针对音频的特性。我们就以正点原子 ALPHA 开发板所使用的 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 整体框图如下图所示:

依次来看一下图中这四部分接口都是什么功能:
①、此部分是 WM8960 提供的输入接口,作为立体声音频输入源,一共提供了三路,分别为 LINPUT1/RINPUT1、 LINPUT2/RINPUT2、 LINPUT3/RINPUT3。麦克风或线路输入就连接到
此接口上,这部分是需要硬件工程师重点关心的,因为音频选择从哪一路进入需要在画 PCB 的时候就应该定好。
②、此部分是 WM8960 的输出接口,比如输出给耳机或喇叭, SPK_LP/SPK_LN 用于连接左声道的喇叭,支持 1W 的 8Ω喇叭。 SPK_RP/SPK_RN 用于连接右声道的喇叭,同样支持 1W
的 8Ω喇叭,最后就是 HP_L/HP_R,用于连接耳机。
③、此部分是数字音频接口,用于和主控制器连接,有 5 根线,用于主控制器和 WM8960之间进行数据“沟通”。主控制器向 WM8960 的 DAC 发送的数据, WM8960 的 ADC 向主控制
传递的数据都是通过此音频接口来完成的。这个接口非常重要,是我们驱动开发人员重点关注的,此接口支持 I2S 格式。此接口 5 根线的作用如下:
ADCDAT: ADC 数据输出引脚,采集到的音频数据转换为数字信号以后通过此引脚传输给主控制器。
ADCLRC: ADC 数据对齐时钟,也就是帧时钟(LRCK),用于切换左右声道数据, 此信号的频率就是采样率。此引脚可以配置为 GPIO 功能,配置为 GPIO 以后 ADC 就会使用 DACLRC
引脚作为帧时钟。
DACDAT: DAC 数据输入引脚,主控器通过此引脚将数字信号输入给 WM8960 的 DAC。
DACLRC: DAC 数据对齐时钟,功能和 ADCLRC 一样,都是帧时钟(LRCK),用于切换左右声道数据,此信号的频率等于采样率。
BCLK: 位时钟,用于同步。
MCLK: 主时钟, WM8960 工作的时候还需要一路主时钟,此时钟由 I.MX6ULL 提供,MCLK 频率等于采样率的 256 或 384 倍,因此大家在 WM8960 的数据手册里面常看到MCLK=256fs 或 MCLK=384fs。
④、此部分为控制接口,是一个标准的 I2C 接口, WM8960 要想工作必须对其进行配置,这个 I2C 接口就是用于配置 WM8960 的。

I2S 总线接口

I2S(Inter-IC Sound)总线有时候也写作 IIS, I2S 是飞利浦公司提出的一种用于数字音频设备之间进行音频数据传输的总线。和 I2C、 SPI 这些常见的通信协议一样, I2S 总线用于主控制器和音频 CODEC 芯片之间传输音频数据。因此,要想使用 I2S 协议, 主控制器和音频 CODEC 都得支持 I2S 协议, I.MX6ULL 的 SAI 外设就支持 I2S 协议, WM8960 同样也支持 I2S,所以本章实验就是使用 I2S 协议来完成的。 I2S 接口需要 3 根信号线(如果需要实现收和发,那么就要 4根信号线,收和发分别使用一根信号线):

SCK: 串行时钟信号,也叫做位时钟(BCLK),音频数据的每一位数据都对应一个 SCK,立体声都是双声道的,因此 SCK=2×采样率×采样位数。比如采样率为 44.1KHz、 16 位的立体声音频,那么 SCK=2× 44100× 16=1411200Hz=1.4112MHz。
WS: 字段(声道)选择信号,也叫做 LRCK,也叫做帧时钟,用于切换左右声道数据, WS 为“1”表示正在传输左声道的数据, WS 为“0”表示正在传输右声道的数据。 WS 的频率等于采样率,比如采样率为 44.1KHz 的音频, WS=44.1KHz。
SD: 串行数据信号,也就是我们实际的音频数据,如果要同时实现放音和录音,那么就需要 2 根数据线,比如 WM8960 的 ADCDAT 和 DACDAT,就是分别用于录音和放音。不管音频数据是多少位的,数据的最高位都是最先传输的。数据的最高位总是出现在一帧开始后(LRCK变化)的第 2 个 SCK 脉冲处。
另外,有时候为了使音频 CODEC 芯片与主控制器之间能够更好的同步,会引入另外一个叫做 MCLK 的信号,也叫做主时钟或系统时钟,一般是采样率的 256 倍或 384 倍。
下图就是一帧立体声音频时序图:

随着技术的发展,在统一的 I2S 接口下,出现了不同的数据格式,根据 DATA 数据相对于 LRCK 和 SCLK 位置的不同,出现了 Left Justified(左对齐)和 Right Justified(右对齐)两种格
式,这两种格式的时序图如下图所示:

I.MX6ULL SAI 简介

音频 CODEC 支持 I2S 协议,那么主控制器也必须支持 I2S 协议,大家如果学过STM32F4/F7/H7 的话应该知道 SAI 接口,因为在 STM32 中就是通过 SAI 接口来连接音频CODEC。 I.MX6ULL 也提供了一个叫做 SAI 的外设,全称为 Synchronous Audio Interface,翻译过来就是同步音频接口。I.MX6ULL 的 SAI 是一个全双工、支持帧同步的串行接口,支持 I2S、 AC97、 TDM 和音频
DSP, SAI 主要特性如下:
①、帧最大为 32 个字。
②、字大小可选择 8bit 或 32bit。
③、每个接收和发送通道拥有 32× 32bit 的 FIFO。
④、 FIFO 错误以后支持平滑重启。
I.MX6ULL 的 SAI 框图如下图所示:

图中右侧“SAI_TX”和“SAI_RX”开头的就是 SAI 外设提供给外部连接音频CODEC 的信号线,具体连接方法查看下面的原理图。

图中我们重点关注两个接口, SAI 和 I2C,我们依次来看一下这两个接口:
①、 SAI 接口一共用到了 6 根数据线,这 6 根数据线用于 I.MX6ULL 与 WM8960 之间的音频数据收发。
②、 WM8960 在使用的时候需要进行配置,配置接口为 I2C,连接到了 I.MX6ULL 的 I2C2上。

音频驱动使用

修改设备树

前面分析原理图的时候已经说过了, WM8960 与 I.MX6ULL 之间有两个通信接口: I2C 和 SAI,因此设备树中会涉及到 I2C 和 SAI 两个设备节点。其中 I2C 用于配置 WM8960, SAI 接口用于音频数据传输,我们依次来配置一下这两个接口。

1、 wm8960 i2c 接口设备树

首先配置一下 I2C 接口,根据原理图我们知道 WM8960 连接到了 I.MX6ULL 的 I2C2 接口上,因此在设备树中的“i2c2”节点下需要添加 wm8960 信息。如果去添加肯定是要看设备树的绑定手册,打开 Documentation/devicetree/bindings/sound/wm8960.txt,此文件仅仅用于描述如何在 I2C 节点下添加 WM8960 相关信息,此文档适用于所有的主控,不局限于 I.MX6ULL。
有 2 个必要的属性:
compatible:兼容属性,属性值要设置为“wlf,wm8960”。所以大家在 linux 内核里面全局搜索“wlf,wm8960”的话就会找到WM8960的I2C驱动文件,此文件为sound/soc/codecs/wm8960.c。
reg: 设置 WM8960 的 I2C 地址,在正点原子的 ALPHA 开发板中 WM8960 的 I2C 地址为0X1A。
还要几个其他的可选属性:
wlf,shared-lrclk: 这是一个 bool 类型的属性,如果添加了此属性, WM8960 的 R24 寄存器的 LRCM 位(bit2)就会置 1。当 LRCM 为 1 的时候只有当 ADC 和 DAC 全部关闭以后 ADCLRC
和 DACLRC 时钟才会关闭。
wlf,capless: 这也是一个 bool 类型的属性, 如果添加了此属性, OUT3 引脚将会使能,并且为了响应耳机插入响应事件, HP_L 和 HP_R 这两个引脚都会关闭。
绑定文档给出的参考节点内容如下所示:

codec: wm8960@1a {
    compatible = "wlf,wm8960";
    reg = <0x1a>;
    wlf,shared-lrclk;
};

根据 wm8960.txt 这份绑定文档我们就可以在任意一个主控的 I2C 节点下添加 wm8960 相关信息了, NXP 官方 I.MX6ULL EVK 开发板使用的也是 WM8960,因此在设备树中添加设备节
点这些工作 NXP 已经帮我们做了。打开 imx6ull-alientek-emmc.dts,找到名为“i2c2”的节点,此节点下都是连接到 I2C2 总线上的设备,其中就包括了 wm8960, wm8960 节点信息如下所示:

1 codec: wm8960@1a {
2     compatible = "wlf,wm8960";
3     reg = <0x1a>;
4     clocks = <&clks IMX6UL_CLK_SAI2>;
5     clock-names = "mclk";
6     wlf,shared-lrclk;
7 };

可以看出,dts中的内容基本和 wm8960.txt 这个绑定文档中的示例内容一致,只是多了第 4 和第 5 这两行,这两行用于描述时钟相关信息。第 4 行指定时钟源为 SAI2,第 5行指定时钟的名字为“mclk”。前面我们说过,为了更好的同步,一般都会额外提供一条 MCLK时钟。至此,关于 wm8960 的 I2C 配置接口设备树就已经添加好了。

2、 I.MX6ULL SAI 音频接口设备树

接下来就是 I.MX6ULL 的 SAI 音频接口设备树相关内容的修改了,同样的,先查阅一下相应的绑定文档: Documentation/devicetree/bindings/sound/fsl-sai.txt。和我们前面讲过的 IIC 接口、
ECSPI 等接口一样,在 imx6ull.dtsi 文件中会有关于 SAI 相关接口的描述,这部分是 NXP 原厂编写的,我们不需要做任何修改, SAI2 的设备子节点内容如下所示:

1 sai2: sai@0202c000 {
2     compatible = "fsl,imx6ul-sai",
3                  "fsl,imx6sx-sai";
4     reg = <0x0202c000 0x4000>;
5     interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
6     clocks = <&clks IMX6UL_CLK_SAI2_IPG>,
7              <&clks IMX6UL_CLK_DUMMY>,
8              <&clks IMX6UL_CLK_SAI2>,
9              <&clks 0>, <&clks 0>;
10     clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
11     dma-names = "rx", "tx";
12     dmas = <&sdma 37 24 0>, <&sdma 38 24 0>;
13     status = "disabled";
14 };

直接搜索 compatible 属性中的两个兼容值,那么你就会找到 I.MX6ULL 的 SAI 接口驱动文件,路径为 sound/soc/fsl/fsl_sai.c,此驱动文件不需要我们去研究,除非你在 NXP 上班,而你的工作恰好是给 NXP 的 I.MX 系列芯片编写 SAI 驱动的。从第 13 行可以看出, SAI2 默认是关闭的,因此我们需要将其打开,也就是设置 status 属性的值为“okay”,这个工作肯定是在具体板子对应的.dts 文件中完成的,其实就是向 sai2 节点里面追加或者修改一些属性值。打开 imx6ullalientek-emmc.dts 文件,找到如下内容:

1 &sai2 {
2     pinctrl-names = "default";
3     pinctrl-0 = <&pinctrl_sai2
4                 &pinctrl_sai2_hp_det_b>;
5     assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>,
6                       <&clks IMX6UL_CLK_SAI2>;
7     assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
8     assigned-clock-rates = <0>, <12288000>;
9     status = "okay";
10 };

dts中的内容是 NXP 针对自己的 I.MX6ULL EVK 开发板而添加的,主要是对 sai2 节点做了三个方面的修改: SAI2 接口的 pinctrl、相应的时钟、修改 status 为“okay”。我们重点来看一下 pinctrl 的设置,因为关系到 SAI2 接口的 IO 设置,从 pinctrl-0 属性可以看出这里一共有两组 IO: pinctrl_sai2 和 pinctrl_sai2_hp_det_b,这两组 IO 内容如下:

1 pinctrl_sai2: sai2grp {
2     fsl,pins = <
3         MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK 0x17088
4         MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC 0x17088
5         MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA 0x11088
6         MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA 0x11088
7         MX6UL_PAD_JTAG_TMS__SAI2_MCLK 0x17088
8     >;
9 };
10
11 pinctrl_sai2_hp_det_b: sai2_hp_det_grp {
12     fsl,pins = <
13         MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04 0x17059
14     >;
15 };

pinctrl_sai2 描述的是 SAI2 接口的 IO 配置,这个要根据自己板子的实际硬件情况修改,正点原子的 ALPHA 开发板上 SAI2 所使用的 IO 和 NXP 的 EVK 开发板一样,因此这里不需要做任何修改。 pinctrl_sai2_hp_det_b 描述的是耳机插入检测引脚, wm8960 支持耳机插入检测,这样当耳机插入以后就会通过耳机播放音乐,当耳机拔出来以后就会通过喇叭播放音乐。对于正点原子的 ALPHA 开发板, SAI 部分的设备树信息不需要做任何修改,直接使用 NXP官方写好的即可。

I.MX6ULL sound 节点

最后我们需要在根节点“/”下创建一个名为“sound”的子节点,笔者并没有在 linux 内核中找到此节点的绑定信息。只有一份在 I.MX 系列芯片中使用 WM8962 芯片的 sound 节点绑定文档,路径为: Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt。虽然不是 wm8960的绑定文档,但是我们也可以参考 imx-audio-wm8962.txt。 NXP 官方已经针对 EVK 开发板编写
了 sound 节点,我们可以在此基础上针对我们所使用的平台来修改出对应的 sound 节点,修改完成以后的 sound 节点内容如下所示:

1 sound {
2     compatible = "fsl,imx6ul-evk-wm8960",
3                  "fsl,imx-audio-wm8960";
4     model = "wm8960-audio";
5     cpu-dai = <&sai2>;
6     audio-codec = <&codec>;
7     asrc-controller = <&asrc>;
8     codec-master;
9     gpr = <&gpr 4 0x100000 0x100000>;
10 /*
11 * hp-det = <hp-det-pin hp-det-polarity>;
12 * hp-det-pin: JD1 JD2 or JD3
13 * hp-det-polarity = 0: hp detect high for headphone
14 * hp-det-polarity = 1: hp detect high for speaker
15 */
16     hp-det = <3 0>;
17 /*hp-det-gpios = <&gpio5 4 0>;
18     mic-det-gpios = <&gpio5 4 0>;*/
19     audio-routing =
20         "Headphone Jack", "HP_L",
21         "Headphone Jack", "HP_R",
22         "Ext Spk", "SPK_LP",
23         "Ext Spk", "SPK_LN",
24         "Ext Spk", "SPK_RP",
25         "Ext Spk", "SPK_RN",
26         "LINPUT2", "Mic Jack",
27         "LINPUT3", "Mic Jack",
28         "RINPUT1", "Main MIC",
29         "RINPUT2", "Main MIC",
30         "Mic Jack", "MICB",
31         "Main MIC", "MICB",
32         "CPU-Playback", "ASRC-Playback",
33         "Playback", "CPU-Playback",
34         "ASRC-Capture", "CPU-Capture",
35         "CPU-Capture", "Capture";
36 };

简单看一下 sound 节点中几个重要的属性:
compatible: 非常重要,用于匹配相应的驱动文件,有两个属性值,在整个 linux 内核源码中搜索这两个属性值即可找到对应的驱动文件,这里找到的驱动文件为:sound/soc/fsl/imxwm8960.c。
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(源)。

使能内核的 WM8960 驱动

设备树配置完成以后就可以使能内核自带的 WM8960 驱动了,直接通过图形化界面配置即可,输入如下命令打开 linux 内核的图形化配置界面:

make menuconfig

1、取消 ALSA 模拟 OSS API

首先取消 ALSA 模拟 OSS,进入如下路径:

2、使能 I.MX6ULL 的 WM8960 驱动

接下来使能 WM8960 驱动,进入如下路径:

-> Device Drivers
-> Sound card support (SOUND [=y])
-> Advanced Linux Sound Architecture (SND [=y])
-> ALSA for SoC audio support (SND_SOC [=y])
-> SoC Audio for Freescale CPUs
-> <*> Asynchronous Sample Rate Converter (ASRC) module support //选中
-> <*> SoC Audio support for i.MX boards with wm8960 //选中

驱动使能以后重新编译 linux 内核,编译完成以后使用新的 zImage 和.dtb 文件启动,如果设备树和驱动都使能的话系统启动过程中就会如图所示的 log 信息:

系统最终启动以后会打印出 ALSA 设备列表,现在的音频 CODEC 驱动基本都是 ALSA 架构的,本章的 WM8960 驱动也是根据 ALSA 架构编写的。因此在 ALSA 设备列表中就会找到
“wm8960-audio”这个声卡,如图所示:

进入系统以后查看一下/dev/snd 目录,看看有没有如图所示文件:

图中的这些文件就是ALSA音频驱动框架对应的设备文件,这些文件的作用如下:
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 这两个东西。 

alsa-lib 和 alsa-utils 移植

首选下载alsa-lib和alsa-utils 源码 ,下载地址为:http://www.alsaproject.org/main/index.php/Main_Page。当前最新版本为 1.2.2, 如图所示:

注意 alsa-lib 编译过程中会生成一些配置文件,而这些配置信息的路径都是绝对路径,因此为了保证 ubuntu 和开发板根文件系统中的路径一致!我们需要在 ubuntu 和开发板中各创建一
个路径和名字完全一样的目录,这里我们都创建一个/usr/share/arm-alsa 目录。

这样 ubuntu 和开发板根文件系统都有一个“/usr/share/arm-alsa”目录,我们交叉编译的时候就不怕存在引用绝对路径了,因为 ubuntu 和开发板中的配置文件路径都是一模一样的。
由于 alsa-utils 要用到 alsa-lib 库,因此要先编译 alsa-lib 库。 alsa-lib 就是 ALSA 相关库文件,应用程序通过调用 ALSA 库来对 ALSA 框架下的声卡进行操作。先创建一个名为“alsa-lib”
的目录用来保存 alsa-lib 的编译结果,然后将 alsa-lib-1.2.2.tar.bz2 拷贝到 ubuntu 中并解压。

解压完成以后就会得到一个名为“alsa-lib-1.2.2”的文件夹,这个就是 alsa-lib 的源码。进入 alsa-lib-1.2.2 目录,然后配置并编译,命令如下:

cd alsa-lib-1.2.2/ //进入 alsa-lib 源码目录
./configure --host=arm-linux-gnueabihf --prefix=/home/xxx/linux/IMX6ULL/tool/alsalib --with-configdir=/usr/share/arm-alsa //配置

注意, “--with-configdir”用于设置 alsa-lib 编译出来的配置文件存放位置,这里设置为前 面创建的“/usr/share/arm-alsa”目录。 配置完成以后就可以编译了,命令如下:

make //编译
sudo make install //安装

可能会出现如图所示的错误提示:

图中提示 libatopology.la 编译失败, 这是因为 sudo 会切换到 root 用户下,但是此时 root 用户下的环境变量中没有交叉编译器路径,因此会提示找不到“arm-linux-gnueabihf-gcc”,从而导致 libatopology.la 编译失败。解决方法就是先切换到 root 用户,重新执行一下/etc/profile文件,然后直接 make install 即可,命令如下:

sudo -s //切换到 root 用户
source /etc/profile //执行/etc/profile
make install //安装,此时已经工作在 root 下,因此不需要加“sudo”
su xxx    //编译完成以后回原来的用户

编译完成以后前面创建的“alsa-lib”目录就会保存相应的编译结果,如图所示:

ubuntu 中/usr/share/arm-alsa 目录下的内容如图所示:

将alsa-lib 目录下的所有文件拷贝到开发板根文件系统的/usr/lib 目录下,将/usr/share/arm-alsa 目录下的所有文件拷贝到开发板的/usr/share/arm-alsa 目录下。

alsa-utils 移植

alsa-utils 是 ALSA 的一些小工具集合,我们可以通过这些小工具测试我们的声卡。将 alsautils-1.2.2.tar.bz2 复制到 ubuntu 中并解压,命令如下:

tar -vxjf alsa-utils-1.2.2.tar.bz2 //解压

解压成功以后会得到一个名为“alsa-utils-1.2.2”的文件夹,此文件夹就是 alsa-utils 源码。重新创建一个名为“alsa-utils”的目录用于存放 alsa-utils-1.2.2 的编译结果。按照如下命令编译alsa-utils:

cd alsa-utils-1.2.2/ //进入
./configure --host=arm-linux-gnueabihf --prefix=/home/xxx/linux/IMX6ULL/tool/alsautils --with-alsa-inc-prefix=/home/xxx/linux/IMX6ULL/tool/alsa-lib/include/ --with-alsaprefix=/home/xxx/linux/IMX6ULL/tool/alsa-lib/lib/ --disable-alsamixer --disable-xmlto
make //编译
sudo make install

编译完成以后就会在前面创建的“alsa-utils”目录下生成 bin、 sbin 和 share 三个文件夹。将图 bin、 sbin 和 share 这三个目录中的所有文件分别拷贝到开发板根目录下的/bin、 /sbin 和/usr/share/alsa 目录下。打开开发板根文件系统中的/etc/profile 文件,在里面加入如下所示内容:

export ALSA_CONFIG_PATH=/usr/share/arm-alsa/alsa.conf

ALSA_CONFIG_PATH 用于指定 alsa 的配置文件,这个配置文件是 alsa-lib 编译出来的。

测试

amixer 使用

声卡相关选型默认都是关闭的,比如耳机和喇叭的左右声道输出等。因此我们在使用之前一定要先设置好声卡, alsa-utils 自带了 amixer 这个声卡设置工具。输入如下命令即可查看 amixer
的帮助信息:

amixer --help //查看 amixer 帮助信息

从图中可以看出, amixer 软件命令分为两组, scontrols、 scontents、 sset 和 sget 为一组。 controls、 contents、 cset 和 cget 为另一组。这两组的基本功能都是一样的,只不过“s”开头的是 simple(简单)组,这一组命令是简化版,本教程最终使用“s”开头的命令设置声卡,因为少输入很多字符。

我们要先看一下都有哪些设置项,先来看一下 scontrols 对应的设置项,输入如下命令:

amixer scontrols //查看所有设置项

再来看一下 controls 对应的设置项,输入如下命令:

amixer controls //查看所有设置项

由于篇幅原因只列出了一部分设置项,整体设置项目还是比较多的,很多设置项目我们都不知道是啥意思,毕竟不是从事音频专业的。这里我们只关注一些最常用的设置即可,比如设置耳机和喇叭音量、设置左右声道音量、设置输入音量等等。

不同的设置项对应的设置值类型不同,先查看一下scontents对应的设置值,输入如下命令:

从图中可以看出“Headphone”项目就是设置耳机音量的,音量范围为 0-127,当前音量为 0。有些设置项是 bool 类型,只有 on 和 off 两种状态。关于 controls 对应的设置值大家自行输入“amixer controls”命令查看即可。知道了设置项和设置值,那么设置声卡就很简单了,直接使用下面命令即可:

amixer sset 设置项目 设置值
amixer cset 设置项目 设置值

如果要读取当前声卡某项设置值的话使用如下命令:

amixer sget 设置项目
amixer cget 设置项目
音乐播放测试

第一次使用声卡之前一定要先使用 amixer 设置声卡,打开耳机和喇叭,并且设置喇叭和耳机音量,输入如下命令:

amixer sset Headphone 100,100
amixer sset Speaker 120,120
amixer sset 'Right Output Mixer PCM' on
amixer sset 'Left Output Mixer PCM' on

声卡设置好以后就可以使用 aplay 软件播放 wav 格式的音乐测试一下, aplay 也是 alsa-utils提供的。可以在开发板根文件系统下创建一个名为“music”的目录来存放音频文件,然后找一首 wav 格式的音乐放到开发板根文件系统中,然后输入如下命令播放:

aplay test.wav //播放歌曲

如果一切设置正常的话就会开始播放音乐,因为 ALPHA 开发板支持喇叭和耳机自动切换,因此如果不插耳机的话默认从喇叭播放音乐。插上耳机以后喇叭就会停止播放音乐,改为耳机播放音乐。ALPHA 开发板上有一个麦克风,我们可以通过麦克风(MIC)来完成录音测试。

录音测试

同样的,第一次使用声卡录音之前要先使用 amixer 设置一下声卡,这里为了方便,我们在开发板根文件系统的/music 目录下创建一个名为“mic_in_config.sh”的 shell 脚本,然后在里面输入声卡的设置命令。 mic_in_config.sh 脚本内容如下所示:

1 #!/bin/sh
2
3 #设置捕获的音量
4 amixer cset name='Capture Volume' 90,90
5 
6 #PCM
7 amixer sset 'PCM Playback' on
8 amixer sset 'Playback' 256
9 amixer sset 'Right Output Mixer PCM' on
10 amixer sset 'Left Output Mixer PCM' on
11
12 #ADC PCM
13 amixer sset 'ADC PCM' 200
14
15 #耳机/喇叭(扬声器)设置播放音量,直流/交流
16 #Turn on Headphone
17 amixer sset 'Headphone Playback ZC' on
18 #Set the volume of your headphones(98% volume, 127 is the MaxVolume)
19 amixer sset Headphone 125,125
20 #Turn on the speaker
21 amixer sset 'Speaker Playback ZC' on
22 #Set the volume of your Speaker(98% volume, 127 is the MaxVolume)
23 amixer sset Speaker 125,125
24 #Set the volume of your Speaker AC(80% volume, 100 is the MaxVolume)
25 amixer sset 'Speaker AC' 4
26 #Set the volume of your Speaker AC(80% volume, 5 is the MaxVolume)
27 amixer sset 'Speaker DC' 4
28
29 #音频输入,左声道管理
30 #Turn on Left Input Mixer Boost
31 amixer sset 'Left Input Mixer Boost' off
32 amixer sset 'Left Boost Mixer LINPUT1' off
33 amixer sset 'Left Input Boost Mixer LINPUT1' 0
34 amixer sset 'Left Boost Mixer LINPUT2' off
35 amixer sset 'Left Input Boost Mixer LINPUT2' 0
36 #Turn off Left Boost Mixer LINPUT3
37 amixer sset 'Left Boost Mixer LINPUT3' off
38 amixer sset 'Left Input Boost Mixer LINPUT3' 0
39
40 #音频输入,右声道管理,全部关闭
41 #Turn on Right Input Mixer Boost
42 amixer sset 'Right Input Mixer Boost' on
43 amixer sset 'Right Boost Mixer RINPUT1' off
44 amixer sset 'Right Input Boost Mixer RINPUT2' 0
45 amixer sset 'Right Boost Mixer RINPUT2' on
46 amixer sset 'Right Input Boost Mixer RINPUT2' 127
47 amixer sset 'Right Boost Mixer RINPUT3' off
48 amixer sset 'Right Input Boost Mixer RINPUT3' 0

给予 mic_in_config.sh 可执行权限并运行,命令如下:

chmod 777 mic_in_config.sh //给予可执行权限
./mic_in_config.sh //运行

使用 arecord 来录制一段 10 秒的音频, arecord 也是 alsa-utils 编译出来的,输入如下命令:

arecord -f cd -d 10 record.wav

-f 是设置录音质量,“-f cd”表示录音质量为 cd 级别。 -d 是指定录音时间,单位是 s,这条指令就是录制一段 cd 级别 10s 的 wav 音频,音频名字为 record.wav。录制的时候大家就可以对着开发板上的 MIC 说话,直到录制完成。录制完成以后使用 aplay 播放刚刚录制的 record.wav 音频, 大家会发现只有左声道有声音,右声道没有任何声音,这是因为 ALPHA 开发板的 MIC 只接了左声道,因此录出来的音频只有左声道有数据。

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

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

相关文章

【MCAL】TC397+EB-tresos之MCU配置实战 - 芯片时钟

本篇文章介绍了在TC397平台使用EB-treso对MCU驱动模块进行配置的实战过程&#xff0c;主要介绍了后续基本每个外设模块都要涉及的芯片时钟部分&#xff0c;帮助读者了解TC397芯片的时钟树结构&#xff0c;在后续计算配置不同外设模块诸如通信速率&#xff0c;定时器周期等&…

自定义注解结合Hutool对SpringBoot接口返回数据进行脱敏

首先说到脱敏问题,我相信在座的很多人都需要处理这样的场景,比如前端页面显示的身份证号、地址等敏感信息都需要脱敏处理,而hutool就有这样的一个工具来辅助我们完成对某些字段属性信息的脱敏,hutool没有现成的实现方式,只是借助这个工具帮助我们来具体实现 前言 我们在…

AIGC开发:调用openai的API接口

简介 开始进行最简单的使用&#xff1a;通过API调用openai的模型能力 OpenAI的能力如下图&#xff1a; 文本生成模型 OpenAI 的文本生成模型&#xff08;通常称为生成式预训练 Transformer 或大型语言模型&#xff09;经过训练可以理解自然语言、代码和图像。这些模型提供文…

Bluetooth Mesh 入门学习干货,参考Nordic资料(更新中)

蓝牙网状网络&#xff08;Bluetooth mesh&#xff09;概念 概述 蓝牙Mesh Profile | Bluetooth Technology Website规范&#xff08;Mesh v1.1 后改名Mesh ProtocolMesh Protocol | Bluetooth Technology WebsiteMesh Protocol&#xff09;是由蓝牙技术联盟(Bluetooth SIG)开…

电影《海王2》观后感

上周看了电影《海王2》&#xff0c;整体特效和打斗还是非常不错的&#xff0c;自己在写文章的时候&#xff0c;看完电影已经一周了&#xff0c;相当于是叙事自我在描述这段经历。 &#xff08;1&#xff09;体验自我VS叙事自我 首先简单说明下“体验自我”和“叙事自我”&…

查看ios 应用程序性能

目录 摘要 前言 性能概括 CPU内存监控 内存监控 磁盘监控 网络监控 GPU fps 摘要 本篇博文将介绍一款重量级性能测试工具——克魔助手&#xff0c;针对iOS应用程序的性能监控进行详细介绍。通过克魔助手&#xff0c;开发者可以方便地查看应用程序的CPU、内存、GPU性能…

用OpenDataLab下载PASCAL VOC 2007等公开数据集

OpenDataLab OpenDataLab 公开数据集平台&#xff0c;集海量优质的多模态数据集资源、数据集智能检索、数据可视化展示、数据在线预览、下载优化、标准化管理等功能于一体&#xff0c;力争将平台打造成企业、高校、科研机构等的AI 模型训练的必备利器&#xff0c;帮大家解决数…

【Hive_04】分区分桶表以及文件格式

1、分区表1.1 分区表基本语法&#xff08;1&#xff09;创建分区表&#xff08;2&#xff09;分区表读写数据&#xff08;3&#xff09;分区表基本操作 1.2 二级分区1.3 动态分区 2、分桶表2.1 分桶表的基本语法2.2 分桶排序表 3、文件格式与压缩3.1 Hadoop压缩概述3.2 Hive文件…

前端的 js

js 点击按钮修改文字 <!DOCTYPE html> <html> <head></head><body><h2>Head 中的 JavaScript</h2><p id"demo">一个段落。</p><button type"button" onclick"myFunction()">试一…

全新研发体系助力产品落地 传音控股成科技出海代表

一直以来&#xff0c;手机都被认为是所有新技术的最佳应用载体&#xff0c;尤其是在数字化、智能化时代&#xff0c;技术创新能力决定着手机厂商的生存与发展。 作为全球新兴市场手机行业的中坚力量之一&#xff0c;传音控股始终坚持以技术创新为驱动&#xff0c;围绕用户需求…

零基础学Java第二天

复习回顾&#xff1a; 1.dos命令 dir 显示当前文件夹下面的所有的文件和文件夹 cd 切换目录的 mkdir 创建文件夹的 rd 删除文件夹的 del 删除文件 D: 切换盘符 cls 清屏 2.书写Java代码换行打印《静夜诗》这首古诗 class Demo1 { …

十二:爬虫-Scrapy框架(上)

一&#xff1a;Scrapy介绍 1.Scrapy是什么&#xff1f; Scrapy 是用 Python 实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架(异步爬虫框架) 通常我们可以很简单的通过 Scrapy 框架实现一个爬虫&#xff0c;抓取指定网站的内容或图片 Scrapy使用了Twisted异步网…

PayPal账户被封是因为什么?如何解决?

Paypal作为跨境出海玩家最常用的付款工具之一&#xff0c;同时也是最容易出现冻结封号现象。保障PP账号安全非常重要&#xff0c;只有支付渠道安全&#xff0c;才不会“白费力气”&#xff0c;那么最重要的就是要了解它的封号原因以做好规避。 一、Paypal账号被封原因 1、账号…

逻辑卷学习

磁盘分区的缺点 1.无法扩容 2.必须使用的空间 3.没有备份: 一、逻辑卷的定义 LVM 是 Logical Volume Manager 的简称&#xff0c;译为中文就是逻辑卷管理。它是 Linux 下对硬盘分区的一种管理机制。LVM 适合于管理大存储设备&#xff0c;并允许用户动态调整文件系统的大小…

Mybatis行为配置之Ⅲ—其他行为配置项说明

专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 再谈动态SQL Mybatis配置入门 Mybatis行为配置之Ⅰ—缓存 Mybatis行为配置…

【数据结构和算法】---二叉树(2)--堆的实现和应用

目录 一、堆的概念及结构二、堆结构的实现2.1堆向下调整算法2.2堆向上调整算法2.3删除堆顶元素2.4插入元素2.5其他函数接口 三、堆结构的应用3.1堆排序3.2Top-k问题 四、堆概念及结构相关题目 一、堆的概念及结构 如果有一个数字集合&#xff0c;并把它的所有元素按完全二叉树…

水库大坝安全监测设计与施工经验

随着我国的科技水平不断上升&#xff0c;带动了我国的水电建设向更高层次发展。目前&#xff0c;我国的水电站大坝已有上百座&#xff0c;并且大坝安全检测仪器质量与先进技术不断更新发展&#xff0c;如今水电站大坝数据信息采集与观测资料分析&#xff0c;能够有效提高水库大…

C语言编程入门 – 编写第一个Hello, world程序

C语言编程入门 – 编写第一个Hello, world程序 C Programming Entry - Write the first application called “Hello, world!” By JacksonML C语言编程很容易&#xff01; 本文开始&#xff0c;将带领你走过C语言编程之旅&#xff0c;通过实例使你对她颇感兴趣&#xff0c;一…

openGauss学习笔记-176 openGauss 数据库运维-实例主备切换

文章目录 openGauss学习笔记-176 openGauss 数据库运维-实例主备切换176.1 操作场景176.2 操作步骤176.3 示例176.4 错误排查176.5 异常处理 openGauss学习笔记-176 openGauss 数据库运维-实例主备切换 176.1 操作场景 openGauss在运行过程中&#xff0c;数据库管理员可能需要…

mongodb聚合_删除_可视化工具

3.5 MongoDB中limit和skip MongoDB Limit() 方法 如果你需要在MongoDB中读取指定数量的数据记录&#xff0c;可以使用MongoDB的Limit方法&#xff0c;limit()方法接受一个数字参数&#xff0c;该参数指定从MongoDB中读取的记录条数。limit()方法基本语法如下所示&#xff1a;…