Linux 音频驱动实验

具体参考正点原子的应用开发手册或者驱动开发手册。

本文仅作为个人学习记录使用。 

音频是我们最常用到的功能,音频也是 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,直接存储。


结论

大多数场景仍需软件参与,尤其是需要编解码、音效或协议转换时。

全硬件方案仅适用于功能固定的简单设备(如传统MP3播放器)。

如果需要具体芯片(如 WM8960、CS42L52)的配置案例,可以进一步探讨!

为了保证灵活性,大部分情况下都是将采集到的数据交给软件去进行后续的处理。

声卡指的是音频编解码模块吗?

声卡(Sound Card)是计算机系统中处理音频信号的硬件组件,其核心功能确实包括音频编解码(Codec),但现代声卡的功能远不止于此,它是一个完整的音频处理系统。以下是详细解析:

一、声卡的核心组成与功能

声卡通常包含以下关键模块:

  • 编解码芯片(Codec)

    • 核心功能:实现数模转换(DAC)模数转换(ADC)
      • DAC:将数字音频信号(如电脑中的 MP3 文件)转换为模拟信号,驱动耳机或音箱发声;
      • ADC:将麦克风输入的模拟声音转换为数字信号,用于录音或语音通信。
    • 示例:常见的编解码芯片如 Cirrus Logic CS4398、ESS Sabre ES9038 等,其性能直接影响声卡的音质(如动态范围、信噪比)。
  • 数字信号处理器(DSP)

    • 处理复杂音频算法:如 3D 环绕声、均衡器(EQ)、降噪、音频特效等,减轻 CPU 负担;
    • 应用场景:游戏中模拟枪声方位、音乐制作中的实时效果处理。
  • 输入 / 输出接口

    • 模拟接口:耳机插孔、麦克风输入、线路输入 / 输出(RCA 或 3.5mm 接口);
    • 数字接口:光纤(TOSLINK)、同轴(S/PDIF)、USB、HDMI 等,用于传输无损数字信号。
  • 放大器(AMP)

    • 增强输出功率,驱动高阻抗耳机或音箱;
    • 高端声卡常配备独立运放芯片(如 OPA 系列),提升音质解析力。
  • 电源管理与滤波电路

    • 提供稳定电源,减少电磁干扰(EMI)和电源噪声,确保纯净的音频信号。

二、声卡与编解码模块的关系

  • 编解码芯片是声卡的 “心脏”:没有 Codec,声卡无法完成最基本的数字 - 模拟信号转换;
  • 但声卡是一个系统级产品,除了 Codec,还需 DSP、接口电路、电源管理等协同工作,才能实现完整的音频功能(如录音、播放、音效处理、多设备兼容等)。

类比:

  • 编解码芯片 ≈ 汽车发动机(负责动力转换);
  • 声卡 ≈ 完整的汽车(包含发动机、变速箱、底盘、车身等,才能上路行驶)。

三、常见误解澄清

  1. “声卡 = Codec” ×
    早期声卡可能仅集成简单 Codec,但现代声卡(尤其是高端产品)功能更复杂,如支持多声道输出、硬件加速的音频特效等。

  2. “所有电脑都有声卡” √
    主板上的 “集成声卡”(如 Realtek ALC 系列)本质也是声卡,只是功能简化(Codec + 基本 I/O 接口),音质通常逊于独立声卡。

  3. “USB 声卡只是外接 Codec” ×
    USB 声卡需包含 USB 控制器、驱动程序和音频处理电路,才能与电脑通信并实现完整功能,并非单纯的 Codec。

四、声卡的应用场景

  • 音乐制作:专业声卡(如 Universal Audio Apollo)提供低延迟的多轨录音和高精度 DAC,满足录音室需求;
  • 游戏 / 电影:声卡的 DSP 可实现 7.1 环绕声,增强沉浸感(如 Creative Sound Blaster 系列);
  • 日常使用:提升电脑音频质量,减少底噪,支持高解析度音频(如 DSD、FLAC)。

总结

声卡的核心是编解码模块,但它是一个包含编解码、信号处理、接口、放大等功能的完整系统。判断声卡性能时,不仅要看 Codec 的参数(如信噪比、动态范围),还需关注整体设计、电源方案和驱动优化。

WM8960 简介

