3、数字音频路由:数字音频接口(I2S、TDM、PDM)、数字交叉点开关、数字路由器的设计
好,咱们进入数字音频路由这一章。说实话,这部分内容是我个人觉得最“硬核”的。模拟音频路由你还能靠耳朵听,数字路由一旦出问题,示波器都未必能一眼看出毛病。我刚开始做数字音频系统时,就吃过不少亏。
3.1 数字音频接口:I2S、TDM、PDM
数字音频的世界里,接口就是“语言”。设备之间要能对话,得说同一种话。目前主流的数字音频接口有三种:I2S、TDM 和 PDM。它们各有各的脾气。
3.1.1 I2S 接口
I2S 是飞利浦公司定义的,说白了就是“立体声数字音频的标准总线”。它只有三条线:
- BCLK(位时钟):每个时钟周期传输一个数据位。
- LRCLK(左右声道时钟):用来区分左声道还是右声道。
- SDATA(串行数据):音频数据就在这根线上跑。
嗯,这里要注意:I2S 的 LRCLK 频率等于采样率。比如 48kHz 采样,LRCLK 就是 48kHz。BCLK 呢?如果是 24 位数据,立体声,BCLK = 48k × 24 × 2 = 2.304MHz。
核心要点:I2S 的数据在 LRCLK 变化后的第二个 BCLK 上升沿开始传输。这是飞利浦标准,但有些芯片厂商会搞“左对齐”或“右对齐”,千万别搞混。
我在项目中遇到过一件事:一个音频编解码芯片死活不出声。查了半天,发现是 I2S 的相位搞反了。芯片要求数据在 BCLK 下降沿采样,我默认用了上升沿。嗯,这种坑,踩一次就记住了。
3.1.2 TDM 接口
TDM 是 I2S 的“升级版”。你想想看,I2S 只能传两个声道。那如果我要做 8 声道、16 声道呢?用 I2S 就得拉好几组线,太浪费了。
TDM 的思路很简单:把时间片分给不同的声道。它也是三条线:
- BCLK:位时钟,频率更高。
- FSYNC(帧同步):相当于 I2S 的 LRCLK,但频率等于采样率。
- SDATA:数据线,但一个帧里塞了多个声道的数据。
举个例子:8 声道、24 位、48kHz 采样。BCLK 需要 48k × 24 × 8 = 9.216MHz。每个 FSYNC 周期内,依次传输声道 0、声道 1……声道 7 的数据。
个人经验:设计 TDM 总线时,一定要留够 BCLK 的余量。我曾经为了省功耗,把 BCLK 压到刚好够用,结果线缆一长,信号抖动导致数据错位。后来我习惯把 BCLK 频率提高 10%~20%,多出来的 slot 做填充或校验。
3.1.3 PDM 接口
PDM 是另一种思路。它不传多 bit 数据,而是传“1 位密度流”。说白了,就是用高速的 1 位信号来代表模拟音频。
PDM 只有两条线:
- CLK:时钟,频率很高(典型值 2.4MHz 或 3.2MHz)。
- DATA:数据线,每个时钟周期输出 1 位。
PDM 最大的优势是简单。MEMS 麦克风几乎都用 PDM 接口。但缺点也很明显:
- 数据量巨大(1 位 × 高频时钟)。
- 需要后续做“抽取滤波”才能变成 PCM 数据。
避坑指南:我曾经在一个项目里直接用 MCU 的 GPIO 模拟 PDM 时钟,结果发现时钟抖动太大,导致 SNR 下降 10dB。后来老老实实用了专用的 PDM 时钟发生器。PDM 对时钟质量很敏感,别省这个钱。
3.2 数字交叉点开关
数字交叉点开关,你可以把它想象成一个“数字音频的交换机”。输入有 N 路,输出有 M 路,你可以任意把某一路输入切换到某一路输出。
常见的芯片有:
| 型号 | 通道数 | 最大数据速率 | 典型应用 |
|---|---|---|---|
| ADAU1445 | 8×8 | 192kHz/24bit | 汽车音响路由 |
| CS8427 | 4×4 | 96kHz/24bit | 专业音频矩阵 |
| FPGA 实现 | 任意 | 取决于设计 | 定制化系统 |
设计数字交叉点开关时,有几个关键点:
- 时钟域同步:输入和输出可能来自不同的时钟域。必须做异步 FIFO 或时钟同步处理。
- 无杂音切换:切换瞬间不能有“咔哒”声。我习惯在切换时做“过零检测”——只在数据过零时切换。
- 路由表管理:用寄存器或 RAM 存储路由配置,支持动态更新。
核心设计思路:数字交叉点开关的本质是一个“多路选择器阵列”。每个输出通道对应一个 MUX,MUX 的选通信号由路由表控制。用 FPGA 实现时,就是一个简单的 case 语句或 LUT。
3.3 数字路由器的设计
数字路由器比交叉点开关更“智能”。它不仅能做点对点路由,还能做广播、组播、优先级管理。
我设计过一个 16×16 的数字音频路由器,用在会议系统里。它的架构是这样的:
// 伪代码:数字路由器核心逻辑
module audio_router (
input wire [15:0] [23:0] data_in, // 16路输入,24位数据
input wire [15:0] [4:0] route_cfg, // 路由配置,每路输出选择哪路输入
output reg [15:0] [23:0] data_out // 16路输出
);
always @(*) begin
for (int i = 0; i < 16; i++) begin
data_out[i] = data_in[route_cfg[i]];
end
end
endmodule
嗯,代码看起来简单,但实际工程中要考虑很多:
- 延迟一致性:所有通道的延迟必须一致。如果某路走 FIFO,另一路走直通,相位就乱了。
- 错误处理:如果路由配置指向一个不存在的输入,怎么办?我习惯加一个“静音输出”的默认状态。
- 热插拔支持:输入信号突然消失,输出不能产生噪声。需要做“信号丢失检测”和“自动静音”。
我的设计习惯:在路由器输入端加一个“数据有效”标志位。只有标志位有效时,数据才被路由。这样能避免很多莫名其妙的噪声问题。
3.4 实战:一个 8 通道数字音频路由系统
最后,咱们看一个完整的例子。假设我们要设计一个 8 通道数字音频路由系统:
需求:
- 8 路 I2S 输入(每路立体声,共 16 声道)
- 8 路 I2S 输出
- 支持任意输入到任意输出的路由
- 采样率 48kHz,24 位
方案:
- 用 FPGA 做核心处理。
- 输入侧:8 个 I2S 接收器,将串行数据转成并行。
- 内部:一个 16×16 的数字交叉点开关。
- 输出侧:8 个 I2S 发送器,将并行数据转成串行。
- 控制接口:SPI 或 I2C,用来配置路由表。
关键参数计算:
| 参数 | 值 | 说明 |
|---|---|---|
| 采样率 | 48kHz | 标准音频采样 |
| 位深 | 24 bit | 专业音频标准 |
| 总声道数 | 16 | 8路立体声 |
| 内部数据速率 | 48k × 24 × 16 = 18.432 Mbps | FPGA 内部总线速率 |
| 路由表大小 | 16 × 4 bit = 64 bit | 每个输出需要 4 bit 选择输入 |
我曾经踩过的坑:第一次做这个系统时,我忘了考虑 I2S 的“字长”问题。输入是 24 位,但有些输出设备只支持 16 位。结果高 8 位被截断,声音变得很“刺耳”。后来我在路由器里加了“位宽转换”模块,支持 16/20/24 位自适应。
好了,数字音频路由这部分就讲到这里。说白了,核心就是三件事:选对接口、做好切换、管好时钟。下一章咱们聊聊更高级的话题——数字音频处理器的设计。