STM32cubeMX I2S DMA双缓冲配置

开发测试环境

STM32型号:stm32F401RC
I2S芯片:ES7243
stm32cubeMX 版本:

cubeMX配置方法

1,配置I2S模块;我的是录音模块,所以master RX模式;

1.1 I2S的参数需要根据I2S芯片特性和用户需要来配置。比如通信标准,数据格式和音频采样率…

在这里插入图片描述
1.2 DMA 配置
在这里插入图片描述

2,配置时钟树。
2.1 mcu使用外部晶振。
在这里插入图片描述
在这里插入图片描述

I2S 的有些引脚可以灵活选择;我用的硬件
在这里插入图片描述
点击生成keil5工程;

修改固件

1,修改stm32f4xx_hal_i2s.c

1,修改函数名为HAL_I2S_Receive_DMA_modiy,增加一个buffer,与已有的buffer形成双缓冲。
2,将函数中的HAL_DMA_Start_IT用DMA双缓冲中断启动函数HAL_DMAEx_MultiBufferStart_IT替换
在这里插入图片描述

HAL_StatusTypeDef HAL_I2S_Receive_DMA(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size){}
HAL_StatusTypeDef HAL_I2S_Receive_DMA_modiy(I2S_HandleTypeDef *hi2s, uint16_t *pData,uint16_t *pData2, uint16_t Size)
{
  uint32_t tmpreg_cfgr;

  if ((pData == NULL) || (Size == 0U))
  {
    return  HAL_ERROR;
  }

  /* Process Locked */
  __HAL_LOCK(hi2s);

  if (hi2s->State != HAL_I2S_STATE_READY)
  {
    __HAL_UNLOCK(hi2s);
    return HAL_BUSY;
  }

  /* Set state and reset error code */
  hi2s->State = HAL_I2S_STATE_BUSY_RX;
  hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
  hi2s->pRxBuffPtr = pData;

  tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);

  if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
  {
    hi2s->RxXferSize = (Size << 1U);
    hi2s->RxXferCount = (Size << 1U);
  }
  else
  {
    hi2s->RxXferSize = Size;
    hi2s->RxXferCount = Size;
  }

  /* Set the I2S Rx DMA Half transfer complete callback */
  hi2s->hdmarx->XferHalfCpltCallback = I2S_DMARxHalfCplt;

  /* Set the I2S Rx DMA transfer complete callback */
  hi2s->hdmarx->XferCpltCallback = I2S_DMARxCplt;

  /* Set the DMA error callback */
  hi2s->hdmarx->XferErrorCallback = I2S_DMAError;

  /* Check if Master Receiver mode is selected */
  if ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_RX)
  {
    /* Clear the Overrun Flag by a read operation to the SPI_DR register followed by a read
    access to the SPI_SR register. */
    __HAL_I2S_CLEAR_OVRFLAG(hi2s);
  }

  /* Enable the Rx DMA Stream/Channel */
//  if (HAL_OK != HAL_DMA_Start_IT(hi2s->hdmarx, (uint32_t)&hi2s->Instance->DR, (uint32_t)hi2s->pRxBuffPtr,
//                                 hi2s->RxXferSize))
  if (HAL_OK != HAL_DMAEx_MultiBufferStart_IT(hi2s->hdmarx, (uint32_t)&hi2s->Instance->DR, (uint32_t)hi2s->pRxBuffPtr,(uint32_t)pData2,
                                 hi2s->RxXferSize))	

  {
    /* Update SPI error code */
    SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA);
    hi2s->State = HAL_I2S_STATE_READY;

    __HAL_UNLOCK(hi2s);
    return HAL_ERROR;
  }

  /* Check if the I2S is already enabled */
  if (HAL_IS_BIT_CLR(hi2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE))
  {
    /* Enable I2S peripheral */
    __HAL_I2S_ENABLE(hi2s);
  }

  /* Check if the I2S Rx request is already enabled */
  if (HAL_IS_BIT_CLR(hi2s->Instance->CR2, SPI_CR2_RXDMAEN))
  {
    /* Enable Rx DMA Request */
    SET_BIT(hi2s->Instance->CR2, SPI_CR2_RXDMAEN);
  }

  __HAL_UNLOCK(hi2s);
  return HAL_OK;
}

