开发测试环境
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。
开发测试环境
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。
举报