完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
开发测试环境
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,将采集到的语音通过u***传到pc,做成u*** microphone。 2,通过5.8G无线模块发送到dongle。 |
|
|
|
只有小组成员才能发言,加入小组>>
3310 浏览 9 评论
2991 浏览 16 评论
3492 浏览 1 评论
9057 浏览 16 评论
4086 浏览 18 评论
1176浏览 3评论
604浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
597浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2334浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1895浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 17:38 , Processed in 1.064418 second(s), Total 78, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号