1)实验平台:正点原子ATK-DLRK3568开发板
2)平台购买地址:https://detail.tmall.com/item.htm?id=731866264428
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban
第四十七章 音频驱动实验
音频是我们最常用到的功能,音频也是 linux 和安卓的重点应用场合。RK3568 带有I2S接口,正点原子的ATK-DLRK3568开发板核心板上通过此接口外接了一个 RK809电源管理芯片,内置音频。本章我们就来学习一下如何使能RK809音频驱动,并且通过 RK809 芯片来完成音乐播放与录音。
47.1 音频接口简介
47.1.1 为何需要音频编解码芯片?
处理器要想“听到”外界的声音必须要把外界的声音转化为自己能够理解的“语言”,处理
器能理解的就是 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。因此大家会看到高端的音频播放器都会有很高的采样率和采样位数,同样的价格也会越高。当然了,实际的效果还与其他部分有关,采样率和采样位数只是其中重要的指标之一。
47.1.2 RK809 Codec简介
RK809集成了高性能24位ADC和高性能24位DAC。录音路径由MIC_PGA和音频ADC组成。DAC将数字信号转换为模拟信号,ab类驱动器采用实地结构,用于耳机应用,THD非常低(-90dB @1KHz@-3dBFS源)。同时,集成了用于扬声器应用的d类驱动程序。扬声器和耳机可以同时使用。集成I2S接口,与处理器通信。
图47.1.2.1 RK809音频系统框图
47.1.3 I2S 总线接口
I2S(Inter-IC Sound)总线有时候也写作 IIS,I2S 是飞利浦公司提出的一种用于数字音频设备之间进行音频数据传输的总线。和 I2C、SPI 这些常见的通信协议一样,I2S 总线用于主控制器和音频 CODEC 芯片之间传输音频数据。因此,要想使用 I2S 协议,主控制器和音频 CODEC 都得支持 I2S 协议,RK3568支持 I2S 协议,RK809同样也支持 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 根数据线,比如 RK809的 SDI和 SDO,就是分别用于录音和放音。不管音频数据是多少位的,数据的最高位都是最先传输的。数据的最高位总是出现在一帧开始后(LRCK变化)的第 2 个 SCK 脉冲处。另外,有时候为了使音频 CODEC 芯片与主控制器之间能够更好的同步,会引入另外一个叫做 MCLK 的信号,也叫做主时钟或系统时钟,一般是采样率的 256 倍或 384 倍。图 47.1.3.1 就是一帧立体声音频时序图:
图47.1.3.1 I2S时序图
图47.1.3.2就是笔者采用逻辑分析仪抓取到的一帧真实的音频时序图:
图47.1.3.2中通道0是LRCK时钟,通道1为BCLK,通道2是DACDATA,通道3是MCLK。随着技术的发展,在统一的I2S接口下,出现了不同的数据格式,根据DATA数据相对于LRCK和SCLK位置的不同,出现了Left Justified(左对齐)和Right Justified(右对齐)两种格式,这两种格式的时序图如图47.1.3.3所示:
图47.1.3.3 I2S左对齐和右对齐数据格式
47.1.4 RK3568 I2S接口介绍
系统中嵌入了一个I2S/PCM/TDM控制器和两个I2S/PCM控制器。这四个控制器分别命名为i2S0、I2S1和I2S2/ I2S3。I2S0连接hdmi。I2S1支持I2S、PCM和TDM模式,I2S2和I2S3支持I2S和TDM模式PCM模式立体声音频输出和输入。除非单独说明,以下所有特性均适用于i2S0、I2S1、I2S2和I2S3。
I2S 控制器特性
支持 8声道 I2S 协议:standard, left justified, right justified
支持 stereo PCM 协议:early, late 1, late 2, late 3
支持 master/slave 模式,模式同时应用于 TX/RX 逻辑
支持 8k ~ 192k 采样率,384k 采样率
支持 16 ~ 32 bits 位宽
支持 MSB/LSB 模式
支持 时钟相位调整
支持 时钟补偿
I2S-TDM 控制器特性
除了支持 I2S 控制器的功能之外,I2S-TDM 控制器新增支持如下功能:
支持 8 slots TDM PCM 协议:normal, left shift mode[0~3]
支持 8 slots TDM I2S 协议:normal, left justified, right justified
支持 slot 位宽可配:16 ~ 32 bits
支持 data line 全映射,可重映射 data line 与 path 的关系
支持 TX/RX 异步模式,独立的时钟,可支持独立的采样率,位宽,协议
支持 TX/RX 同步模式,共享时钟
支持 PCM FSYNC 宽度可配:[1~7] sclk cycle 或 one channel block
支持 I2S FSYNC 宽度可配: half frame / whole frame
I2S控制器框图如下。
图47.1.4 I2S/PCM/TDM 控制器 (8通道) 框图
47.2 硬件原理图分析
正点原子ATK-DLRK3568开发板核心板音频原理图如图47.2.1所示:
图47.2.1 RK809 CODEC音频原理图
①、I2S接口一共用到了5根线,这个5根线用于 RK3568与RK809之间的音频数据收发。
②、RK809自带功放接口的,SPKN_OUT和SPKP_OUT我们在底板上接一个8欧2瓦的喇叭播放音频可以直接听到声音,HPL_OUT和HPR_OUT在底板上接了一个耳机插孔,插上耳机播放音频后可以听到声音。MIC1_INP和MIC1_INN在底板上接了咪头,方便录音使用。
47.3 音频驱动使能
RK官方已经写好了RK809 CODEC驱动,因此我们直接配置内核使能RK809 CODEC驱动即可,按照如下所示步骤使能RK809 CODEC驱动。
正点原子提供的RK3568 linux SDK默认配置了RK809 CODEC驱动,所以我们不用配置了,不过我们需要知道,打开kernel/arch/arm64/configs/rockchip_linux_defconfig文件,看到以下内容。
421 CONFIG_SND_SOC_ES8316=y
422 CONFIG_SND_SOC_RK3328=y
423 CONFIG_SND_SOC_RK817=y
424 CONFIG_SND_SOC_RK_CODEC_DIGITAL=y
425 CONFIG_SND_SOC_RT5616=y
426 CONFIG_SND_SOC_RT5640=y
427 CONFIG_SND_SOC_SPDIF=y
第423行,配置了RK809 CODEC驱动,你没有看错,这个就是RK809 CODEC驱动,只是写了RK817,说明RK809与RK817 CODEC部分驱动代码做了兼容!
RK809 CODEC源码路径为kernel/sound/soc/codecs/rk817_codec.c。这里我们就不去分析这部分代码了,有兴趣的可以自行去分析,结合RK809的寄存器手册。
1、配置电源管理芯片RK809
在使用RK809 CODEC之前要使能RK809,因为音频只属于这个电源管理芯片的一部分而已。详细请参考kernel/Documentation/devicetree/bindings/mfd/rk809.txt文档。
打开arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi,找到以下内容。
示例代码47.3.1 RK809与RK809 CODEC配置
1094 &i2c0 {
1095 status = "okay";
1096
......
1114
1115 rk809: pmic@20 {
1116 compatible = "rockchip,rk809";
1117 reg = <0x20>;
1118 interrupt-parent = <&gpio0>;
1119 interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
1120
1121 pinctrl-names = "default", "pmic-sleep",
1122 "pmic-power-off", "pmic-reset";
1123 pinctrl-0 = <&pmic_int>;
1124 pinctrl-1 = <&soc_slppin_slp>, <&rk817_slppin_slp>;
1125 pinctrl-2 = <&soc_slppin_gpio>, <&rk817_slppin_pwrdn>;
1126 pinctrl-3 = <&soc_slppin_gpio>, <&rk817_slppin_rst>;
1127
1128 rockchip,system-power-controller;
1129 wakeup-source;
......
1362 rk809_codec: codec {
1363 #sound-dai-cells = <0>;
1364 compatible = "rockchip,rk809-codec", "rockchip,rk817-codec";
1365 clocks = <&cru I2S1_MCLKOUT>;
1366 clock-names = "mclk";
1367 assigned-clocks = <&cru I2S1_MCLKOUT>,
<&cru I2S1_MCLK_TX_IOE>;
1368 assigned-clock-rates = <12288000>;
1369 assigned-clock-parents =
<&cru I2S1_MCLKOUT_TX>, <&cru I2S1_MCLKOUT_TX>;
1370 pinctrl-names = "default";
1371 pinctrl-0 = <&i2s1m0_mclk>;
1372 hp-volume = <20>;
1373 spk-volume = <3>;
1374 mic-in-differential;
1375 status = "okay";
1376 };
1377 };
第1115行,可以看出RK809是挂载在I2C0上。上面的配置都是RK官方配置好的,或者需要参考配置文档,可以看上面说的Documentation/devicetree/bindings/mfd/rk809.txt。
第1362~1376行,这部分是RK809 CODEC音频驱动设备树配置,可以看到compatible属性为ockchip,rk809-codec", "rockchip,rk817-codec",可以查看kernel/sound/soc/codecs/rk817_codec.c是否也有类似的字符串,有的话说明就匹配上了,后面代码看到我们是用了I2S1,mclk 为 12288000 Hz。
2、声卡设备树配置
上面配置的是音频驱动,现在我们来看看声卡。Simple Card 是 ASoC(Advanced Linux Sound Architecture,高级Linux音频架构) 通用的声卡驱动,可支持大部分标准声卡的添加。RK809也是使用了这个通用的声卡。现在我们来看看这个声卡是如何将RK809驱动关联起来的。声卡驱动文件路径为sound/soc/generic/simple-card.c。
示例代码47.3.2 声卡配置
188 rk809_sound: rk809-sound {
189 status = "okay";
190 compatible = "simple-audio-card";
191 simple-audio-card,format = "i2s";
192 simple-audio-card,name = "rockchip,rk809-codec";
193 simple-audio-card,mclk-fs = <256>;
194
195 simple-audio-card,cpu {
196 sound-dai = <&i2s1_8ch>;
197 };
198 simple-audio-card,codec {
199 sound-dai = <&rk809_codec>;
200 };
201 };
第190行,配置兼容属性为simple-audio-card,匹配的就是sound/soc/generic/simple-card.c驱动。
第191行,设置声卡协议格式为i2s标准格式。
第192行,设置声卡的名字为“rockchip,rk809-codec”。
第193行,默认情况下,mclk 为采样率的256倍。
第195~197行,这里连接硬件,也就是连接I2S。
第198~200行,设置CODEC为rk809_codec,也就是我们前面的RK809 CODEC音频驱动。
47.4 声卡设置与测试
47.4.1 amixer使用方法
1、查看帮助信息
声卡相关选型默认都是关闭的,比如耳机和喇叭的左右声道输出等。因此我们在使用之前一定要先设置好声卡,alsa-utils自带了amixer这个声卡设置工具。输入如下命令即可查看amixer的帮助信息:
amixer --help //查看amixer帮助信息
结果如图47.4.1.1所示:
图47.4.1.1 amixer帮助信息
从图47.4.1.1可以看出,amixer软件命令分为两组,scontrols、scontents、sset和sget为一一组。controls、contents、cset和cget为另一组。这两组的基本功能都是一样的,只不过“s”开头的是simple(简单)组,这一组命令是简化版,本教程最终使用“s”开头的命令设置声卡,因为少输入很多字符。
2、查看设置项
我们要先看一下都有哪些设置项,先来看一下scontrols对应的设置项,输入如下命令:
amixer scontrols //查看所有设置项
结果如图47.4.1.2所示:
图48.5.1.2 scontrols命令对应的设置项
再来看一下controls对应的设置项,输入如下命令:
amixer controls //查看所有设置项
结果如图47.4.1.3所示:
图47.4.1.3 controls命令对应的设置项
图47.4.1.2和47.4.1.3整体设置项目不多,能大体看出意思,我们来设置耳机和喇叭音量、设置左右声道音量、设置输入音量等等。
3、查看设置值
不同的设置项对应的设置值类型不同,先查看一下scontents对应的设置值,输入如下命令:
amixer scontents //查看设置值
结果如图47.4.1.4所示:
图47.4.1.4 scontrols命令对应的设置项
从图47.4.1.4可以看出“Master”项目就是设置耳机音量的,音量范围为0-100(注意若你没看到这些值,默认Buildroot文件系统没有配置声卡,开机初次使用需要播放音频文件后才能看到),当前音量为100。有些设置项是bool类型,只有on和off两种状态。关于controls对应的设置值大家自行输入“amixer controls”命令查看即可。
4、设置声卡
知道了设置项和设置值,那么设置声卡就很简单了,直接使用下面命令即可:
amixer sset 设置项目 设置值
或:
amixer cset 设置项目 设置值
5、获取声卡设置值
如果要读取当前声卡某项设置值的话使用如下命令:
amixer sget 设置项目
或:
amixer cget 设置项目
47.4.2 音乐播放测试
1、使用amixer设置声卡
第一次使用声卡之前一定要先使用amixer设置声卡,打开耳机或者喇叭,并且设置喇叭或者耳机音量,还有就是开启左右声道,输入如下命令:
amixer cset name=‘Master Playback Volume’ ‘on’,‘on’
amixer cset name=‘Master Playback Volume’ ‘63’,‘63’
2、使用aplay播放WAV格式音乐
声卡设置好以后就可以使用aplay软件播放wav格式的音乐测试一下,aplay也是alsa-utils提供的。默认已经在/usr/share/sounds路径下存放了一个音频了,我们可以直接拿来测试,测试命令如下:
aplay /usr/share/sounds/test.wav //播放音频
如果一切设置正常的话就会开始播放音乐。
注意:由于RK809 CODEC虽有耳机检测功能但是RK在驱动上没有实现耳机和喇叭自动切换,应用层上面也没有去实现,所以耳机与喇叭不能自动切换,播放音乐的时候会同时有声音。
47.4.3 MIC录音测试
ATK-DLRK3568开发板上有一个板载麦克风,如图47.4.3.1所示:
图47.4.3.1 板载麦克风
1、使用amixer设置声卡
同样的,第一次使用声卡录音之前要先使用amixer设置一下声卡,设置为板载的咪头,本想设置捕获音量的,但是发现没有相关controls,设置声卡的命令如下所示:
amixer cset name=‘Capture MIC Path’ ‘Main Mic’
2、使用arecord录制音频
使用arecord来录制一段10秒中的音频,arecord也是alsa-utils编译出来的,输入如下命令:
arecord -r 44100 -f S16_LE -d 10 record.wav
-r 44100:采样率 44.1K,-f是用来设置录音的数据以S16_LE格式进行采样。-d是指定录音时间,单位为s,这条指令就是录制一段以S16_LE格式10s的wav音频,音频名字为record.wav。录制的时候大家就可以对着开发板上的MIC说话,直到录制完成。
录制完成以后使用aplay播放刚刚录制的音频,看看录制是否成功,命令如下:
aplay record.wav
47.5 开机自动配置声卡
大家在使用的时候应该应该会发现开发板重启以后声卡的所有设置都会消失,必须重新设置声卡。也就是说我们对声卡的设置不能保存,本小节我们就来学习一下如何保存声卡的设置。
1、使用alsactl保存声卡设置
声卡设置的保存通过alsactl工具来完成,此工具也是alsa-utils编译出来的。alsactl默认将声卡配置文件保存在/var/lib/alsa目录下。
首先使用amixer设置声卡,然后输入如下命令保存声卡设置
alsactl -f /var/lib/alsa/asound.state store //保存声卡设置
-f指定声卡配置文件,store表示保存。关于alsactl的详细使用方法,输入“alsactl -h”即可。保存成功以后就会生成/var/lib/alsa/asound.state这个文件,asound.state里面就是关于声卡的各种设置信息,大家可以打开此文件查看一下里面的内容,如图47.5.1所示:
图47.5.1 asound.state文件部分内容
如果要使用asound.state中的配置信息来配置声卡,执行如下命令即可:
alsactl -f /var/lib/alsa/asound.state restore
最后面的参数改为restore即可,也就是恢复的意思。
我们需要创建/etc/init.d/S98alactl自启动文件,如果没有此文件的话自行创建,或者使用/etc/init.d/rcS文件,在此文件中添加如下内容:
示例代码47.5.1 /etc/init.d/S98alactl自启动文件内容
1 PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
2 start_restore()
3 {
4 if [ -f "/var/lib/alsa/asound.state" ]; then
5 /usr/sbin/alsactl -f /var/lib/alsa/asound.state restore &
6 fi
7 }
8 stop_restore()
9 {
10 echo -n ""
11 }
12 case "$1" in
13 start)
14 echo -n "ALSA: Restoring mixer setting......"
15 start_restore
16 echo "done."
17 ;;
18 stop)
19 stop_restore
20 echo "done."
21 ;;
22 restart|reload)
23 echo -n "stoping restore... "
24 stop_restore && sleep .3
25 echo "done."
26 echo -n "starting restore... "
27 start_restore
28 echo "done."
29 ;;
30 *)
31 echo "Usage: $0 {start|stop|restart}"
32 exit 1
33 esac
34 exit 0
chmod 777 /etc/init.d/S98alactl # 赋予文件可执行权限
第4行判断/var/lib/alsa/asound.state这个文件是否存在,存在的话就执行下面的。首先输出一行提示符:“ALSA: Restoring mixer setting…”,表示设置声卡,最后调用/usr/sbin/alsactl来执行声卡设置工作。
设置完成以后重启开发板,开发板开机就会自动设置声卡,输出如图47.5.2所示内容:
图47.5.2 声卡开机自动设置
直接使用aplay播放音乐测试声卡开机自动配置是否正确。
47.6 alsamixer简介
alsamixer是基于图形化的,直接输入“alsamixer”命令即可打开声卡配置界面,如图47.6.1所示:
图47.6.1 alsamixer配置界面
F1键:查看帮助信息。
F2键:查看系统信息。
F3键:播放设置。
F4键:录音设置。
F6键:选择声卡,多声卡情况下。
Item:设置项全名。
图47.6.1最下面一行就是具体的设置项,比如“Master”、“Playback Path”等等,通过键盘上左右键选择设置项。按下上下键来调整大小,比如设置耳机音量大小等。有些项目会显示“MM”,表示静音,按下“M”键修改为“OO”状态打开,“M”键用于修改打开或关闭某些项目。
关于alsamixer的介绍就到这里,用起来还是很简单的。