STM32F4 HAL库I2S 全双工模式的一个BUG

在使用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);
}

不知道有没有人遇到过和我同样的问题,也许是我分析的不对,如果有你有更合理的见解希望能给我留言。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值