STM32F103RCT6的I2S2收,I2S3发的“伪全双工”连接WM8978

由于需要给WM8978的接收发送音频数据增加延迟,所以将音频数据先通过WM8978的ADC发送给STM32F103,再让STM32F103发送音频数据到WM8978的DAC,进而实现延迟效果,但是由于STM32F103的I2S2是半双工,所以配置STM32F103的I2S2接收音频数据,I2S3发送音频数据,音频数据的收发采用DMA以及双缓冲

首先是I2S2和I2S3的GPIO初始化。

void I2S_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |RCC_APB2Periph_AFIO, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = I2S2_WS_PIN | I2S2_CK_PIN | I2S2_SD_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIO_I2S2_PORT, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = I2S2_MCLK_PIN;
	GPIO_Init(GPIO_I2S2_MCLK_PORT, &GPIO_InitStructure);
}

void I2S3_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |RCC_APB2Periph_AFIO, ENABLE);

	GPIO_InitStructure.GPIO_Pin = I2S3_CK_PIN | I2S3_SD_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIO_I2S3_PORT2, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = I2S3_WS_PIN;
	GPIO_Init(GPIO_I2S3_PORT1, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = I2S3_MCLK_PIN;
	GPIO_Init(GPIO_I2S3_MCLK_PORT, &GPIO_InitStructure);
}

然后是I2S2和I2S3的配置

void I2S_Mode_Config(uint16_t _usStandard, uint16_t _usWordLen, uint16_t _usAudioFreq)
{
	I2S_InitTypeDef I2S_InitStructure; 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
	
	/* 复位 SPI2 外设到缺省状态 */
	SPI_I2S_DeInit(SPI2); 

	/* I2S2 外设配置 */
    I2S_InitStructure.I2S_Mode = I2S_Mode_MasterRx;			/* 配置I2S工作模式 */
    I2S_InitStructure.I2S_Standard = _usStandard;			/* 接口标准 */
	I2S_InitStructure.I2S_DataFormat = _usWordLen;			/* 数据格式,16bit */
	I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;	/* 主时钟模式 */
	I2S_InitStructure.I2S_AudioFreq = _usAudioFreq;			/* 音频采样频率 */
	I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;  			
	I2S_Init(SPI2, &I2S_InitStructure);

	/* 禁止I2S2 TXE中断(发送缓冲区空),需要时再打开 */ 
	SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
		
	/* 禁止I2S2 RXNE中断(接收不空),需要时再打开 */ 
	SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, DISABLE);
	
	/* 使能 SPI2/I2S2 外设 */
	I2S_Cmd(SPI2, ENABLE);
}

void I2S3_Mode_Config(uint16_t _usStandard, uint16_t _usWordLen, uint16_t _usAudioFreq)
{
	I2S_InitTypeDef I2S_InitStructure;

	/* 打开 I2S3 APB1 时钟 */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);

	/* 复位 SPI3 外设到缺省状态 */
	SPI_I2S_DeInit(SPI3);

	/* I2S3 外设配置 */
	I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;			/* 配置I2S工作模式 */
	I2S_InitStructure.I2S_Standard = _usStandard;			/* 接口标准 */
	I2S_InitStructure.I2S_DataFormat = _usWordLen;			/* 数据格式,16bit */
	I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;	/* 主时钟模式 */
	I2S_InitStructure.I2S_AudioFreq = _usAudioFreq;			/* 音频采样频率 */
	I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
	I2S_Init(SPI3, &I2S_InitStructure);

	/* 禁止I2S3 TXE中断(发送缓冲区空),需要时再打开 */
	SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_TXE, DISABLE);

	/* 禁止I2S3 RXNE中断(接收不空),需要时再打开 */
	SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_RXNE, DISABLE);

	/* 使能 SPI3/I2S3 外设 */
	I2S_Cmd(SPI3, ENABLE);
}

然后配置DMA通道

DMA1_Channel4 ----- I2S2_RX

DMA2_Channel2 ----- I2S3_TX

void DMA_RX_InitConfig(uint16_t *rxBuffer, uint32_t bufferSize)
{
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    // 配置接收DMA SPI2_RX 
    DMA_DeInit(DMA1_Channel4);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = bufferSize;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);

    DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE); // 使能传输完成中断

    // 配置NVIC
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Rx,ENABLE);//SPI2 RX DMA请求使能
    DMA_Cmd(DMA1_Channel4, ENABLE); // 使能DMA1 Channel4
}

void DMA_TX_InitConfig(uint16_t *txBuffer, uint32_t bufferSize)
{
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);

    // 配置发送DMA SPI3_TX
    DMA_DeInit(DMA2_Channel2);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI3->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)txBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = bufferSize;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA2_Channel2, &DMA_InitStructure);

    DMA_ITConfig(DMA2_Channel2, DMA_IT_TC, ENABLE); // 使能传输完成中断

    // 配置NVIC
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    SPI_I2S_DMACmd(SPI3,SPI_I2S_DMAReq_Tx,ENABLE);//SPI3 TX DMA请求使能
    DMA_Cmd(DMA2_Channel2, ENABLE); // 使能DMA2 Channel2
}

DMA中断处理,设置接收完成标志位和发送完成标志位

extern volatile uint8_t bufferReady;
extern volatile uint8_t bufferReady01;

// 接收DMA传输完成中断处理函数
void DMA1_Channel4_IRQHandler(void)
{
    if (DMA_GetITStatus(DMA1_IT_TC4))
    {
        DMA_ClearITPendingBit(DMA1_IT_TC4);
        bufferReady = 1;
    }
}

// 发送DMA传输完成中断处理函数
void DMA2_Channel2_IRQHandler(void)
{
    if (DMA_GetITStatus(DMA2_IT_TC2))
    {
        DMA_ClearITPendingBit(DMA2_IT_TC2);
        bufferReady01 = 1;
    }
}

主函数,audioBuffer1和audioBuffer2分别承担接收发送任务,任务都完成后交换彼此的接收发送功能。

#define BUFFER_SIZE 256
uint16_t audioBuffer1[BUFFER_SIZE];
uint16_t audioBuffer2[BUFFER_SIZE];
volatile uint8_t bufferReady = 0;
volatile uint8_t bufferReady01 = 0;
volatile uint8_t currentBuffer = 0;

int main(void)
{
    System_Modle_Init();					//芯片及外设初始化,参数初始化

 	DMA_RX_InitConfig(audioBuffer1, BUFFER_SIZE);
 	DMA_TX_InitConfig(audioBuffer2, BUFFER_SIZE);

	while(1)
	{
		if (bufferReady && bufferReady01)
		{
			// 交换缓冲区
			if (currentBuffer == 0)
			{
				DMA_TX_InitConfig(audioBuffer2, BUFFER_SIZE);
			 	DMA_RX_InitConfig(audioBuffer1, BUFFER_SIZE);

				currentBuffer = 1;
				bufferReady = 0;
				bufferReady01 = 0;
			} else
			{
				DMA_TX_InitConfig(audioBuffer1, BUFFER_SIZE);
			 	DMA_RX_InitConfig(audioBuffer2, BUFFER_SIZE);

				currentBuffer = 0;
				bufferReady = 0;
				bufferReady01 = 0;
			}
		}
	}
}

这样声音的延时时长由双缓冲数组的大小即BUFFER_SIZE 所决定,数组越大声音的延迟时长越大。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值