4、音频硬件接口:I2S、PDM、TDM接口原理与R329上的配置
做音频处理,绕不开硬件接口。说白了,音频数据怎么从麦克风进到芯片,又怎么从芯片送到喇叭,全靠这些接口在干活。
R329这颗芯片,我用了好几年。它的音频接口挺全的——I2S、PDM、TDM都有。今天咱们就一个一个聊清楚。
4.1 I2S接口:最常用的音频总线
I2S,全称是Inter-IC Sound。这玩意儿是飞利浦在80年代搞出来的,专门用来传数字音频数据。到现在,几乎所有音频芯片都支持它。
4.1.1 I2S的信号线
I2S总线就4根线,不多不少:
- BCLK(位时钟):每个时钟周期传一个bit的数据。采样率越高,BCLK频率也越高。
- LRCK(左右声道时钟):也叫帧时钟。高电平传右声道,低电平传左声道。频率等于采样率。
- SDI/SDO(数据输入/输出):传音频数据的线。
- MCLK(主时钟):有些系统需要,有些不需要。R329内部可以自己生成。
4.1.2 I2S的数据格式
I2S标准格式有个特点:数据比LRCK晚一个BCLK周期。为什么?为了兼容性。早期的DAC芯片需要这个延迟来准备数据。
不过现在很多芯片也支持左对齐、右对齐格式。R329的I2S控制器支持三种模式:
- 标准I2S格式(飞利浦格式)
- 左对齐格式(MSB对齐)
- 右对齐格式(LSB对齐)
4.1.3 R329上的I2S配置
R329有3个I2S控制器。每个控制器可以独立配置采样率、位深、通道数。
下面是一个典型的配置代码,初始化I2S0用于录音:
#include <sunxi_hal_i2s.h>
i2s_config_t i2s_cfg = {
.sample_rate = 16000, // 16kHz采样率
.channel_num = 2, // 双声道
.data_width = I2S_DATA_WIDTH_16BIT, // 16位精度
.mode = I2S_MODE_MASTER, // R329做主设备
.format = I2S_FORMAT_STANDARD, // 标准I2S格式
.mclk_freq = 0, // 使用内部MCLK
};
hal_i2s_init(I2S_DEVICE_0, &i2s_cfg);
hal_i2s_start(I2S_DEVICE_0);
4.2 PDM接口:数字麦克风的专属通道
PDM,脉冲密度调制。这玩意儿跟I2S不一样,它只传1bit的数据,但采样率极高。
4.2.1 PDM的原理
你想想看,传统的ADC是把模拟信号转成16bit的数字值。PDM呢?它用1bit来表示信号的大小——1代表正,0代表负。但它的采样率特别高,通常是2.4MHz到3.2MHz。
为什么用这么高的频率?因为后面要经过一个叫「抽取滤波器」的东西,把高采样率的1bit数据转成低采样率的多bit数据。这个过程叫降采样。
4.2.2 PDM的信号线
PDM接口更简单,就3根线:
- PDM_CLK:时钟线,由主设备提供
- PDM_DATA:数据线,可以同时传两个麦克风的数据(左右声道)
- PDM_SYNC:同步信号,有些芯片需要
4.2.3 R329上的PDM配置
R329的PDM控制器支持最多4个数字麦克风。配置时主要设置采样率和抽取倍数。
pdm_config_t pdm_cfg = {
.sample_rate = 16000, // 目标采样率16kHz
.decimation_ratio = 200, // 抽取倍数,输入3.2MHz / 200 = 16kHz
.channel_num = 2, // 双麦克风
.data_width = PDM_DATA_WIDTH_16BIT,
};
hal_pdm_init(PDM_DEVICE_0, &pdm_cfg);
hal_pdm_start(PDM_DEVICE_0);
4.3 TDM接口:多通道音频的利器
TDM,时分复用。说白了,就是把多个音频通道的数据塞到同一根数据线上,分时传输。
4.3.1 TDM的工作原理
I2S只能传两个声道(左+右)。但TDM可以传4个、8个、甚至16个声道。怎么做?
每个声道分配一个固定的时隙(slot)。比如8声道TDM,一个帧周期内就有8个slot,每个slot传一个声道的数据。BCLK频率要足够高,才能把所有slot的数据传完。
4.3.2 TDM的配置要点
配置TDM时,有几个参数必须搞清楚:
- 时隙数:等于麦克风数量
- 时隙宽度:每个时隙占几个BCLK周期,一般等于位深
- 帧同步:TDM的帧同步信号可以是高电平有效,也可以是低电平有效
- 数据延迟:数据相对于帧同步的延迟,可以是0或1个BCLK
4.3.3 R329上的TDM配置示例
下面是一个4通道TDM的配置,用于麦克风阵列:
tdm_config_t tdm_cfg = {
.sample_rate = 16000,
.slot_num = 4, // 4个时隙
.slot_width = TDM_SLOT_WIDTH_16BIT,
.frame_sync = TDM_FRAME_SYNC_HIGH,
.data_delay = TDM_DATA_DELAY_1BCLK,
.mode = TDM_MODE_MASTER,
};
hal_tdm_init(TDM_DEVICE_0, &tdm_cfg);
hal_tdm_start(TDM_DEVICE_0);
4.4 三种接口的对比与选型
做项目时,怎么选?我列个表,一目了然:
| 接口类型 | 通道数 | 典型应用 | 优点 | 缺点 |
|---|---|---|---|---|
| I2S | 2(立体声) | Codec芯片、蓝牙音频 | 通用性强,几乎所有音频芯片都支持 | 通道数少 |
| PDM | 2~4 | 数字麦克风 | 线少,抗干扰强 | 需要抽取滤波器,延迟稍大 |
| TDM | 4~16 | 麦克风阵列 | 通道数多,一根线搞定 | 配置复杂,时钟要求高 |
4.5 调试经验分享
最后,分享几个我调试音频接口时的心得:
- 先看时钟: 用示波器量BCLK和LRCK,确认频率对不对。我遇到过晶振虚焊,BCLK频率只有一半的情况。
- 再看数据: 用逻辑分析仪抓数据,看数据格式对不对。特别是TDM的时隙对齐,很容易搞错。
- 最后听声音: 如果数据格式对了但声音不对,检查位深和字节序。R329默认是小端,有些Codec是大端。
嗯,音频接口这块内容不少,但掌握了I2S、PDM、TDM这三个,R329上的音频项目基本都能搞定。下一章咱们聊聊音频Codec的配置和调试,到时候会用到今天讲的这些接口知识。