前面我们已经分析了为何需要音频编解码芯片,那是因为专用的音频编解码芯片提供了很多针对音频的特性。我们就以正点原子 ALPHA 开发板所使用的 WM8960 这颗芯片为例,来看一下专用的音频编解码芯片都有哪些特性。

WM8960 是一颗由 wolfson(欧胜)公司出品的音频编解码芯片,是一颗低功耗、高质量的立体声音频 CODEC。集成 D 类喇叭功放,每个通道可以驱动一个 1W 喇叭(8Ω)。内部集成 3 个立体声输入源,可以灵活配置,拥有一路完整的麦克风接口。WM8960 内部 ADC DAC 都为24 位,WM8960 主要特性如下所示:

①、DAC SNR(信噪比)98dB3.3V48KHz THD(谐波失真)-84dB

②、ADC SNR(信噪比)94dB3.3V48KHz THD(谐波失真)-82dB

③、3D 增强。

④、立体声 D 类功放,可以直接外接喇叭,8Ω负载下每通道 1W

⑤、集成耳机接口。

⑥、集成麦克风接口。

⑦、采样率支持 8K11.025K12K16K22.05K24K32K44.1K 48K

……

WM8960 整体框图如图 65.1.2.1 所示:

依次来看一下图 65.1.2.1 中这四部分接口都是什么功能:

①、此部分是 WM8960 提供的输入接口,作为立体声音频输入源,一共提供了三路,分别为 LINPUT1/RINPUT1LINPUT2/RINPUT2LINPUT3/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 根线的作用如下:

  • ADCDATADC 数据输出引脚,采集到的音频数据转换为数字信号以后通过此引脚传输给主控制器。
  • ADCLRCADC 数据对齐时钟,也就是帧时钟(LRCK),用于切换左右声道数据,此信号的频率就是采样率。此引脚可以配置为 GPIO 功能,配置为 GPIO 以后 ADC 就会使用 DACLRC引脚作为帧时钟。
  • DACDATDAC 数据输入引脚,主控器通过此引脚将数字信号输入给 WM8960 DAC
  • DACLRCDAC 数据对齐时钟,功能和 ADCLRC 一样,都是帧时钟(LRCK),用于切换左右声道数据,此信号的频率等于采样率。
  • BCLK位时钟,用于同步。
  • MCLK主时钟,WM8960 工作的时候还需要一路主时钟,此时钟由 I.MX6ULL 提供,MCLK 频率等于采样率的 256 384 倍,因此大家在 WM8960 的数据手册里面常看到MCLK=256fs 或 MCLK=384fs

④、此部分为控制接口,是一个标准的 I2C 接口,WM8960 要想工作必须对其进行配置,这个 I2C 接口就是用于配置 WM8960 的。

音频的功放是什么?跟运放是什么关系?有哪些类功放?

音频功放(功率放大器,Power Amplifier)和运放(运算放大器,Operational Amplifier)是音频电路中密切相关但功能不同的核心组件。以下从定义、关系、分类三个维度详细说明:

一、音频功放是什么?

音频功放是一种将微弱音频信号(如手机、播放器输出的信号)放大到足够功率,以驱动扬声器(喇叭)发声的电子设备。其核心作用是提升信号的功率(电压 × 电流),因为扬声器需要较大的电流才能振动发声,而前端设备(如声卡、播放器)输出的信号功率通常不足 1mW,无法直接驱动扬声器。

  • 输入:来自音源设备的低功率音频信号(如 DAC 输出的模拟信号、麦克风放大后的信号)。
  • 输出:高功率信号,直接连接扬声器(或音箱),推动振膜振动产生声音。

二、音频功放与运放的关系

运放是一种通用的模拟集成电路,而音频功放是针对 “功率放大” 设计的专用电路,两者既有区别也有联系:

1. 核心区别

维度运放(Operational Amplifier)音频功放(Power Amplifier)
功能主要用于信号的电压放大、滤波、比较、缓冲等(低功率处理)专注于功率放大(同时提升电压和电流),驱动负载(扬声器)
输出功率很小(通常 mA 级电流,无法驱动扬声器)较大(从几瓦到几千瓦,满足不同扬声器需求)
负载能力弱,只能驱动高阻抗负载(如后续电路的输入端)强,可驱动低阻抗负载(扬声器通常为 4Ω、8Ω、16Ω)

