音频是我们最常用到的功能,音频也是 linux 和安卓的重点应用场合。I.MX6ULL 带有 SAI接口,正点原子的 I.MX6ULL ALPHA 开发板通过此接口外接了一个 WM8960 音频 DAC 芯片,本章我们就来学习一下如何使能 WM8960 驱动,并且通过 WM8960 芯片来完成音乐播放与录音。
音频开发是自己搭建音频电路还是直接使用音频编解码芯片?
在音频开发中,选择自己搭建音频电路还是直接使用音频编解码芯片(CODEC)取决于多个因素,包括项目需求、开发周期、成本预算、技术能力等。以下是两者的对比分析和适用场景建议:
自己搭建音频电路
优点
灵活性高:完全自定义电路设计,适合特殊需求(如超高保真、特殊滤波器设计)。
学习价值:深入理解模拟电路(运放、ADC/DAC、信号调理)和数字音频基础。
成本可控:对于简单应用(如单声道麦克风前置放大),分立元件可能更便宜。
缺点
复杂度高:需处理模拟信号噪声、阻抗匹配、时钟同步等问题,调试难度大。
开发周期长:从原理图设计、PCB布局到调试优化,耗时远高于使用现成CODEC。
性能受限:分立元件的信噪比(SNR)、THD等指标通常不如专业CODEC。
典型场景
专业音频设备:高端Hi-Fi放大器、定制效果器。
教育/实验:学习模拟音频电路设计。
极简需求:单一功能电路(如麦克风放大+ADC)。
关键组件
ADC/DAC芯片(如TI的PCM1808/PCM5102A)。
运放电路:麦克风前置放大(如NE5532)、低通滤波。
时钟管理:晶振+PLL生成低抖动时钟。
使用音频编解码芯片(CODEC)
优点
集成度高:单芯片集成ADC/DAC/放大器/混音功能,减少外围电路。
性能优异:专业CODEC的SNR>90dB,支持24bit/192kHz高解析度。
开发快捷:通过I2C/SPI配置寄存器即可工作,无需复杂模拟设计。
低功耗:针对便携设备优化(如WM8960、CS42L52)。
缺点
灵活性较低:功能受限于芯片设计(如固定采样率、不可调谐的滤波器)。
成本较高:高端CODEC(如AK4499)单价可能超过10美元。
典型场景
消费电子:蓝牙音箱、智能家居语音交互。
嵌入式系统:树莓派音频扩展、工业录音设备。
快速原型开发:需要短期内实现音频输入/输出的项目。
常见芯片
低功耗:WM8960、MAX9867(适合便携设备)。
高性能:CS42L52、AK4558(支持192kHz)。
多功能:TLV320AIC3104(带DSP和多种接口)。
决策建议:如何选择?
选择自己搭建电路当:
你需要完全自定义的模拟信号链(如特殊EQ或滤波器)。
项目预算极低,且需求简单(如仅需ADC)。
目标是教学或技术验证(非量产)。
选择CODEC当:
你需要快速实现高质量音频输入/输出(如I2S接口)。
项目涉及复杂功能(如麦克风阵列、耳机驱动、混音)。
缺乏模拟电路设计经验或资源。
折中方案:
混合设计:
使用CODEC处理核心功能(如ADC/DAC)。
自定义外围电路(如麦克风前置放大、功放级)。
示例对比
需求 自己搭建电路 使用CODEC 蓝牙音箱音频处理 复杂(需功放+滤波+ADC) 简单(WM8960一键解决) 高保真DAC 可选分立R2R DAC(极致音质) 用现成芯片(如PCM1794) 麦克风+耳机接口 多块芯片+复杂布线 单芯片(TLV320AIC3104) 总结
优先选择CODEC:除非有特殊需求,现代音频CODEC在性能、成本和开发效率上远超分立电路。
自己搭建电路:仅推荐给专业音频工程师或教育场景。
工具推荐:
快速验证:使用开发板(如STM32+WM8960模块)。
仿真工具:SPICE(模拟电路)、Audio Precision(测试)。
如果需要具体芯片推荐或电路设计指导,可以提供更多项目细节!
音频接口简介
为何需要音频编解码芯片?
处理器要想“听到”外界的声音必须要把外界的声音转化为自己能够理解的“语言”,处理器能理解的就是 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。因此大家会看到高端的音频播放器都会有很高的采样率和采样位数,同样的价格也会越高。当然了,实际的效果还与其他部分有关,采样率和采样位数只是其中重要的指标之一。
如果使用了音频编解码芯片,还需要软件来处理PCM数据吗?
即使使用了音频编解码芯片(CODEC),软件(如 MCU、DSP 或 PC 端程序)通常仍需参与 PCM 数据的处理,但具体程度取决于应用场景和 CODEC 的功能集成度。以下是详细分析:
音频编解码芯片(CODEC)的核心功能
CODEC 芯片的主要任务是:
模数转换(ADC):将模拟信号(如麦克风输入)转换为数字 PCM 数据。
数模转换(DAC):将数字 PCM 数据转换为模拟信号(如扬声器输出)。
集成功能:部分 CODEC 还可能包含:
硬件编解码(如直接输出 MP3/AAC,而非原始 PCM)。
数字信号处理(DSP)(如降噪、均衡器)。
音频接口(如 I2S、TDM、PDM)。
哪些场景仍需软件处理 PCM?
即使使用 CODEC,软件可能仍需处理 PCM 数据的场景包括:
(1) CODEC 仅提供 ADC/DAC 功能
典型芯片:PCM1808(ADC)、PCM5102A(DAC)。
软件职责:
接收 CODEC 输出的原始 PCM 数据,进行编码(如转 MP3/AAC)。
将解码后的 PCM 数据发送给 CODEC 的 DAC。
示例:
// 伪代码:MCU 读取 ADC 的 PCM 数据并编码 pcm_data = read_from_codec_adc(); // 从 CODEC 获取 PCM mp3_data = encode_to_mp3(pcm_data); // 软件编码
(2) 需要高级音频处理
场景:降噪、混音、回声消除、语音识别等。
软件工具:
嵌入式端:DSP 算法(如 ARM CMSIS-DSP)、专用库(如 Speex)。
PC/服务器端:FFmpeg、WebRTC 音频处理模块。
(3) 多设备或协议适配
场景:
将 PCM 数据通过蓝牙(需转 SBC/AAC)、USB 音频或网络传输(如 RTP)。
对接不同接口的 CODEC(如 I2S 转 TDM)。
示例:
通过 FFmpeg 将 PCM 推送到 RTMP 服务器 ffmpeg -f s16le -ar 44100 -i input.pcm -c:a aac -f flv rtmp://server
(4) CODEC 功能不足
部分低端 CODEC 仅支持固定采样率(如 16kHz),需软件重采样(如转 48kHz)。
动态控制:如实时调整音量、声道平衡(需软件干预寄存器)。
哪些场景可以绕过软件处理?
以下情况可能无需软件处理 PCM:
全硬件通路:
CODEC 直接连接 DSP 芯片(如数字麦克风 → CODEC → 扬声器),无额外处理需求。
CODEC 集成编解码:
某些 CODEC(如 WM8960 的硬件 DSP 模式)可直接输出压缩数据(如 MP3),但灵活性较低。
简单播放/录制:
例如:MCU 仅需将 MP3 文件通过 I2S 发送给 CODEC 解码播放,无需修改 PCM 数据。
典型架构示例
(1) 语音识别设备
麦克风 → CODEC(ADC) → PCM → 软件降噪 → 云端ASR → 文本
软件必须处理 PCM:降噪、分帧、编码(如转 Opus)。
(2) 蓝牙音箱
手机 AAC → 蓝牙芯片 → 软件解码 → PCM → CODEC(DAC) → 扬声器
软件必须解码 AAC 为 PCM,再发送给 CODEC。
(3) 专业录音设备
麦克风 → CODEC(ADC+PCM) → 直接保存为 WAV(无软件处理)
无需软件处理:CODEC 输出标准 PCM,直接存储。
总结
场景 是否需要软件处理 PCM? 原因 CODEC 仅做 ADC/DAC ✅ 是 需编码/解码/音效处理 CODEC 集成硬件编码(如MP3) ❌ 否 直接输出压缩数据 实时音频传输(如蓝牙/USB) ✅ 是 需协议转换(PCM→SBC/AAC) 简单播放/录制(无处理) ❌ 否 CODEC 直接处理 结论:
大多数场景仍需软件参与,尤其是需要编解码、音效或协议转换时。
全硬件方案仅适用于功能固定的简单设备(如传统MP3播放器)。
如果需要具体芯片(如 WM8960、CS42L52)的配置案例,可以进一步探讨!
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 整体框图如图 65.1.2.1 所示:
依次来看一下图 65.1.2.1 中这四部分接口都是什么功能:
①、此部分是 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 倍。
图 65.1.3.1 就是一帧立体声音频时序图:
图 65.1.3.2 就是笔者采用逻辑分析仪抓取到的一帧真实的音频时序图:
图 65.1.3.2 中通道 0 是 LRCK 时钟,通道 1 为 BCLK,通道 2 是 DACDATA,通道 3 是MCLK。随着技术的发展,在统一的 I2S 接口下,出现了不同的数据格式,根据 DATA 数据相对于 LRCK 和 SCLK 位置的不同,出现了 LeftJustified(左对齐)和 RightJustified(右对齐)两种格式,这两种格式的时序图如图 65.1.3.3 所示:
I.MX6ULL SAI 简介
音频 CODEC 支持 I2S 协议,那么主控制器也必须支持 I2S 协议,大家如果学过STM32F4/F7/H7 的话应该知道 SAI 接口,因为在 STM32 中就是通过 SAI 接口来连接音频CODEC。I.MX6ULL 也提供了一个叫做 SAI 的外设,全称为 SynchronousAudio Interface,翻译过来就是同步音频接口。
I.MX6ULL 的 SAI 是一个全双工、支持帧同步的串行接口,支持 I2S、AC97、TDM 和音频DSP,SAI 主要特性如下:
①、帧最大为 32 个字。
②、字大小可选择 8bit 或 32bit。
③、每个接收和发送通道拥有 32×32bit 的 FIFO。
④、FIFO 错误以后支持平滑重启。
I.MX6ULL 的 SAI 框图如图 65.1.4.1 所示:
图 65.1.4.1 中右侧“SAI_TX”和“SAI_RX”开头的就是 SAI 外设提供给外部连接音频CODEC 的信号线,具体连接方法查看 65.2 小节的原理图。
SAI(Serial Audio Interface,串行音频接口)是一种用于数字音频数据传输的嵌入式硬件接口协议,常见于微控制器(如STM32)、DSP和音频编解码芯片(CODEC)中。它支持多种音频格式(如PCM、I2S、TDM),广泛应用于嵌入式音频系统、消费电子和车载音频设备。
SAI 的核心特点
特性 说明 多协议支持 兼容 I2S、PCM、TDM 等多种音频格式。 灵活的数据帧 可配置帧长度(8/16/32bit)、声道数(单声道/立体声/多声道)。 主从模式 支持主设备(提供时钟)或从设备(接收时钟)。 全双工/半双工 支持同时收发(全双工)或单向传输(半双工)。 低延迟 硬件级接口,适合实时音频处理。 SAI 的常见应用场景
嵌入式音频设备:智能音箱、耳机、车载娱乐系统。
多声道音频:家庭影院、环绕声系统(通过TDM模式支持多路音频)。
数字麦克风阵列:PDM麦克风数据接收与处理。
专业音频设备:音频接口、效果器(与DSP芯片通信)。
SAI vs. 其他音频接口
对比项 SAI I2S TDM PDM 协议灵活性 高(多模式) 仅I2S 仅TDM 仅PDM 多声道支持 是(可扩展) 仅立体声 是(8+声道) 否(单声道) 典型用途 通用嵌入式音频 芯片间音频传输 多通道音频系统 数字麦克风 ✅ SAI的优势:
在STM32等MCU中,SAI可替代I2S,提供更灵活的时钟和帧配置。
支持 非标准音频格式(如自定义位深度和采样率)。
SAI 的硬件连接与信号
SAI接口通常包含以下信号线:
SCK(串行时钟):同步数据传输的时钟信号。
FS(帧同步):标记音频帧的开始(左右声道切换)。
SD(数据线):音频数据输入/输出(支持多路复用)。
MCLK(主时钟):可选,提供高精度时钟参考(如256×FS)。
典型连接示意图:
MCU (SAI) ──SCK──> 音频CODEC ──FS──> ──SD──> ──MCLK─>
SAI 的配置示例(以STM32为例)
(1) 初始化参数
音频模式:I2S标准模式、PCM模式或TDM模式。
数据格式:16/24/32位数据对齐。
采样率:8kHz~192kHz(依赖时钟配置)。
(2) 代码片段(HAL库)
SAI_HandleTypeDef hsai; hsai.Instance = SAI1_Block_A; hsai.Init.AudioMode = SAI_MODEMASTER_TX; // 主设备发送模式 hsai.Init.Synchro = SAI_ASYNCHRONOUS; // 异步时钟 hsai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; hsai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; hsai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_EMPTY; hsai.Init.ClockSource = SAI_CLKSOURCE_PLLSAI; hsai.Init.MonoStereoMode = SAI_STEREOMODE; // 立体声 hsai.Init.Protocol = SAI_FREE_PROTOCOL; // 自由协议(可自定义) HAL_SAI_Init(&hsai);
常见问题
Q1: SAI 和 I2S 有什么区别?
I2S 是固定格式的音频接口(仅支持立体声,标准时钟配置)。
SAI 是更通用的接口,可模拟I2S、PCM或TDM,且支持自定义帧结构。
Q2: 如何用SAI连接数字麦克风(PDM)?
需外接 PDM转PCM解码器(如DFSDM模块在STM32中),SAI接收PCM数据。
Q3: SAI是否支持高解析度音频(如192kHz/24bit)?
是的,但需确保主时钟(MCLK)和PLL配置足够(如STM32的PLLSAI分频设置)。
总结
SAI 是嵌入式音频系统的“瑞士军刀”,兼顾灵活性与性能。
适用场景:需要多协议、多声道或非标准音频格式的嵌入式设计。
开发建议:参考芯片手册(如STM32的SAI章节)配置时钟和帧参数。
如果需要具体的硬件设计或代码实现案例,可以进一步探讨!
硬件原理图分析
V2.4 版本以前底板音频原理图如图 65.2.1 所示:
V2.4 及后面版本的底板音频原理图如图 65.2.2 所示:
图 65.2.1 和 65.2.2 中唯一的区别就是 WM8960 所连接的 I2C 接口,一个是 I2C2,一个是I2C1,其他都是一模一样的。
我们重点关注两个接口,SAI 和 I2C,我们依次来看一下这两个接口:
①、SAI 接口一共用到了 6 根数据线,这 6 根数据线用于 I.MX6ULL 与 WM8960 之间的音频数据收发。
②、WM8960 在使用的时候需要进行配置,配置接口为 I2C,V2.4 以前版本连接到了I.MX6ULL 的 I2C2 上,V2.4 及以后版本连接到了 I2C1 上
音频驱动使能
NXP 官方已经写好了 WM8960 驱动,因此我们直接配置内核使能 WM8960 驱动即可,按照如下所示步骤使能 WM8960 驱动。
修改设备树
前面分析原理图的时候已经说过了,WM8960 与 I.MX6ULL 之间有两个通信接口:I2C 和 SAI,因此设备树中会涉及到 I2C 和 SAI 两个设备节点。其中 I2C 用于配置 WM8960,SAI 接口用于音频数据传输,我们依次来配置一下这两个接口。
1、wm8960 i2c 接口设备树
首先配置一下 I2C 接口,根据原理图我们知道 V2.4 以前版本底板 WM8960 连接到了I.MX6ULL 的 I2C2 接口上,因此在设备树中的“i2c2”节点下需要添加 wm8960 信息。V2.4及以后版本 WM8960 连接到了 I2C1 上,因此需要在设备树中的“i2c1”节点下需要添加 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 这两个引脚都会关闭。
绑定文档给出的参考节点内容如下所示:
根据 wm8960.txt 这份绑定文档我们就可以在任意一个主控的 I2C 节点下添加 wm8960 相关信息了,NXP 官方 I.MX6ULL EVK 开发板使用的也是 WM8960,因此在设备树中添加设备节点这些工作 NXP 已经帮我们做了。打开 imx6ull-alientek-emmc.dts,根据自己所使用的底板版本号,找到名为“i2c2”或“i2c1”的节点,将如下 wm8960 节点信息添加到对应的 i2c 节点下:
可以看出,示例代码 65.3.1.2 中的内容基本和 wm8960.txt 这个绑定文档中的示例内容一致,只是多了第 4 和第 5 这两行,这两行用于描述时钟相关信息。第 4 行指定时钟源为 SAI2,第 5行指定时钟的名字为“mclk”。前面我们说过,为了更好的同步,一般都会额外提供一条 MCLK时钟。
V2.4 以前版本的底板添加到 I2C2 节点下,如图 65.3.1.1 所示:
V2.4 及以后版本的底板添加到 I2C1 节点下,如图 65.3.1.2 所示:
至此,关于 wm8960 的 I2C 配置接口设备树就已经添加好了。
I.MX6ULL SAI 音频接口设备树
接下来就是 I.MX6ULL 的 SAI 音频接口设备树相关内容的修改了,同样的,先查阅一下相应的绑定文档:Documentation/devicetree/bindings/sound/fsl-sai.txt。和我们前面讲过的 IIC 接口、 ECSPI 等接口一样,在 imx6ull.dtsi 文件中会有关于 SAI 相关接口的描述,这部分是 NXP 原厂编写的,我们不需要做任何修改,SAI2 的设备子节点内容如下所示:
直接搜索 compatible 属性中的两个兼容值,那么你就会找到 I.MX6ULL 的 SAI 接口驱动文件,路径为 sound/soc/fsl/fsl_sai.c,此驱动文件不需要我们去研究,除非你在 NXP 上班,而你的工作恰好是给 NXP 的 I.MX 系列芯片编写 SAI 驱动的。从第 13 行可以看出,SAI2 默认是关闭的,因此我们需要将其打开,也就是设置 status 属性的值为“okay”,这个工作肯定是在具体板子对应的.dts 文件中完成的,其实就是向 sai2 节点里面追加或者修改一些属性值。打开 imx6ull-alientek-emmc.dts 文件,找到如下内容:
示例代码 65.3.1.3 中的内容是 NXP 针对自己的 I.MX6ULL EVK 开发板而添加的,主要是对 sai2 节点做了三个方面的修改:SAI2 接口的 pinctrl、相应的时钟、修改 status 为“okay”。我们重点来看一下 pinctrl 的设置,因为关系到 SAI2 接口的 IO 设置,从 pinctrl-0 属性可以看出这里一共有两组 IO:pinctrl_sai2 和 pinctrl_sai2_hp_det_b,这两组 IO 内容如下:
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 节点内容如下所示:
简单看一下 sound 节点中几个重要的属性:
compatible:非常重要,用于匹配相应的驱动文件,有两个属性值,在整个 linux 内核源码中搜索这两个属性值即可找到对应的驱动文件,这里找到的驱动文件为:sound/soc/fsl/imx-wm8960.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,进入如下路径:
结果如图 65.5.2.1 所示:
2、使能 I.MX6ULL 的 WM8960 驱动
接下来使能 WM8960 驱动,进入如下路径:
结果如图 65.5.2.2 所示:
驱动使能以后重新编译 linux 内核,编译完成以后使用新的 zImage 和.dtb 文件启动,如果设备树和驱动都使能的话系统启动过程中就会如图 65.5.2.4 所示的 log 信息:
系统最终启动以后会打印出 ALSA 设备列表,现在的音频 CODEC 驱动基本都是 ALSA 架构的,本章的 WM8960 驱动也是根据 ALSA 架构编写的。因此在 ALSA 设备列表中就会找到“wm8960-audio”这个声卡,如图 65.5.2.5 所示:
进入系统以后查看一下/dev/snd 目录,看看有没有如图 65.5.2.6 所示文件:
图65.5.2.6中的这些文件就是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 这两个东西。
具体参考正点原子的应用开发手册或者驱动开发手册。