STM32 I2S播放MP3文件实验报告
一、实验原理
本实验主要是初始化DA芯片PCM1770后,处理器读取预先放置在处理器内部的音频文件,判断音频文件的合法性,并依据音频文件的格式设置I2S3接口的参数,然后处理器采用中断方式通过I2S3接口重复播放该音频文件。
二、I2S相关知识
I2S与SPI共用3个引脚:
● SD:串行数据(映射至MOSI引脚),用来发送和接收2路时分复用通道的数据;
● WS:字选(映射至NSS引脚),主模式下作为数据控制信号输出,从模式下作为输入;
● CK:串行时钟(映射至SCK引脚),主模式下作为时钟信号输出,从模式下作为输入。
在某些外部音频设备需要主时钟时,可以另有一个附加引脚输出时钟:
● MCK:主时钟(独立映射),在I2S配置为主模式,寄存器SPI_I2SPR的MCKOE位为’1’时,作为输出额外的时钟信号引脚使用。输出时钟信号的频率预先设置为256 ×Fs,其中Fs是音频信号的采样频率。
支持的音频协议
有四种可用的数据和包帧组合。可以通过以下四种数据格式发送数据:
● 16位数据打包进16位帧
● 16位数据打包进32位帧
● 24位数据打包进32位帧
● 32位数据打包进32位帧
有四种标准协议
--I2S飞利浦标准
--MSB对齐标准
--LSB对齐标准
--PCM标准
时钟发生器
I2S的比特率即确定了在I2S数据线上的数据流和I2S的时钟信号频率。
I2S比特率= 每个声道的比特数 × 声道数目 × 音频采样频率
对于一个具有左右声道和16位音频信号,I2S比特率计算如下
I2S比特率= 16 ×2 ×Fs
如果包长为32位,则有:I2S比特率= 32 ×2 ×Fs
I2S主模式
设置I2S工作在主模式,串行时钟由引脚CK输出,字选信号由引脚WS产生。可以通过设置寄存
器SPI_I2SPR的MCKOE位来选择输出或者不输出主时钟(MCK)。
流程
1. 设置寄存器SPI_I2SPR的I2SDIV[7:0]定义与音频采样频率相符的串行时钟波特率。同时
也要定义寄存器SPI_I2SPR的ODD位。
2. 设置CKPOL位定义通信用时钟在空闲时的电平状态。如果需要向外部的DAC/ADC音频器
件提供主时钟MCK,将寄存器SPI_I2SPR的MCKOE位置为’1’。(按照不同的MCK输出状
态,计算I2SDIV和ODD的值,详见23.4.3节)。
3. 设置寄存器SPI_I2SCFGR的I2SMOD位为’1’激活I
2
S功能,设置I2SSTD[1:0]和PCMSYNC
位选择所用的I2S标准,设置CHLEN选择每个声道的数据位数。还要设置寄存器
SPI_I2SCFGR的I2SCFG[1:0]选择I2S主模式和方向(发送端还是接收端)。
4. 如果需要,可以通过设置寄存器SPI_CR2来打开所需的中断功能和DMA功能。
5. 必须将寄存器SPI_I2SCFGR的I2SE位置为’1’。
6. 引脚WS和CK需要配置为输出模式。如果寄存器SPI_I2SPR的MCKOE位为’1’,引脚MCK也要配置成输出模式。
状态标志位
忙标志位(BSY)
发送缓存空标志位(TXE)
接收缓存非空标志位(RXNE)
声道标志位(CHSIDE)
三、硬件设计
PCM1770芯片是一款低电压、低功耗带耳机放大的DAC芯片,用其实现音频的DA转换。
四、软件设计
int main(void)
{
USART_Configuration();
printf("\n\r -----------------------------------------") ;
printf("\n\r神舟III号音频播放实验") ;
printf("\n\r -----------------------------------------") ;
printf("\n\r串口初始化完成");
/* I2S GPIO接口配置 */
I2S_GPIO_Config();
/*SPI2接口初始化*/
SPI2_Config();
PCM1770_CS_config();
SPI2_Init_For_PCM1770();
printf("\n\rPCM1770 SPI接口初始化完成");
/*中断向量与中断优先级配置*/
NVIC_Configuration();
I2S_CODEC_Init(OutputDevice_SPEAKER, AUDIO_FILE_ADDRESS);//I2C CODEC初始化
I2S_CODEC_Play(1);
while(1)
{
}
}
在音频播放试验中采用I2S3中断方式来实现音频播放。当I2S3中断时,就进入I2S3的中断服务程序,调用音频播放程序I2S_CODEC_DataTransfer(),因此,我们可以重复听到相同的音频。
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Set the Vector Table base address at 0x08010000 */
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0000);
/* SPI2 IRQ Channel configuration */
NVIC_InitStructure.NVIC_IRQChannel = SPI3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void SPI3_IRQHandler(void)
{
//static int IRQcounter = 0;
if ((SPI_I2S_GetITStatus(SPI3, SPI_I2S_IT_TXE) == SET))
{
/* Send data on the SPI3 and Check the current commands */
I2S_CODEC_DataTransfer();
}
}
void I2S_CODEC_DataTransfer(void)
{
/* Send the data read from the memory */
SPI_I2S_SendData(SPI3, (Media_ReadHalfWord(AudioDataIndex)));
/* Increment the index */
//根据波形文件的通道数目增加播放文件指针地址
IncrementVar_AudioDataIndex(WAVE_Format.NumChannels);
}
波形文件的格式:
/* .WAV file format :
Endian Offset Length Contents
big 0 4 bytes 'RIFF' // 0x52494646
little 4 4 bytes
big 8 4 bytes 'WAVE' // 0x57415645
Next, the fmt chunk describes the sample format:
big 12 4 bytes 'fmt ' // 0x666D7420
little 16 4 bytes 0x00000010 // Length of the fmt data (16 bytes)
little 20 2 bytes 0x0001 // Format tag: 1 = PCM
little 22 2 bytes // Channels: 1 = mono, 2 = stereo
little 24 4 bytes // Samples per second: e.g., 22050
little 28 4 bytes // sample rate * block align
little 32 2 bytes // channels * bits/sample / 8
little 34 2 bytes // 8 or 16
Finally, the data chunk contains the sample data:
big 36 4 bytes 'data' // 0x64617461
little 40 4 bytes
little 44 *