2. 联系

  • 运放可作为功放的 “前级”:在音频电路中,运放常被用于功放的 “前置放大级”,负责将微弱信号先进行电压放大(如麦克风信号从 mV 级放大到 V 级),再送入功放的功率放大级进行功率提升。
  • 部分功放基于运放设计:低功率功放(如耳机放大器)可能直接采用 “大功率运放”(如 LM386、NE5532 的高功率版本),通过外部电路扩展电流输出能力,实现简化设计。

三、音频功放的分类(按电路结构 / 工作方式)

根据功率放大级的工作状态(即晶体管的导通时间),音频功放主要分为以下几类,各有适用场景:

1. 甲类功放(Class A)

  • 工作原理:功放管(晶体管)在信号的整个周期(正半周 + 负半周)内始终处于导通状态,导通角为 360°。
  • 特点
    • 优点:失真极低(线性度好),音质细腻温暖,适合高保真(Hi-Fi)场景。
    • 缺点:效率极低(仅 20%-30%),大量能量转化为热量,需庞大散热装置,体积大、功耗高。
  • 适用场景:高端音响、耳机放大器(追求极致音质,不计较功耗)。

2. 乙类功放(Class B)

  • 工作原理:采用两个互补的功放管,分别负责信号的正半周和负半周放大(每个管子导通角 180°)。
  • 特点
    • 优点:效率高(理想状态下可达 78.5%),功耗低,散热压力小。
    • 缺点:存在 “交越失真”(信号过零时,两个管子切换导通的瞬间产生的失真),音质较甲类粗糙。
  • 适用场景:早期低成本音响、汽车音响(注重效率,对失真不敏感)。

3. 甲乙类功放(Class AB)

  • 工作原理:在乙类基础上改进,让两个功放管在信号过零时保持微小导通电流(导通角略大于 180°),避免交越失真。
  • 特点
    • 优点:兼顾甲类的低失真和乙类的高效率(效率约 50%-70%),是目前最常用的音频功放类型。
    • 缺点:失真略高于甲类,但远低于乙类,性价比极高。
  • 适用场景:家用音箱、汽车音响、多媒体音响、中高端耳机放大器(平衡音质与效率)。

4. 丁类功放(Class D)

  • 工作原理:采用 “脉冲宽度调制(PWM)” 技术,将音频信号转换为高频脉冲(占空比随音频信号变化),通过功率开关管(MOSFET)放大后,再通过低通滤波器还原为音频信号驱动扬声器。
  • 特点
    • 优点:效率极高(80%-95%),功耗低、发热小,可做得体积小巧(如便携音箱、蓝牙音箱)。
    • 缺点:早期型号因 PWM 转换和滤波问题,失真和噪声较高;现代高端丁类功放(如 TI 的 TPA3255)通过优化电路,音质已接近甲乙类。
  • 适用场景:便携音箱、蓝牙音箱、汽车音响、有源监听音箱、大功率舞台功放(追求小型化和高效率)。

5. 其他特殊类型

  • 丙类功放(Class C):导通角远小于 180°,效率更高,但失真极大,仅用于射频放大(非音频领域)。
  • 甲丙类、甲乙丙类:多为射频领域设计,音频中极少使用。
  • 数字功放:广义上丁类功放属于数字功放,部分高端型号通过全数字信号处理(DSP)优化,进一步提升音质(如索尼 S-Master HX)。

总结

  • 音频功放的核心是 “功率放大”,驱动扬声器发声;运放是 “信号处理工具”,常作为功放的前置级,负责信号调理。
  • 甲乙类和丁类是目前主流:甲乙类适合对音质要求较高的场景,丁类适合便携、大功率或高效率需求场景。
  • 选择时需平衡音质、效率、体积和成本:Hi-Fi 发烧友可能偏爱甲类或高端甲乙类,而便携设备几乎全用丁类。

I2S 总线接口

参考:

数字音频接口之I2S总线协议详解-CSDN博客

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

I2S时序图如下所示:

I2S接口通常由三类信号线组成,分别是:

时钟线(Continues Serial Clock,SCK)

SCK线提供了同步音频数据传输的时钟信号。确定了数据传输的速度和时序。该时钟也称为Bit Clock(BCLK)。音频数据的每一位数据都对应一个SCK,立体声都是双声道的,因此

SCK=2×采样率×采样位数。

比如采样率为 44.1KHz、16 位的立体声音频,那么

SCK=2×44100×16=1411200Hz=1.4112MHz。

左/右声道线(Left-Right Clock,LRCK,也可以称为WS,表示字段选择)