2,修改stm32f4xx_hal_dma_ex.c

2.1 在函数HAL_DMAEx_MultiBufferStart_IT 增加如下函数指针的实例:
/* Current memory buffer used is Memory 1 callback /
hdma->XferCpltCallback = dma_m0_rxcplt_callback; //第一个缓冲区填满后会调用这个函数
/
Current memory buffer used is Memory 0 callback */
hdma->XferM1CpltCallback = dma_m1_rxcplt_callback; //第二个缓冲区填满后会调用这个函数
hdma->XferErrorCallback = XferErrorCallback_app;

2.2. 在函数外增加这3个函数的具体实现;
中断发生后可以在dma_m0_rxcplt_callback,dma_m1_rxcplt_callback中复制I2S DMA数据到用户区用户后续处理。
在这里插入图片描述

HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength)
{
  HAL_StatusTypeDef status = HAL_OK;
  
  /* Check the parameters */
  assert_param(IS_DMA_BUFFER_SIZE(DataLength));
  
  /* Memory-to-memory transfer not supported in double buffering mode */
  if (hdma->Init.Direction == DMA_MEMORY_TO_MEMORY)
  {
    hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
    return HAL_ERROR;
  }
  /* Current memory buffer used is Memory 1 callback */
  hdma->XferCpltCallback   = dma_m0_rxcplt_callback; //第一个缓冲区填满后会调用这个函数
  /* Current memory buffer used is Memory 0 callback */
  hdma->XferM1CpltCallback = dma_m1_rxcplt_callback; //第二个缓冲区填满后会调用这个函数
  hdma->XferErrorCallback = XferErrorCallback_app;  
  /* Check callback functions */
  if ((NULL == hdma->XferCpltCallback) || (NULL == hdma->XferM1CpltCallback) || (NULL == hdma->XferErrorCallback))
  {
    hdma->ErrorCode = HAL_DMA_ERROR_PARAM;
    return HAL_ERROR;
  }
  
  /* Process locked */
  __HAL_LOCK(hdma);
  
  if(HAL_DMA_STATE_READY == hdma->State)
  {
    /* Change DMA peripheral state */
    hdma->State = HAL_DMA_STATE_BUSY;
    
    /* Initialize the error code */
    hdma->ErrorCode = HAL_DMA_ERROR_NONE;
    
    /* Enable the Double buffer mode */
    hdma->Instance->CR |= (uint32_t)DMA_SxCR_DBM;
    
    /* Configure DMA Stream destination address */
    hdma->Instance->M1AR = SecondMemAddress;
    
    /* Configure the source, destination address and the data length */
    DMA_MultiBufferSetConfig(hdma, SrcAddress, DstAddress, DataLength); 
    
    /* Clear all flags */
    __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));
    __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));
    __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_TE_FLAG_INDEX(hdma));
    __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_DME_FLAG_INDEX(hdma));
    __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_FE_FLAG_INDEX(hdma));

    /* Enable Common interrupts*/
    hdma->Instance->CR  |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME;
    hdma->Instance->FCR |= DMA_IT_FE;
    
    if((hdma->XferHalfCpltCallback != NULL) || (hdma->XferM1HalfCpltCallback != NULL))
    {
      hdma->Instance->CR  |= DMA_IT_HT;
    }
    
    /* Enable the peripheral */
    __HAL_DMA_ENABLE(hdma); 
  }
  else
  {     
    /* Process unlocked */
    __HAL_UNLOCK(hdma);	  
    
    /* Return error status */
    status = HAL_BUSY;
  }  
  return status; 
}

3,在MX_I2S_Init函数里增加

i2S使能;DMA双缓冲配置和使能DMA中断;
在这里插入图片描述

