基于MM32F5270的I2S音频播放
MM32F5270 系列控制器支持 I2S 总线接口,本章节在接下来会对 MM32F5270 I2S进行介绍,并使用 MM32F5270 和 CS4344 芯片进行 I2S 通信来演示播放一段声音。
I2S 简介
I2S ( Inter—IC Sound ) 总线是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准,该总线专责于音频设备之间的数据传输,广泛应用于各种多媒体系统。它采用了沿独立的导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真,为用户节省了购买抵抗音频抖动的专业设备的费用。在飞利浦公司的 I2S 标准中,既规定了硬件接口规范,也规定了数字音频数据的格式。 在 MM32F5270 中,SPI 与 I2S 共用引脚。在 I2S 的描述中,支持半双工通信,也支持全双工模式。I2S 与 SPI 区别在于,I2S 主模式的控制逻辑使用独立的时钟分频处理单元。在半双工模式下,可使用 MCK 引脚输出驱动时钟,用于驱动外部音频组件。在全双工模式下,为了能同时进行数据的收发,MCK 驱动时钟只能从专用的 MCK 功能引脚输出。I2S 的功能框图如图 1 所示,包括时钟单元,寄存器控制单元,主从模式控制单元等。
图1. I2S 功能框图
MM32F5270 中 I2S 主要特征
支持半双工通信(仅发射机或接收机)和全双工通信(SD,extSD 的数据方向根据主/从模式配置决定)两种通信方式 9 位可编程线性预分频器,以达到精确的音频采样频率( 8KHz 到 192KHz) 数据帧格式可以是 16 位、 24 位或 32 位 数据包帧固定为 16 位(16 位有效数据)或 32 位(16 位、 24 位、 32 位有效数据) 可编程时钟极性(稳定状态) 发射模式下的下溢标志(仅从机),接收模式下的上溢标志(主和从机)和接收/发射模式下的帧错误标志(仅从机) 用于传输和接收的 32 位寄存器为两个声道分时复用 支持 I2S 协议 ▶ 飞利浦标准 ▶ MSB 对齐标准(左对齐) ▶ LSB 对齐标准(右对齐) ▶ PCM 标准(在 16 位信道帧上具有短帧和长帧同步或扩展到 32 位信道帧的 16 位数据帧) 数据方向始终是 MSB 优先 DMA 传输能力 可配置输出 MCLK 来驱动外部音频组件,比率固定在 256× FS(其中 FS 为音频采样频率)
I2S 信号接口
I2S 和 SPI 共用三个公共管脚: 串行时钟 CK 映射在 SCK 引脚上,也叫位时钟 BCLK,是主模式下的串行时钟输出以及从机模式下的串行时钟输入。SCLK 频率 = 2 x 采样频率 x 采样位数 帧时钟 WS 映射在 NSS 引脚上,是主模式下的串行时钟输出以及从机模式下的串行时钟输入。用于切换左右声道,LRCK 频率 = 采样频率 串行数据 SD 映射在 MOSI 管脚上,二进制补码表示的音频数据,用于发送或接收两次多路数据通道(仅在半双工模式下)。 当某些外部设备需要主时钟输入时,可以使用一个附加的管脚输出时钟到音频设备 主时钟 MCLK 映射在 MISO 引脚或专用 MCK 引脚上,当 I2S 配置为主模式时使用此时钟。MCLK 频率 = 256 x 采样频率 Fs I2S 引脚信号如图 2 所示。
图2. I2S 引脚信号
数据格式 三线总线处理音频数据,必须经过分时复用两个声道:右声道和左声道。因为只有一个 32 位寄存器用于传输或接收,所以软件应依次配置寄存器 TXREG 为各声道的数据,或依次读取寄存器 RXREG 为各声道的数据。按照 I2S 协议,总是先发送左声道,然后发送右声道。 数据格式可以采用以下格式进行发送: 16 位数据打包在 16 位帧中 16 位数据打包在 32 位帧中 24 位数据打包在 32 位帧中 32 位数据打包在 32 位帧中 当使用 32 位帧上发送 16 位数据时,前 16 位(MSB)是有效的位,16 位 LSB 制为 0,无需任何软件操作,通过硬件实现,其他格式相似。
通信标准
I2S 接口支持四种音频标准,通过配置寄存器 SPI_I2S_I2SCFGR 中的 I2SSTD[1:0]、PCMSYNC 位进行切换;数据格式则通过配置 DATLEN[1:0]、CHLEN 来进行选择。对于所有通信标准及数据格式,总是先发送最高位(MSB 优先)。
飞利浦标准
对于飞利浦标准,WS 信号用于指示正在传输的声道。发射器在 CK 的下降沿锁存数据,接收器并在 CK 的上升读取数据。WS 信号也在 CK 的下降沿被锁定。对于这种标准 I2S 格式的信号,无论有多少位有效数据,数据的最高位总是出现在 WS 变化(也就是一帧开始)后的第 2 个 CK 脉冲处,如图 3 所示。
图3. 飞利浦标准示意图 MSB 对齐标准
对于 MSB 对齐标准,第一个数据在 WS 变化后的第一个沿有效,如图 4 所示。
图4. MSB 对齐标准示意图
LSB 对齐标准
对于 LSB 对齐标准,每个数据包帧的最低有效位总(LSB 位)是出现在 WS 变化前的 1 个 CK 脉冲周期处,如图 5 所示。
图5. LSB 对齐标准示意图
PCM 标准
对于 PCM 标准,不需要使用声道信息。PCM 有两个模式:短帧模式和长帧模式,通过配置SPI\_I2S\_I2SCFGR 寄存器的 PCMSYNC 位进行切换。在 PCM 模式下,输出信号(WS, SD)在 CK 信号的上升沿进行采样。输入信号(WS, SD)在 CK 下降沿被捕获。注意在主模式下, CK 和 WS 被配置为输出,如图 6 所示。
图6. PCM 对齐标准示意图
I2S 配置
I2S 的配置主要包括主从模式选择,时钟极性,全双工半双工模式选择,采样频率和通信标准的配置,从而进行数据传输。
主模式
I2S 功能的主模式下,选择全双工工作时,SD 引脚作为主机发送接口,extSD 作为主机接收接口,SCK 和 WS作为主机的输出信号,同时 MCK 向外部提供可选的驱动时钟(配置 SPI_I2S_I2SCFGR.MCKOE 位为 ‘1’ 使能 MCK 输出),如图 7 所示。
图7. I2S 主模式全双工通信
基于 MM32F5270 的声音播放实验
CS4344 芯片是实现本次实验功能的重要器件之一。CS4344 是一种立体声音频数模转换器 (DAC) ,可使用单个 +3.3 V 或 +5 V 电源,仅需要最小的支持电路。该系列线性模拟低通滤波器和自动速度模式检测,当自动选择 2 kHz 和 200 kHz 之间的采样率,使用采样率和主时钟速率方法。 本实验的基本原理是 MM32F3270 读取正弦波采样计算出的左右声道的数组数据,通过 I2S 接口将 PCM 信号传输给 CS4344,再经过 TS4871(音频功率放大器)连接到耳机接口,可以接入耳机等音频播放装置。
硬件设计
如图 8-9 是 PLUS-F5270 的 I2S 电路部分,完整原理图可以通过官网下载。其中,引脚信号对应分别为: ▶ I2S2_SD 对应于引脚 E6 ▶ I2S2_CK 对应于引脚 D3 ▶ I2S2_WS 对应于引脚 E4 ▶ I2S2_MCK 对应于引脚 E5
图8. I2S 电路图(1)
图9. I2S 电路图(2)
GPIO 初始化 BOARD_InitPins()
配置 I2S 引脚,I2S_CK 为 PD3 引脚,I2S_SD 为 PE6 引脚,I2S_WS 为 PE4 引脚,I2S_MCK 为 PE5 引脚,复用通道为 AF5 。 void BOARD_InitPins(void)
{
/* PB7 - UART1_TX. */
GPIO_Init_Type gpio_init;
gpio_init.Pins = GPIO_PIN_6;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull; //GPIO_PinMode_AF_PushPull
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_init);
GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_7);
/* PB6 - UART1_RX. */
gpio_init.Pins = GPIO_PIN_7;
gpio_init.PinMode = GPIO_PinMode_In_Floating; //GPIO_PinMode_In_Floating
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_init);
GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_7);
/* PD3 - I2S_CK. */
gpio_init.Pins = GPIO_PIN_3;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull; //GPIO_PinMode_In_PushPull
gpio_init.Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOD, &gpio_init);
GPIO_PinAFConf(GPIOD, gpio_init.Pins, GPIO_AF_5);
/* PE6 - I2S_SD. */
gpio_init.Pins = GPIO_PIN_6;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull; //GPIO_PinMode_In_PushPull
gpio_init.Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOE, &gpio_init);
GPIO_PinAFConf(GPIOE, gpio_init.Pins, GPIO_AF_5);
/* PE4 - I2S_WS. */
gpio_init.Pins = GPIO_PIN_4;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull; //GPIO_PinMode_In_PushPull
gpio_init.Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOE, &gpio_init);
GPIO_PinAFConf(GPIOE, gpio_init.Pins, GPIO_AF_5);
/* PE5 - I2S_MCK. */
gpio_init.Pins = GPIO_PIN_5;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull; //GPIO_PinMode_In_PushPull
gpio_init.Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOE, &gpio_init);
GPIO_PinAFConf(GPIOE, gpio_init.Pins, GPIO_AF_5);
}
I2S 配置初始化 app_i2s_master_init()
初始化 I2S,配置时钟频率、采样率、数据长度、通信协议、传输模式及是否使能 MCLK 。 void app_i2s_master_init(void)
{
/* setup I2S master module. */
I2S_Master_Init_Type i2s_master_init;
i2s_master_init.ClockFreqHz = BOARD_I2S_FREQ;
i2s_master_init.SampleRate = BOARD_I2S_SAMPLE_RATE;
i2s_master_init.DataWidth = BOARD_I2S_DATA_WIDTH;
i2s_master_init.Protocol = BOARD_I2S_PROTOCOL;
i2s_master_init.EnableMCLK = true;
i2s_master_init.Polarity = BOARD_I2S_CPOL;
i2s_master_init.XferMode = I2S_XferMode_TxOnly;
I2S_InitMaster(BOARD_I2S_PORT, &i2s_master_init);
/* enable I2S. */
I2S_Enable(BOARD_I2S_PORT, true);
}
Protocol
通信标准格式选择,可选 I2S Philips 标准、左对齐标准、右对齐标准、 PCM 短帧标准或 PCM 长帧标准,它设定 SPI\_I2S\_I2SCFGR 寄存器 I2SSTD位和 PCMSYNC位的值。一般设置为 I2S Philips 标准即可。
DataWidth
数据格式选择,设定有效数据长度和帧长度,可选标准 16bit 格式、扩展 16bit( 32bit 帧长度) 格式、 24bit 格式和 32bit 格式,它设定 SPI\_I2SCFGR 寄存器 DATLEN 位和CHLEN 位的值。对应 16bit 数据长度可选 16bit 或 32bit 帧长度,其他都是 32bit 帧长度。
EnableMCLK
主时钟输出使能控制,可选使能输出或禁止输出,它设定 SPI_I2SPR 寄存器 MCKOE 位的值。为提高系统性能一般使能主时钟输出。
SampleRate
采样频率设置,标准库提供采样采样频率选择,分别为 4KHz、8kHz、 11kHz、12KHz、16kHz、22kHz、32kHz、44kHz、48kHz、96kHz、192kHz 以及默认 2Hz,它设定 SPI\_I2S\_SPBRG 寄存器的值。
Polarity
空闲状态的 CK 线电平,可选高电平或低电平,它设定 SPI\_I2S\_CCTL 寄存器 CPOL位的值。一般设置为低电平即可。
左右声道数据
采样函数 f (t) = A *sin( B*t ) , t 为采样时间,单位: s。采样位宽为 16bit,采样频率为 8 khz,系数 A 为10000,B 为2000π。 /* i2s left channel xfer data. */
const int16_t sound_buf_left[SOUND_BUF_SIZE] =
{
0, 3535, 5000, 3535, 0, -3535, -5000, -3535,
0, 3535, 5000, 3535, 0, -3535, -5000, -3535,
};
/* i2s right channel xfer data. */
const int16_t sound_buf_right[SOUND_BUF_SIZE] =
{
0, 3827, 7071, 9238, 10000, 9238, 7071, 3827,
0, -3827, -7071, -9238, -10000, -9238, -7071, -3827
};
左右声道数据传输
/* put data into left channel. */
void app_i2s_put_data_left(void)
{
I2S_PutData(BOARD_I2S_PORT, (uint32_t)sound_buf_left[sound_buf_index_left]);
sound_buf_index_left++;
if (sound_buf_index_left >= SOUND_BUF_SIZE)
{
sound_buf_index_left = 0;
}
}
/* put data into right channel. */
void app_i2s_put_data_right(void)
{
I2S_PutData(BOARD_I2S_PORT, (uint32_t)sound_buf_right[sound_buf_index_right]);
sound_buf_index_right++;
if (sound_buf_index_right >= SOUND_BUF_SIZE)
{
sound_buf_index_right = 0;
}
}
main() 函数
main() 函数结合上述操作,串口打印 "i2s_master_basic" ,初始化 I2S 后,将发送数组数据到左右声道缓冲区,进行声音播放。int main(void)
{
BOARD_Init();
printf("i2s_master_basic.\r\n");
app_i2s_master_init();
while (1)
{
while(0u != (I2S_GetStatus(BOARD_I2S_PORT) & SPI_I2S_CSTAT_TXFULL_MASK) )
{}
app_i2s_put_data_left(); /* sending left channel data. */
while(0u != (I2S_GetStatus(BOARD_I2S_PORT) & SPI_I2S_CSTAT_TXFULL_MASK) )
{}
app_i2s_put_data_right(); /* sending right channel data. */
}
}
实验演示
本实验以搭载 MM32F5277E9PV 的 PLUS-F5270 开发板为平台,其扬声器将会播放左声道数据,演示视频如下:
演示1. 播放左声道数据
音响数据的采集、处理和传输是多媒体技术的重要组成部分。众多的数字音频系统已经进入消费市场,例如数字音频录音带、数字声音处理器。对于设备和生产厂家来说,标准化的信息传输结构可以提高系统的适应性。
本文介绍了 MM32F5270 中通过 I2S 和 CS4344 芯片进行通信来演示播放一段声音,后续将进行 MP3 的播放,未完待续! |