LRCK线指示了当前传输的是左声道的音频数据还是右声道的音频数据。它被称为帧同步信号。LRCK的频率=采样频率,比如采样率为 44.1KHz 的音频,LRCK=44.1KHz。频率等于采样率,则每个周期内,一半时间传输左声道,一半时间传输右声道。

数据线(Serial Data,SD )

SD线用于传输实际的音频数据。数据的位宽可以根据具体应用而变化,通常为16位或32位。TX方向为:Serial Data Out(SDOUT);RX方向为:Serial Data In(SDIN)。

另外,有时候为了使音频 CODEC 芯片与主控制器之间能够更好的同步,会引入另外一个叫做 MCLK 的信号,也叫做主时钟或系统时钟,一般是采样率的 256 倍或 384 倍。


并行采样、交替传输

这里要特别注意帧同步信号,是交替的,也就是说左右声道数据是交替传输的,这里只是交替地来传输左右声道数据,并不是说采样时是交替采样的,采样时,并不会用到I2S,别搞混了,I2S是传输音频数据时用的协议。

采样与传输的区别

采样过程:左右声道的 ADC(模数转换器)同时采样模拟信号(例如麦克风的左右声道输入),并将其转换为数字信号。

传输过程:转换后的数字信号通过 I2S 总线交替传输。例如,一个采样周期内:

LRCK = 高,发送左声道的 32 位数据;

LRCK = 低,发送右声道的 32 位数据。 因此,虽然数据在总线上交替传输,但实际采样是并行的,不会导致左右声道时间差。

为什么需要交替传输?

硬件简化:通过时分复用,I2S 只需一根数据线即可传输多声道数据,减少引脚占用(对比 SPI 需要 MOSI+MISO 两根数据线)。

时序对齐:LRCK 时钟确保接收端能正确区分左右声道,避免数据混淆。

与其他传输方式的对比

协议传输方式数据线数量示例场景
I2S时分复用,交替传输1 根(SD)+ 时钟线立体声音频传输(如 WM8960 芯片)
SPI全双工,独立数据线2 根(MOSI+MISO)高速数据传输(如 SD 卡读写)
PCM同步传输,但无左右声道区分1 根(+ 时钟线)单声道或未区分左右的音频

总结

I2S 的左右声道是并行采样、交替传输的。这种设计既保证了左右声道的时间同步,又通过时分复用简化了硬件设计。在实际应用中(如 WM8960 芯片),这一机制使得立体声数据能高效、准确地传输,同时兼容低功耗需求。


I2S 支持全双工和半双工通信模式。

全双工模式下,音频数据在设备之间通过两条数据线同时进行发送和接收。例如,在一些具有独立发送和接收通道的音频设备中,可利用 I2S 的全双工特性,同时进行音频的录制和播放,互不干扰。

半双工模式下,音频数据在设备之间通过一条数据线传输,同一时刻仅能接收或仅能发送。比如在某些简单的音频传输场景中,只需要单向传输音频数据,就可以配置 I2S 为半双工模式,节省硬件资源。

全双工与半双工模式的核心区别主要体现在数据传输方向、硬件需求、应用场景等方面,具体如下:

一、数据传输方向

模式传输特性示例
全双工支持同时双向传输数据,发送端和接收端可在同一时间各自传输音频流。录音时同时播放背景音乐:麦克风通过 I2S 发送音频到芯片,芯片同时通过 I2S 向耳机发送播放数据。
半双工同一时间仅能单向传输数据(要么发送,要么接收),需通过切换方向实现双向通信。简单的语音播放设备:先通过 I2S 接收存储音频数据,再切换方向发送数据到扬声器播放,无法同时录音。

二、硬件接口与数据线需求

模式接口配置数据线数量优势
全双工需独立的发送(Tx)和接收(Rx)数据线,通常包括:
- 发送数据引脚(SDOUT)
- 接收数据引脚(SDIN)
至少2 条数据传输线(SDOUT + SDIN),配合时钟线(BCLK、LRCK)使用。支持实时双向通信,适合复杂音频系统(如录音 + 播放同步)。
半双工发送和接收共用一条数据线(SD),通过控制信号或协议层切换传输方向。仅需1 条数据传输线(SD),节省硬件引脚和 PCB 布线资源。适合单向或分时双向传输场景,降低硬件成本。

三、时钟与协议复杂度

