音频驱动
音频接口
首先需要音频解码芯片, 要把外界的声音转换为0和1, 由模拟电路采集到之后传递给处理器, 就是音频的编解码器, 还有把数字信号转换为模拟信号就是声卡
ADC录音, DAC放音, 声卡就是对两者进行优化英文为”CODEC”, 采样率就是HIFI,
常见音频采样率有8K、44.1K、48K、192K甚至384K和768K, 采样位数常见的有8位、16位、24位、32位
大多是使用软件解码, 把音频文件软件解码为数字信号, 之后通过声卡进行转换为模拟信号
WM8960音频解码芯片
低功耗, 高质量, 双声道, 可以驱动1W喇叭, 集成三个立体声输入, 有一个完整的麦克风, , 24位最高48K采样
-
立体声音频输入源,一共提供了三路,分别为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之间进行数据“沟通”,
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倍
- 标准的I2C接口,WM8960要想工作必须对其进行配置,这个I2C接口就是用于配置WM8960的
IIS接口
主要用于音频的传输
还有采集的原始的音频数据格式就是PCM格式等
IIS用于主控制器和音频芯片之间传递音频信息, I2S接口需要3根信号线(如果需要实现收和发,那么就要4根信号线,收和发分别使用一根信号线)
- SCK:串行时钟信号,也叫做位时钟(BCLK)
- WS:字段(声道)选择信号,也叫做LRCK,也叫做帧时钟,用于切换左右声道数据, “1”表示正在传输左声道的数据,WS为“0”表示正在传输右声道的数据。WS的频率等于采样率
- SD:串行数据信号,也就是我们实际的音频数据,如果要同时实现放音和录音,那么就需要2根数据线,比如WM8960的ADCDAT和DACDAT,就是分别用于录音和放音。不管音频数据是多少位的,数据的最高位都是最先传输的
- 有时候为了使音频CODEC芯片与主控制器之间能够更好的同步,会引入另外一个叫做MCLK的信号,也叫做主时钟或系统时钟,一般是采样率的256倍或384倍
根据DATA数据相对于LRCK和SCLK位置的不同,出现了LeftJustified(左对齐)和RightJustified(右对齐)两种格式
SAI简介
I.MX6ULL也提供了一个叫做SAI的外设, 就是同步音频接口
I.MX6ULL的SAI是一个全双工、支持帧同步的串行接口,支持I2S、AC97、TDM和音频DSP,SAI
音频使能
需要一个WM8960驱动框架, IIC接口, 用来配置WM8960
需要一个SOC端SAI驱动文件
需要一个驱动文件, WM8960和I.MX6ull连接起来
ALSA音频驱动框架
Linux的默认音频驱动框架
用户空间: alsa-lib, 使用这个库进行音频处理
针对于嵌入式处理器推出了ASoC, 针对移动设备, 建立在ALSA框架之上, 实际使用的就是这个
只要分为三部分, SOC, Codec, 板载硬件
SOC: 具体的SOC音频接口驱动, 比如SAI, 都是半导体厂商编写的
Codec: 具体的芯片, 比如WM8960驱动, IIC驱动, Codec芯片厂商写了
板载硬件: 将具体的SOC和具体的Codec结合的, 与具体的硬件框架相关
实现
配置wm8960的接口设备树
- 驱动文件在sound/soc/codecs文件中
codec: wm8960@1a {
compatible = "wlf,wm8960";
reg = <0x1a>;
clocks = <&clks IMX6UL_CLK_SAI2>;
clock-names = "mclk";
wlf,shared-lrclk;
};
- SOC就是6ULL的驱动, 驱动文件fsl_sai.c文件
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";
};
- sound节点, 驱动文件imx-wm8960.c
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>;
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";
};
cpu-dai: 数字音频接口
audio-codec: 对应的音频解码芯片
model:最终用户看到的此声卡名字,这里设置为“wm8960-audio”
audio-routing:音频器件一系列的连接设置,每个条目都是一对字符串,第一个字符串是连接的sink,第二个是连接的source(源)
驱动使能
图形界面, 取消ALSA模拟OSS
Device dirver->Sound card support–> <*> Advanced Linux Sound Architecture
之后使能对应的驱动
Device dirver->Sound card support–> <*> Advanced Linux Sound Architecture –><*> ALSA for SoC audio support —> SoC Audio for Freescale CPUs —>< > SoC Audio support for i.MX boards with wm8960
启动之后显示
ALSA device list:
#0: wm8960-audio
在文件/dev/snd文件夹
/dev/snd # ls
controlC0 pcmC0D0c pcmC0D0p pcmC0D1c pcmC0D1p timer
ontrolC0:用于声卡控制,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, 前面的是库文件, 后面的是测试文件
库文件移植
创建文件夹/usr/share/arm-alsa, 开发板和主机都需要
cd alsa-lib-1.2.2///进入alsa-lib源码目录
jiao@jiao-virtual-machine:~/linux/tool/alsa-lib$ ./configure --host=arm-linux-gnueabihf --prefix=/home/jiao/linux/tool/alsa-lib --with-configdir=/usr/share/arm-alsa
make//编译
sudo makeinstall//安装
失败的话使用sudo用户执行/etc/profile
把得到的lib文件放到lib文件夹
把之前创建的文件夹中的文件放到对应的目录中
软件移植
cd alsa-utils-1.2.2///进入
./configure --host=arm-linux-gnueabihf --prefix=/home/zuozhongkai/linux/IMX6ULL/tool/alsa-utils --with-alsa-inc-prefix=/home/zuozhongkai/linux/IMX6ULL/tool/alsa-lib/include/ --with-alsa-prefix=/home/zuozhongkai/linux/IMX6ULL/tool/alsa-lib/lib/ --disable-alsamixer --disable-xmlto
make//编译
sudo make instal
cd alsa-utilssudo cp bin/* /home/zuozhongkai/linux/nfs/rootfs/bin/ -rfasudo cp sbin/* /home/zuozhongkai/linux/nfs/rootfs/sbin/ -rfasudo cp share/* /home/zuozhongkai/linux/nfs/rootfs/usr/share/ -rfa
/etc/profile文件
export ALSA_CONFIG_PATH=/usr/share/arm-alsa/alsa.conf
使用
aplay可以播放wav模式的音频
不作任何配置没有效果, 产生错误
aplay: pcm_write:2061: write error: Interrupted system call
声卡默认都是关闭的
使用软件amixer配置
amixer scontents
: 具体的调试
amixer sset Headphone 100,100
amixer sset Speaker 120,120
amixer sset 'Right Output Mixer PCM' on
amixer sset 'Left Output Mixer PCM' on
- 录音测试
使用软件arecord -f cd -d 10 record.wav
-f是设置录音质量,“-fcd”表示录音质量为cd级别。-d是指定录音时间,单位是s,这条指令就是录制一段cd级别10s的wav音频,音频名字为record.wav。
麦克风连接的是左声道, 右声道是杂音, 喇叭连接的时候右声道
解决方法: 修改寄存器
wm8960.c文件
{ 0x16, 0x00c3 },
/*{ 0x17, 0x01c0 },*/
{ 0x17, 0x01c4 },
开机自动配置
声卡设置的保存通过alsactl工具来完成, 将声卡配置文件保存在/var/lib/alsa目录下
使用命令alsactl -f /var/lib/alsa/my_asound.state store
使用alsactl -f /var/lib/alsa/my_asound.state restore
使用文件