在使用STM324的I2S全双工模式时发现HAL库可能存在的一个问题,DMA使能循环模式后I2S发送和接收完成的回调不执行。
查找原因发现是HAL库的stm32f4xx_hal_i2s_ex.c文件中I2SEx_TxRxDMACplt函数在判断到开启了DMA循环模式就不在调用完成回调。
/**
* @brief DMA I2S transmit receive process complete callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void I2SEx_TxRxDMACplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef* hi2s = (I2S_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent;
/* if DMA is not configured in DMA_CIRCULAR mode */
if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U)
{
if (hi2s->hdmarx == hdma)
{
/* Disable Rx DMA Request */
if (((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_TX) ||
((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_SLAVE_TX))
{
CLEAR_BIT(I2SxEXT(hi2s->Instance)->CR2,SPI_CR2_RXDMAEN);
}
else
{
CLEAR_BIT(hi2s->Instance->CR2,SPI_CR2_RXDMAEN);
}
hi2s->RxXferCount = 0U;
if (hi2s->TxXferCount == 0U)
{
hi2s->State = HAL_I2S_STATE_READY;
HAL_I2SEx_TxRxCpltCallback(hi2s);
}
}
if (hi2s->hdmatx == hdma)
{
/* Disable Tx DMA Request */
if (((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_TX) ||
((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_SLAVE_TX))
{
CLEAR_BIT(hi2s->Instance->CR2,SPI_CR2_TXDMAEN);
}
else
{
CLEAR_BIT(I2SxEXT(hi2s->Instance)->CR2,SPI_CR2_TXDMAEN);
}
hi2s->TxXferCount = 0U;
if (hi2s->RxXferCount == 0U)
{
hi2s->State = HAL_I2S_STATE_READY;
HAL_I2SEx_TxRxCpltCallback(hi2s);
}
}
}
}
有点不太理解为什么开启了DMA循环模式就不给完成回调,我还在想是不是ST的工程师有什么特别的意图我没有理解。所以我决定看一下F4的半双工模式是不是也是这样操作的,打开stm32f4xx_hal_i2s.c,发送和接收的回调分别是在不同的函数上实现的。很明显是否开启DMA的循环模式并不影响完成回调的执行,也就是说在半双工模式开启DMA的循环模式是可以正常使用传输完成回调。
/**
* @brief DMA I2S transmit process complete callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void I2S_DMATxCplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef* hi2s = ( I2S_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U)
{
/* Disable Tx DMA Request */
CLEAR_BIT(hi2s->Instance->CR2,SPI_CR2_TXDMAEN);
hi2s->TxXferCount = 0U;
hi2s->State = HAL_I2S_STATE_READY;
}
HAL_I2S_TxCpltCallback(hi2s);
}
/**
* @brief DMA I2S transmit process half complete callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void I2S_DMATxHalfCplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef* hi2s = (I2S_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent;
HAL_I2S_TxHalfCpltCallback(hi2s);
}
/**
* @brief DMA I2S receive process complete callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void I2S_DMARxCplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef* hi2s = ( I2S_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U)
{
/* Disable Rx DMA Request */
CLEAR_BIT(hi2s->Instance->CR2,SPI_CR2_RXDMAEN);
hi2s->RxXferCount = 0U;
hi2s->State = HAL_I2S_STATE_READY;
}
HAL_I2S_RxCpltCallback(hi2s);
}
/**
* @brief DMA I2S receive process half complete callback
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void I2S_DMARxHalfCplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef* hi2s = (I2S_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent;
HAL_I2S_RxHalfCpltCallback(hi2s);
}
此时我已经开始怀疑是不是F4的HAL库存在BUG,为了验证我的想法我决定看一下F3的库是否也是如此。为什么是F3,以为我发现F1和F7都是只有半双工模式,F7这么高端的芯片竟然在I2S的功能上比F4弱,实在是不能理解啊。
F3的HAL库半双工模式和全双工模式是共用同一个回调函数,通过代码我们可以发现F3不会出现使能DMA循环模式就不执行传输完成回调的问题。
/**
* @brief DMA I2S transmit receive process complete callback
* @param hdma DMA handle
* @retval None
*/
static void I2S_TxRxDMACplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef* hi2s = ( I2S_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
/* DMA Normal Mode */
if((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
/* Disable Rx/Tx DMA Request */
if(((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_TX) || ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_SLAVE_TX))
{
hi2s->Instance->CR2 &= (uint32_t)(~SPI_CR2_TXDMAEN);
I2SxEXT(hi2s->Instance)->CR2 &= (uint32_t)(~SPI_CR2_RXDMAEN);
}
else
{
hi2s->Instance->CR2 &= (uint32_t)(~SPI_CR2_RXDMAEN);
I2SxEXT(hi2s->Instance)->CR2 &= (uint32_t)(~SPI_CR2_TXDMAEN);
}
hi2s->RxXferCount = 0U;
hi2s->TxXferCount = 0U;
hi2s->State = HAL_I2S_STATE_READY;
}
HAL_I2S_TxRxCpltCallback(hi2s);
}
static void I2S_TxRxDMAHalfCplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef* hi2s = ( I2S_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
HAL_I2S_TxRxHalfCpltCallback(hi2s);
}
上一篇:STM32Cube-USART
下一篇:stm32f103 keil5 HAL库 UART中断接收
推荐阅读最新更新时间:2024-11-12 00:14
设计资源 培训 开发板 精华推荐
- 基于LTC1864 ADC的微功率500V光隔离16位数据采集系统
- DC2026B-KIT,Linduino 一款隔离式 Arduino 兼容演示板,带有 LTC2607/LTC2422 (DC934A) 演示板
- 【训练营】【物联网实战】灯带世界+846932A
- MC145201EVK,基于 MC145201 PLL 频率合成器的评估板
- 使用 Analog Devices 的 LT6233 的参考设计
- 作为CPU模块使用的无刷直流电机控制应用电路
- 小米车充转type-c
- 【已验证-开源】ESP全系列学习板
- 具有可编程时序的 ADM1186-2ARQZ 升序和降序器和监视器的典型应用电路
- LTC2946IDE 双向功率监视器的典型应用,在正向路径中具有能量和电荷监视器