模式时钟同步协议复杂度
全双工发送和接收通常使用独立的时钟源(或同一时钟的分频),需确保收发时钟同步,避免数据错位。协议设计更复杂,需处理双向时钟同步和数据流控制,避免数据冲突。
半双工收发共用同一时钟源,无需额外处理双向时钟同步,方向切换时只需控制数据引脚的读写状态。协议简单,方向切换通过软件或硬件控制(如 GPIO 引脚配置),适合低功耗场景。

四、应用场景对比

模式典型应用原因
全双工- 手机、录音笔(同时录音和播放)
- 音频接口设备(如声卡,支持输入输出同步)
- 蓝牙音箱(接收蓝牙信号的同时播放本地音频)
需要实时双向音频交互,全双工模式可保证低延迟和同步性。
半双工- 简单 MP3 播放器(仅需从存储设备读取数据并播放)
- 单通道语音对讲机(收发分时进行)
- 低成本嵌入式设备(如智能家电的音频提示)
对实时性要求不高,半双工可减少硬件成本,简化电路设计。

五、总结:如何选择模式?

选全双工:若需要同时进行音频输入和输出(如边录边播),且硬件资源充足(支持多引脚),优先选择全双工模式,以保证功能完整性和实时性。

选半双工:若应用场景为单向传输或分时双向传输(如仅播放或仅录音),且需节省成本和引脚资源,半双工模式更具性价比,同时简化开发难度。

实际应用中,I2S 的模式配置通常由芯片(如 WM8960)的寄存器或硬件引脚决定,可根据具体需求灵活选择。


图 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 所示:

再附一个I2S连接的示例图:

更多待补充。

STM32进行I2S配置的简单示例 使用标准库

以下是基于 STM32 标准外设库的 I2S 配置示例,以 STM32F4 系列为例,展示如何配置 I2S3 作为主发送器模式,适用于连接外部 DAC 播放音频。

配置步骤说明

  1. 硬件连接(以 STM32F4 为例):

    • I2S_CK (SCK) - 连接到外部 DAC 的时钟输入
    • I2S_WS (LRCK) - 连接到外部 DAC 的左右声道选择
    • I2S_SD (SD) - 连接到外部 DAC 的数据输入
    • I2S_MCK (MCK) - 连接到外部 DAC 的主时钟(可选,部分 DAC 需要)
  2. 关键配置参数

    • 标准模式:飞利浦标准 (I2S_STANDARD_PHILIPS)
    • 数据格式:16 位 (I2S_DATAFORMAT_16B)
    • 采样率:44.1kHz
    • 主时钟输出:启用
    • 时钟极性:低电平 (I2S_CPOL_LOW)

代码示例

#include "stm32f4xx.h"

/* I2S3初始化函数 */
void I2S3_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    I2S_InitTypeDef I2S_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);  /* 使能SPI3时钟 */
    
    /* 配置I2S3 GPIO: SCK, WS, SD, MCK */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE);
    
    /* PA4: I2S3_WS */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI3);
    
    /* PB3: I2S3_CK */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI3);
    
    /* PC12: I2S3_SD */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SPI3);
    
    /* PA7: I2S3_MCK (如果需要) */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI3);
    
    /* 禁用SPI3外设,以便配置I2S */
    SPI_I2S_DeInit(SPI3);
    
    /* I2S3配置 */
    I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;             /* 主发送模式 */
    I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;      /* 飞利浦标准 */
    I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;       /* 16位数据格式 */
    I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;    /* 启用MCLK输出 */
    I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_44k;         /* 44.1kHz采样率 */
    I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;                   /* 时钟极性低 */
    I2S_Init(SPI3, &I2S_InitStructure);
    
    /* 启用I2S3 */
    I2S_Cmd(SPI3, ENABLE);
}

/* 发送音频数据函数 */
void I2S3_SendData(uint16_t* data, uint32_t size)
{
    uint32_t i;
    
    for (i = 0; i < size; i++)
    {
        /* 等待发送缓冲区为空 */
        while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
        
        /* 发送数据 */
        SPI_I2S_SendData(SPI3, data[i]);
    }
}

/* 主函数示例 */
int main(void)
{
    /* 系统初始化 */
    SystemInit();
    
    /* 配置I2S3 */
    I2S3_Init();
    
    /* 假设audio_buffer包含音频数据 */
    uint16_t audio_buffer[1024];
    
    while (1)
    {
        /* 发送音频数据 */
        I2S3_SendData(audio_buffer, 1024);
        
        /* 延时或其他处理 */
    }
}

