应用数学基础: 香农-奈奎斯特采样定理
角速度倒数是频率;
采样一段最大角速度为ω的信息,理想状态下需要2ω的速度才能完全采样,否则就会产生混叠Aliasing(即较高频被对称采样到较低频段),而限制于前后端,一般还需要大于该角速度保证得到最基本的采样点。
例如采样一段 20 to 22,000 Hz, 低通滤波20Hz以下后,还需要22Khz 的两倍即 44Hz,外加容错一些速率。
另外经典的44.1 kHz兼容 PAL 和 NTSC 制式视频
Ps. 采样频率和声音频率/声波不是一个东西,一个是采样点间隔,一个是波。
公式:
奈奎斯特频率数学表达式: f_Nyquist > 2 * f_max
混叠频率公式计算:f_alias = |f_signal - n * f_s| (n为整数),通常会找到一个在 0 到 f_s/2 之间的频率。例如,用 3Hz 采样 2Hz 信号,会产生一个 |2 - 3| = 1Hz 的混叠信号。
另外要求无限陡峭的理想重建滤波器(高低/带通滤波器)无法做到理想实现(吉布斯现象等),所以需要工程师引入安全裕量,即使用更高一些的采样频率。
Windows10/11音频架构堆栈图
图源巨硬
Android 音频架构
图源谷歌
图源einfochips
图源 zyuanyun
AudioTrack音频输出/AudioRecord音频输入采集/AudioSystem控制
AudioFlinger是安卓系统的混音架构,软件上的多路音频经过该框架后,进行混音,转换为单独的数据输出到ALSA驱动,也是现代操作系统音频管理的案例。
安卓底层是Linux的ALSA体系(Advanced Linux Sound Architecture)
ALSA application 测试工具ALSA utils如aplay、arecord等二进制可执行程序
ALSA lib 提供操作驱动的函数库
ALSA driver 底层驱动
其中为了解决复用性问题, 内核引入了ASoC架构
图源_kerneler
目录
- kernel
- sound
- core 核心中间层-ALSA核心
- soc 芯片厂商层-SOC驱动
- 总多SOC厂商驱动
- codecs 外设厂商驱动
- arm 芯片架构arm驱动
- mips 芯片架构mips驱动
- usb 连接方式:usb驱动
- pci 连接方式:pci驱动
- 还有很多
- sound
ASOC(Alsa System on Chip)架构
DMA负责SOC内数据搬运
I2S是一种DAI
AFIx也是一种DAI
DAC数模转换
SPK/HP 模拟信号设备,如耳机/扬声器
架构分层(以RK芯片为栗子)
Machine 机器设备: 搭配RK3588芯片平台的某款量产上市用户终端产品,由终端厂商编写
Platform 平台架构: RK3588,负责DMA和I2S等控制,由SOC厂商编写
Codec 编解码器: 由Codec厂商编写,最终实现数模转化输出音频模拟信号波形。TI芯片有 德州仪器-音频编解码器 系列产品
Machine 配置
一般只是写个设备树:
将Platform和Codec通讯打通即可
当然需要定制化的话可以修改驱动代码。如果是GKI则需要留意修改范围。
更多的还是在调优方面
系统中可能有多个Codecs
以下图源NXP AN12202
I2S (Inter-IC Sound) 引脚时序图
图源NXP
TDM (Time-Division Multiplexed)
PCM (Pulse Code Modulation) 引脚时序图
SAI (Synchronous Audio Interface) 架构图及其引脚时序图
这里介绍两个非常简单的Codec芯片供参考:
德州仪器PCM3008/新款为TAC5142
官网:https://www.ti.com/product/PCM3008
控制接口:GPIO {de_Emphasis控制dem0/dem1 电源控制pdad/pdda}
驱动代码 kernel/sound/soc/codecs/pcm3008.c
德州仪器pcm3060芯片
介绍:24-bit Asynchronous Stereo Audio Codec with 96/192kHz sampling rate
音频接口:I2S, LR
控制接口:可选iic/spi
框图:
驱动:
-
/sound/soc/codecs/pcm3060.c
-
kernel/sound/soc/codecs/pcm3060-i2c.c
-
kernel/sound/soc/codecs/pcm3060-spi.c
-
-
/Documentation/devicetree/bindings/sound/pcm3060.txt
也可以在这里下载:https://www.ti.com.cn/tool/cn/PCM3XXX-DRIVERS
硬件连接图:
还有人用树莓派Pico+PCM3060做了48kHz/16-bit DAC耳机:https://github.com/ploopyco/headphones
Platform 驱动
# platform probe:
struct platform_driver
Platform-Dai
介绍一个概念 Digital Audio Interface (DAI)
DAI根据硬件连接位置区分为 SOC侧 和 CODEC侧 的DAI
soc dai驱动对应N个 I2S/PCM 数字音频接口。用来连接platform和machine。
如RK芯片的SOC DAI驱动有
- kernel/sound/soc/rockchip/
- rockchip_i2s.c
- rockchip_sai.c
- 等等
struct snd_soc_dai_driver {.ops = struct snd_soc_dai_ops
}
devm_snd_soc_register_component(&pdev->dev,&rockchip_sai_component,dai, 1);
snd_soc_dai_ops定义了DAI的能力集及其操作,即定义多个rates/fmt支持及其切换函数
至于网上说的 snd_soc_register_dais实际上是:
devm_snd_soc_register_component-》snd_soc_register_component-》snd_soc_add_component-》snd_soc_register_dais
Codec驱动
struct snd_soc_codec
一个Codec一般支持多个dai接口,如pcm3060支持 I2S/LR 两种,2个数字输入,2个数字输出,共4个数字音频接口
Codec-DAI接口
可以是CPU侧的DAI(I2S/PDM), 也可以是Codec侧的DAI(AFIx)
如 sound/soc/codecs/pcm3060.c
struct snd_soc_dai_driver {[多组]= {.ops = &struct snd_soc_dai_ops},
}
snd_soc_dai_ops定义了DAI的能力集及其操作,即定义多个rates/fmt支持及其切换函数
Codec-控制接口/DAPM动态电源管理
如 I2C/SPI/UART/GPIO等,是SOC控制Codec的物理通路
如ES8388是一个带IIC的Codec芯片,所以IIC就是它的控制接口。
如Ti PCM3070是一个带IIC/SPI的Codec芯片,那么它有两个可选的控制接口,我们需要根据Machice选用对应的驱动IIC/SPI。
ES8388/PCM3070驱动需要注册IIC总线到Linux内核。
Kcontrol是mixer混音/mux多路开关/控制音量/调节器等等,最终作用到codec芯片的寄存器
DAPM动态电源管理
static const struct snd_soc_component_driver pcm3060_soc_comp_driver = {# Kcontrol 寄存器控制.controls = pcm3060_dapm_controls, #结构体struct snd_kcontrol_new .num_controls = ARRAY_SIZE(pcm3060_dapm_controls),# dapm 动态音频电源管理.dapm_widgets = pcm3060_dapm_widgets,.num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets),.dapm_routes = pcm3060_dapm_map,.num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map),.endianness = 1,
};devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,pcm3060_dai,ARRAY_SIZE(pcm3060_dai));
Codec芯片原理解析
还是用PCM3060做栗子
模拟音频输入端:
VinL/VinR -> Single-Ended to Diff 单端转差分 -》 SDM积分微分ΔΣ调制/模数转换 -> 带数字高通滤波器HPF的降采样 -> Audio Interface and Clock Control 数字芯片 => IIS等DAI接口
数字音频输出端:
VoutR-/+和VoutL-/+ <- 带buff的低通滤波器LPF <- 多级数模转换/ΔΣ调制 <- 数字插值 <- 数字芯片 <- IIS等DAI接口
Common and Reference 提供电源控制和参考
Mode Control 提供模式切换控制等
关于ΔΣ调制器:
- 精度音频ADC几乎都采用ΔΣ调制器,但其需要差分输入来匹配ΔΣ调制器对共模噪声和高线性度的要求。
- 噪声传导有两种模式:
2.1 差模传导,电流抵消总和为0。
2.2 共模传导,又称非对称噪声或线路对地的噪声,经杂散电容等泄漏的噪声电流经由大地返回电源线线的噪声
计算 see: https://www.eet-china.com/mp/a54105.html
总之,噪声电流值相同的情况下,共模传导远大于差模传导
文章末尾
放一篇 RK3588搭配ES8388 Codec芯片的架构分析(作者arnoldlu):
Linux音频(1):alsa架构和RK3588 PCM实例
设备树配置
i2s0_8ch: i2s@fe470000 {compatible = "rockchip,rk3588-i2s-tdm";reg = <0x0 0xfe470000 0x0 0x1000>;interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;clocks = <&cru MCLK_I2S0_8CH_TX>, <&cru MCLK_I2S0_8CH_RX>, <&cru HCLK_I2S0_8CH>;clock-names = "mclk_tx", "mclk_rx", "hclk";assigned-clocks = <&cru CLK_I2S0_8CH_TX_SRC>, <&cru CLK_I2S0_8CH_RX_SRC>;assigned-clock-parents = <&cru PLL_AUPLL>, <&cru PLL_AUPLL>;dmas = <&dmac0 0>, <&dmac0 1>;dma-names = "tx", "rx";power-domains = <&power RK3588_PD_AUDIO>;resets = <&cru SRST_M_I2S0_8CH_TX>, <&cru SRST_M_I2S0_8CH_RX>;reset-names = "tx-m", "rx-m";rockchip,clk-trcm = <1>;pinctrl-names = "default";pinctrl-0 = <&i2s0_lrck&i2s0_sclk&i2s0_sdi0&i2s0_sdi1&i2s0_sdi2&i2s0_sdi3&i2s0_sdo0&i2s0_sdo1&i2s0_sdo2&i2s0_sdo3>;#sound-dai-cells = <0>;status = "disabled";};