static void MX_I2S3_Init(void)
{

  /* USER CODE BEGIN I2S3_Init 0 */

  /* USER CODE END I2S3_Init 0 */

  /* USER CODE BEGIN I2S3_Init 1 */

  /* USER CODE END I2S3_Init 1 */
  hi2s3.Instance = SPI3;
  hi2s3.Init.Mode = I2S_MODE_MASTER_RX;
  hi2s3.Init.Standard = I2S_STANDARD_PHILIPS;
  hi2s3.Init.DataFormat = I2S_DATAFORMAT_16B;
  hi2s3.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
  hi2s3.Init.AudioFreq = I2S_AUDIOFREQ_16K;
  hi2s3.Init.CPOL = I2S_CPOL_HIGH;
  hi2s3.Init.ClockSource = I2S_CLOCK_PLL;
  hi2s3.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE;
  if (HAL_I2S_Init(&hi2s3) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2S3_Init 2 */
	//HAL_I2S_Init  include  HAL_I2S_MspInit(hi2s);
		__HAL_I2S_ENABLE(&hi2s3);					//使能I2S2	
	
		__HAL_DMA_DISABLE(&hdma_spi3_rx); 
	
		HAL_I2S_Receive_DMA_modiy(&hi2s3,(uint16_t*)test_333[0],(uint16_t*)test_333[1],128);
	
		__HAL_DMA_ENABLE(&hdma_spi3_rx); 
    __HAL_DMA_ENABLE_IT(&hdma_spi3_rx,DMA_IT_TC|DMA_IT_DME);             		//开启传输完成中断		
	
  /* USER CODE END I2S3_Init 2 */

}

4,测试

编译通过后下载跟踪,可以看到test_333[1],test_333[0]的内存交替刷新。 DMA 中断服务程序dma_m0_rxcplt_callback,dma_m1_rxcplt_callback中的变量在不断增加.
DMA 双缓冲OK!!!
在这里插入图片描述

后续将实现:1,将采集到的语音通过usb传到pc,做成usb microphone。
2,通过5.8G无线模块发送到dongle。

测试通过的固件: https://download.csdn.net/download/weixin_43336331/13218938

  • 8
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
STM32CubeMX是一个用于配置STM32微控制器的图形化工具。它可以帮助我们快速配置SD卡、DMA和FATFS文件系统。 在开始配置之前,我们需要先连接SD卡到STM32微控制器,并确保正确配置了SD卡的GPIO引脚,使其与STM32的SDIO接口连接。 首先,打开STM32CubeMX并选择相应的微控制器型号。然后,点击"Pinout & Configuration"选项卡,在左侧的"Peripherals"下选择SDIO,然后在右侧选择SDIO的引脚和模式。确保使能SDIO的时钟和数据信号引脚,并选择正确的模式,如4线模式。 接下来,点击"Middleware"选项卡,在右侧的"STemWin"下选择"FATFS"。然后,在"FATFs 1"下选择"SDIO"作为SD卡的字节访问连接器,并在"Volume1 size"中指定SD卡的容量。 再次点击"Middleware"选项卡,在右侧的"FATFS"下选择"DMA",以启用DMA传输。在"Mode"中选择"POLLING" 或"DMA"作为传输模式,并选择一个可用的DMA通道,例如DMA2-Stream3。 最后,点击"Project"选项卡,在右侧的"Project Name"下输入项目名称,然后点击"Save"按钮保存配置。 现在,我们已经完成了STM32CubeMX配置。生成代码并导入到我们的IDE中,例如Keil或者STM32CubeIDE。 在代码中,我们需要初始化SDIO和DMA,并创建FATFS实例,在主循环中使用FATFS函数完成SD卡的读写操作。我们可以使用FATFS提供的函数来打开、写入、读取和关闭文件,以及创建、删除和重命名目录。 这就是使用STM32CubeMX配置SD卡、DMA和FATFS的步骤。通过使用STM32CubeMX,我们可以快速而方便地配置SD卡、DMA和FATFS,从而实现SD卡的读写操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值