注意事项

  • 时钟配置

    • 示例中使用默认时钟配置,实际应用中可能需要调整 PLL 以获得准确的 44.1kHz 采样率
    • 对于更高精度的音频,建议使用外部晶振作为 I2S 时钟源
  • DMA 传输

    • 示例中使用轮询方式发送数据,实际应用中建议配置 DMA 以提高效率
    • 配置 DMA 时需要同时启用 SPI3 的 DMA 请求和相应的 DMA 通道
  • 数据格式

    • 飞利浦标准下,LRCK 信号切换时刻决定左右声道数据
    • 16 位数据格式下,每个声道数据占 16 位,左右声道交替发送
  • 错误处理

    • 实际应用中应添加错误处理代码,如溢出检测、总线错误处理等

如需更完整的实现(如 DMA 配置、中断处理、立体声数据格式等),可以进一步扩展上述代码。

SAI接口简介

音频 CODEC 支持 I2S 协议,那么主控制器也必须支持 I2S 协议,大家如果学过STM32F4/F7/H7 的话应该知道 SAI 接口,因为在 STM32 中就是通过 SAI 接口来连接音频CODEC。

SAI是STM32的新片子引进的音频外设,S就是Serial,A就是Audio,I就是Interface,串行音频接口,还是挺好记的。究竟新在哪里,就是支持音频各种了,但是实际上用到的主要还是I2S。

  1. 定义:SAI是STM32微控制器中的一种更灵活的音频接口,它不仅支持传统I2S协议,还能够支持其他音频传输协议,如AC97、TDM(Time Division Multiplexing)等,以及与I2S类似的协议但具有不同的时序或特性。

  2. 特点:相比I2S,SAI提供了更多的配置选项和更宽泛的功能集,包括不同的时钟模式、数据长度和通道数等。SAI在STM32中通常分为多个独立的单元,如SAI1、SAI2等,每个单元可能支持多个音频串行接口。

  3. 应用:SAI接口因其灵活性和多功能性,适用于需要处理复杂音频流、多声道音频或与不同音频标准兼容的场合,比如专业音频设备、高清音频系统、车载娱乐系统等。

SAI 接口(串行音频接口)适用于许多立体声或单声道应用。例如,它可配置为支持 I2S 标准、LSB 或 MSB 对齐、PCM/DSP、TDM 和 AC’97 等协议。 将音频模块配置为发送器时,SAI 接口可提供 SPDIF 输出。SAI通过两个完全独立的音频子模块来实现这种灵活性和可配置性。 每个模块都有自己的时钟发生器和 I/O 线控制器。SAI 可以配置为主模式或配置为从模式。音频子模块既可作为接收器,又可作为发送器; 既可与另一模块同步,又可以不同步。SAI 可与其它 SAI 相连接来同步运行。

比如,STM32H750的SAI总线接口有4个专用引脚信号:

(1) SAI_SCK_x: 位时钟,数字音频的每一位数据都对应有一个CK脉冲,它的频率为:2*采样频率*量化位数,2代表左右两个通道数据。

(2) SAI_MCLK_x: 主时钟,可用做外部解码器的参考时钟,帧同步与主时钟之间的频率比为固定值256或512,。

(3) SAI_SD_x : 音频模块数据线,用于发送或接收两个时分复用的数据通道上的数据。

(4) SAI_FS_x: 音频模块帧同步线,表明当前传输数据的声道,不同标准有不同的定义,频率等于采样频率(F(S))。

更多参考:

38. SAI—音频播放与录音输入 — [野火]STM32 HAL库开发实战指南——基于H750_Pro_V 文档

I.MX6ULL 也提供了一个叫做 SAI 的外设

I.MX6ULL SAI 是一个全双工、支持帧同步的串行接口,支持 I2SAC97TDM 和音频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 的信号线

ALSA框架

参考:

【音视频 | ALSA】ALSA是什么?ALSA框架详细介绍-CSDN博客

ALSA,全称Advanced Linux Sound Architecture(高级Linux音频体系结构),是Linux操作系统上用于管理音频和音频设备的软件架构,为Linux操作系统提供音频和MIDI功能。它提供了一个标准的接口,用于应用程序与硬件之间的音频通信,以及音频设备之间的通信。
ALSA具有以下重要特征:

