R-Car 音频硬件架构概览:SSI、SCU、SRC、DVC 模块功能解析与数据流路径
做音频驱动适配,第一件事不是看代码,而是把芯片的音频数据路径摸清楚。R-Car 的音频子系统,说白了就是一条从外部数字音频接口到最终扬声器/耳机的流水线。这条流水线上有四个关键模块:SSI、SCU、SRC、DVC。我当年第一次接触 R-Car 时,光看数据手册就被这些缩写绕晕了。今天咱们一个一个拆开讲。
1.1 整体数据流:从录音到放音
先看一张整体框图,把四个模块的位置和关系搞清楚。
从图上你能看到,数据从外部 CODEC 进来,先经过 SSI 变成内部数字信号,然后可以选择走 SRC 做采样率转换,或者走 DVC 做音量调节,最后统一由 SCU 路由到内存。反过来放音就是逆过程。嗯,这里要注意:SCU 是整个子系统的中枢,所有音频数据流都要经过它。
1.2 SSI:串行音频接口
SSI(Synchronous Serial Interface)是 R-Car 与外部 CODEC 通信的物理层。说白了,它就是一组 I2S 或 TDM 接口的控制器。
| 特性 | 说明 |
|---|---|
| 接口标准 | I2S、左对齐、右对齐、TDM(最多 16 通道) |
| 数据位宽 | 8/16/18/20/24/32 bit |
| 时钟源 | 内部 PLL 或外部 MCLK |
| DMA 支持 | 每个 SSI 通道独立 DMA 请求 |
| 多路复用 | 支持多 SSI 通道同步 |
我在项目中遇到过一个问题:某个平台用 8 通道 TDM 录音,结果 SSI 的时钟配置错了,导致只有左声道有数据。后来查了三天才发现是 SSI 的时隙掩码没设对。你想想看,8 个通道的 TDM 帧,每个通道的位时钟周期必须精确对齐,差一个 bit 都不行。
1.3 SRC:采样率转换器
SRC(Sampling Rate Converter)解决的是采样率不匹配的问题。比如你的录音设备是 48kHz,但系统需要 44.1kHz 的音频流,这时候 SRC 就派上用场了。
R-Car 的 SRC 模块支持以下转换比例:
- 整数倍转换:1:2、1:4、2:1、4:1
- 分数倍转换:任意比例,内部通过多相滤波器实现
- 直通模式:输入输出采样率相同,旁路滤波器
我曾经踩过一个坑:SRC 的滤波器系数加载顺序搞反了,导致转换后的音频有高频噪声。后来我仔细看了数据手册,发现 SRC 的系数表是按 相位索引 排列的,不是按频率索引。这个细节很容易被忽略。
1.4 DVC:数字音量控制器
DVC(Digital Volume Control)负责音频信号的增益调节。它位于数据路径上,可以独立控制每个通道的音量。
| 参数 | 范围 |
|---|---|
| 增益范围 | -119.5 dB 到 +24 dB |
| 步进 | 0.5 dB |
| 通道数 | 最多 8 通道独立控制 |
| 渐变支持 | 硬件自动渐变(防止爆音) |
DVC 有一个很实用的功能:零交叉检测。当音量变化时,DVC 会等到信号过零点才切换增益,避免产生咔嗒声。我建议你在驱动中默认开启这个功能,除非有特殊需求。
另外,DVC 的渐变速率是可以配置的。我记得有一次客户反馈音量调节时有明显的阶梯感,后来发现是渐变速率设得太快了,每步只用了 1ms。改成 10ms 后,问题就解决了。
1.5 SCU:音频路由与混音核心
SCU(Sound Control Unit)是整个音频子系统的交通枢纽。它负责:
- 数据路由:将 SSI、SRC、DVC 的数据连接到内存或彼此之间
- 混音:支持多路音频流的叠加
- 格式转换:比如 16bit 转 24bit,或者左右声道交换
- DMA 管理:生成 DMA 请求,将数据搬运到 DDR
SCU 内部有多个 音频通道,每个通道可以独立配置数据源和目的地。我习惯把 SCU 想象成一个 音频交换机,你只需要告诉它从哪个端口收数据,发到哪个端口去。
1.6 典型数据流路径配置
下面是一个实际的放音路径配置示例,我在 R-Car H3 上验证过:
// 放音路径:DDR → SCU → SRC → SSI → CODEC
// 1. 配置 SCU 通道 0 从 DDR 读取 48kHz 16bit 立体声数据
scu_channel_config(0, SCU_SRC_DDR, 48000, 16, 2);
// 2. 配置 SRC 将 48kHz 转换为 44.1kHz
src_config(SRC_UNIT_0, 48000, 44100, SRC_QUALITY_HIGH);
// 3. 配置 SSI 以 I2S 格式输出 44.1kHz 数据
ssi_config(SSI_0, SSI_MODE_I2S, 44100, 16, 2);
// 4. 连接 SCU 输出到 SRC 输入,SRC 输出到 SSI 输入
scu_connect(SCU_CH_0, SRC_UNIT_0);
src_connect(SRC_UNIT_0, SSI_0);
// 5. 启动 DMA 传输
dma_start(SCU_CH_0);
这个配置看起来简单,但实际调试时要注意每个模块的 时钟域。SSI 的时钟来自外部 CODEC 或内部 PLL,SRC 有自己的内部时钟,SCU 则挂在系统总线上。如果时钟不同步,数据就会出错。
1.7 避坑指南
最后分享几个我在项目中踩过的坑:
- SSI 的 FIFO 深度:R-Car 的 SSI FIFO 只有 8 级,如果 DMA 响应不及时,很容易溢出。我建议把 DMA 的 burst 长度设为 4,并且开启 FIFO 中断作为备份。
- SRC 的初始化顺序:必须先配置 SRC 的输入采样率,再配置输出采样率,最后使能。顺序反了会导致 SRC 锁相环无法锁定。
- DVC 的渐变中断:DVC 渐变完成后会触发中断,但中断标志位需要软件清除。我曾经忘了清标志,导致中断一直触发,CPU 占用率飙升。
- SCU 的通道数限制:不同 R-Car 型号的 SCU 通道数不同,H3 有 16 个,M3 只有 8 个。写驱动时要做平台适配,不要硬编码。
好了,这一章的内容就是这些。音频硬件架构是驱动开发的地基,把 SSI、SRC、DVC、SCU 这四个模块的关系理清楚,后面写驱动就会顺畅很多。