STM32cubeMX I2S DMA双缓冲配置

  • 开发测试环境
  • cubeMX配置方法
    • 1,配置I2S模块;我的是录音模块,所以master RX模式;
  • 修改固件
    • 1,修改stm32f4xx_hal_i2s.c
    • 2,修改stm32f4xx_hal_dma_ex.c
    • 3,在MX_I2S_Init函数里增加
    • 4,测试

开发测试环境

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 readaccess 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

STM32cubeMX I2S DMA双缓冲配置相关推荐

  1. dma接收双缓存 stm32_STM32和WM8960 I2S 利用DMA双缓冲音频播放和录音(二)

    前面简单讲解了WM8960语音芯片工作方式,WM8960做master,之前参数配置ADC/DAC采样速率的是44.1K,有点问题,现在改为16K,下面会解释为什么要改成16K. WM8960参数配置 ...

  2. STM32F407学习之DMA双缓冲模式HAL库实现

    本学期第一次培训要求用单片机实现1到40KHz的单步进变频正弦波输出,本菜鸡一开始用了通过修改定时器预分频系数和自动重装载值改变输出波表频率.修改定时器 + DDS两种方法,但实现的效果不太理想,不仅 ...

  3. java串口设备中断_利用DMA双缓冲或半完成中断实现串口不定长数据的接收

    在<HAL版本DMA循环模式串口数据收发>中介绍了利用DMA循环模式进行串口数据的收发,STM32F4xx的DMA还提供了双缓冲的功能,采用双缓冲模式,可以在一个DMA完成接收后,对其缓冲 ...

  4. STM32F767 音乐播放器 SAI DMA双缓冲 可播放WAV、MP3、FLAC文件

    以下为在单缓冲程序基础上修改 /*** Enable DMA controller clock*/ static void MX_DMA_Init(void) {/* DMA controller c ...

  5. DMA双缓冲传输意义

    双缓冲,也有人叫乒乓缓冲.因为一般情况下,串口的数据DMA 传输进BUF1 的过程中,是不建议对 BUF1 进行操作的.但由于串口数据是不会等待的直传,所以你总不能等BUF1 满了, 才往FLASH ...

  6. 采用串口DMA双缓冲方法,快速更新外部FLASH中文字库

    参考这位大佬的写的代码:http://www.openedv.com/forum.php?mod=viewthread&tid=64048&extra=&page=1

  7. 串口接收 DMA FIFO 双缓冲区配置 + 单色OLED屏幕灰度图像显示的抖动算法

    适用于单色OLED屏幕图像显示的抖动算法 Visual studio c++ STM32F407 0.96寸单色IIC通信OLED 5级灰度 串口DMA.双缓冲 github 抖动算法原理 DITHE ...

  8. STM32串口DMA接收双缓冲

    STM32高端MCU(F4.F7等)才支持DMA双缓冲,低端MCU(F1)不支持DMA双缓冲,不过有替代方案可实现类型效果. 一.MCU支持DMA双缓冲的情形 不再赘述,参见博客 STM32 串口DM ...

  9. STM32CubeMX系列教程8:配置工程模板(串口+不定长数据收发+DMA+IDLE中断+软中断)

    文章目录 摘要 生成工程 配置外设 1.配置时钟与Debug 2.配置串口与DMA 3.配置定时器与中断 配置时钟树 配置工程设置 点击`GENERATE CODE`生成工程 修改源码 配置软中断 配 ...

  10. AIR32F103(六) ADC,I2S,DMA和ADPCM实现的录音播放功能

    目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告 AIR32F103(二) Linux环境和LibOpenCM3项目模板 AIR32F103(三) Linux环境基于标准外 ...

最新文章

  1. 基于PredictionIO的推荐引擎打造,及大规模多标签分类探索
  2. php 二维数组按照某value值求出最大值最小值
  3. DXUT框架剖析系列文章(原创:天行健 君子当自强而不息)
  4. SDU暑期集训排位(3)
  5. 双十一大战收官:荣耀反超苹果,以新思维新模式傲视群雄
  6. 基于Cocos2d-x的手机游戏性能监控
  7. tomcat 虚拟目录与显示目录中文件列表
  8. Java贪吃蛇小游戏
  9. 大西瓜支付宝/QQ/微信收款码三合一源码+实测可用
  10. 试题 算法提高 盾神与积木游戏
  11. 一篇关于营销的功能需求分析
  12. 阿里云服务搭建微信小程序开发环境
  13. 晓亮的编程经验总结.txt
  14. 2021-05-03
  15. 网游的跨服玩法是如何实现的?“跨域体系”架构设计思路
  16. VB和VB.NET的大致区别
  17. 如何知道当前操作系统是centos的哪个版本和内核版本?
  18. 全志八核H8芯片可以同时播放13个720p视频窗口
  19. 【PC工具】可能是最好用最方便的内部网络设备查看工具,内网ip查询ip扫描工具...
  20. 龙芯2k1000-pmon(6)- spiflash的底层操作

热门文章

  1. java pem 读取_java读取微信Pem格式证书对字段加密
  2. bcm5396交换机级联配置_工业以太网交换机的专业术语汇总
  3. vivo市场API事件上报对接
  4. 使用百度ai识别身份证信息
  5. 一段Js代码开启任意网站的匿名在线聊天室
  6. el-form 表单的校验
  7. Quorum区块链原理及其概念
  8. 虹软视觉人工智能开放平台创享会圆满落幕,干货满满频获点赞
  9. 网页视频怎么录制?这两个方法操作简单,录制高清!
  10. [Android]自定义锁屏并屏蔽按键