高效支持所有类型的音频接口,从消费类声卡到专业多声道音频接口。
完全模块化的声音驱动程序。
SMP和线程安全设计。
用户空间库(alsa-lib),用于简化应用程序编程并提供更高级别的功能。
支持较旧的开放声音系统(OSS)API,为大多数OSS程序提供二进制兼容性。
ALSA是根据GPL(GNU通用公共许可证)和LGPL(GNU较宽松通用公共许可)发布的。ALSA驱动程序代码包含在Linux内核2.6中。
如果还有其他需要了解的,可以查看ALSA项目的官网:AlsaProject
ALSA项目在github的开源地址(不包含驱动代码):Advanced Linux Sound Architecture (ALSA) project · GitHub


ALSA框架介绍
ALSA架构主要有两方面组成:
1、Linux内核空间的ALSA驱动,在Linux内核2.6之后,ALSA驱动代码已经集成到Linux源码中。
2、Linux用户空间的ALSA库和程序:alsa-lib、alsa-utils、alsa-tools、alsa-firmware、alsa-plugins、alsa-oss、pyalsa。


ALSA驱动 - 内核空间
ALSA驱动程序包含在内核空间中运行的ALSA组件,在Linux内核2.6之后,ALSA驱动代码已经集成到Linux源码中,ALSA驱动代码在Linux内核源码的sound 目录里。在编译内核时,可以选择将alsa驱动单独编译为模块,一般会有如下ko:snd-hwdep.ko、snd-pcm.ko、snd-rawmidi.ko、snd-timer.ko snd-usb-audio.ko、snd-usbmidi-lib.ko、snd.ko、soundcore.ko。

在Linux内核安装完ALSA驱动后,会多出两个目录:/proc/asound/目录、/dev/snd/目录。

有关ALSA驱动的更多内容可以看:ALSA Driver Documentation - AlsaProject


ALSA库、程序 - 用户空间

ALSA库和程序主要:alsa-lib、alsa-utils、alsa-tools、alsa-firmware、alsa-plugins、alsa-oss、pyalsa。
这些都是都是工作在Linux用户空间的,可以在ALSA官网下载:Download - AlsaProject

alsa-lib
alsa-lib 包含开发人员编译alsa应用程序所使用的用户空间库。
有关alsa-lib的使用可以参照:https://www.alsa-project.org/alsa-doc/alsa-lib/

alsa-utils
alsa-utils 包含各种通用的alsa命令行工具,如amixer、aplay、alsaconf等。
alsa-utils是一组小型且功能强大的应用程序,旨在允许用户控制ALSA系统的各个部分:
1、alsactl 应用程序是保存设备设置的一种方式。
2、amixer 应用程序是一个命令行应用程序,允许对设备音量和声音控制进行调整。
3、alsamixer 应用程序是amixer的ncurses版本。
4、acconnect 和aseqview 应用程序用于建立MIDI连接和查看连接端口列表。
5、aplay和arecord 应用程序用于命令行播放和记录多种文件类型,包括原始、波形和aiff,所有采样率、位深度和ALSA库已知的通道计数。

alsa-tools
alsa-tools 包含各种更模糊的工具和加载器。

alsa-firmware
alsa-firmware 包含各种第三方产品的二进制驱动程序。

alsa-plugins
alsa-plugins 包含各种alsa需求的插件(例如Jack)。

alsa-oss
alsa-oss 包含oss兼容层。

pyalsa
pyalsa 包含ALSA的Python绑定。

需要了解更多ALSA相关文档可以参考:Documentation - AlsaProject

总的来说,ALSA是Linux系统中的一个关键音频框架,提供了强大的音频处理功能,并为开发者和用户提供了一种一致的方式来处理音频设备和数据。它在Linux发行版中内置,因此几乎所有基于Linux的系统都可以受益于其音频处理能力。如果开发过程中,有不清楚的,多到ALSA官网查看。

硬件原理图分析

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 在使用的时候需要进行配置,配置接口为 I2CV2.4 以前版本连接到了I.MX6ULL 的 I2C2 上,V2.4 及以后版本连接到了 I2C1 上。

实验

具体实验过程直接参考正点原子驱动开发手册。

……

编译完成以后使用新的 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 这两个东西。

具体移植和使用过程直接参考正点原子驱动开发手册。

更多待补充。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值