cancel
Showing results for 
Search instead for 
Did you mean: 

[BUG] - HAL_I2SEx_TxRxCpltCallback never fire in DMA circular mode

leonardo
Associate III

I was usig stm32f4 hal version 1.11 and in that version there was this code:

void I2S_DMATxCplt(DMA_HandleTypeDef *hdma)
{
  I2S_HandleTypeDef* hi2s = (I2S_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent;
  
  if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U)
  {
    if(hi2s->Init.FullDuplexMode != I2S_FULLDUPLEXMODE_ENABLE)
    {    
       hi2s->Instance->CR2 &= (uint32_t)(~SPI_CR2_TXDMAEN);
    }
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) ||\
    defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx) ||\
    defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F469xx) ||\
    defined(STM32F479xx)
   /* FullDuplexMode feature enabled */   
    else
    {
      if(((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_TX) || ((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_SLAVE_TX))
      {
        /* Disable Tx DMA Request for the I2S Master*/  
        hi2s->Instance->CR2 &= (uint32_t)(~SPI_CR2_TXDMAEN);
      }
      else
      {
        /* Disable Tx DMA Request for the I2SEx Slave */  
        I2SxEXT(hi2s->Instance)->CR2 &= (uint32_t)(~SPI_CR2_TXDMAEN);
      }
    }
#endif /* STM32F40xxx || STM32F41xxx || STM32F42xxx || STM32F43xxx || STM32F401xx || STM32F411xx ||\
          STM32F469xx || STM32F479xx */
 
    hi2s->TxXferCount = 0U;
    if(hi2s->State == HAL_I2S_STATE_BUSY_TX_RX)
    {
      if(hi2s->RxXferCount == 0U)
      {
        hi2s->State = HAL_I2S_STATE_READY;
      }
    }
    else
    {
      hi2s->State = HAL_I2S_STATE_READY; 
    }
  }
  HAL_I2S_TxCpltCallback(hi2s);
}

as you can see HAL_I2S_TxCpltCallback(hi2s) is called at the end of the function, no matter if DMA was in circular mode or not. That is the expected behavior for that callback!!!!

In current stm32f4 hal library we have:

/**
  * @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);
      }
    }
  }
}

this time the call to HAL_I2SEx_TxRxCpltCallback(hi2s) function is inside the circular mode enabled check and therefore it never fire in circular mode.

13 REPLIES 13
Geekboy1011
Associate II

Just following up, A patch was released on Oct 22, 1.25.2 It included a fix for i2c but no patch for this has been released to date.

Is there any ETA on this patch being provided.

Thanks again

Geekboy1011
Associate II

AFAIK no solution has been updated yet, This is what i came up with for the time being.

   

	HAL_I2SEx_TransmitReceive_DMA(&hi2s2, (uint16_t*) &qbuff, (uint16_t*) &rbuff, BUFFER_SIZE *2);
	hi2s2.hdmarx->XferCpltCallback = Custom_TxRxDMACplt;
	hi2s2.hdmarx->XferHalfCpltCallback = Custom_TxRxDMAHalfCplt;
	hi2s2.hdmatx->XferCpltCallback = Custom_TxRxDMACplt;
	hi2s2.hdmatx->XferHalfCpltCallback = Custom_TxRxDMAHalfCplt;
 
static void Custom_TxRxDMAHalfCplt(DMA_HandleTypeDef *hdma)
{
  I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
  if (hi2s->hdmarx == hdma)
  {
	  I2SEx_RxHalfCpltCallback(hi2s);
  }
  else if (hi2s->hdmatx == hdma){
	  I2SEx_TxHalfCpltCallback(hi2s);
  }
}
 
void I2SEx_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
	
}
 
void I2SEx_TxCpltCallback(I2S_HandleTypeDef *hi2s) {
	
}
 
void I2SEx_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
	return;
}
 
void I2SEx_RxCpltCallback(I2S_HandleTypeDef *hi2s) {
		return;
}
 

In short just overwrite their call backs and implement our own, its a cludge but at least it should work even once the updates comeout and properly service these routines.

Imen.D
ST Employee

Hello All,

Sorry for the delayed reply on this, but I have come back on this post with good news =)

A new release of STM32CubeF4 V1.26.0 is now available in ST web page for use, it contains a fix of this issue and several enhancement.

So, I recommend you to download and use this latest version.

Thank you for helping us improve the ST products and for your patienc.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Javier_Leyva08
Associate II

hello everyone, i have one workaround for this issue, actually is pretty simple to fix it.

first off i have the firmware version FW_F4 V1.24.2

the current bug code is the following one:

/**
  * @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 configured in DMA_NORMAL mode */
  if (hdma->Init.Mode == DMA_NORMAL)
  {
    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;
 
        /* Call user TxRx complete callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
        hi2s->TxRxCpltCallback(hi2s);
#else
        HAL_I2SEx_TxRxCpltCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
      }
    }
 
    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;
 
        /* Call user TxRx complete callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
        hi2s->TxRxCpltCallback(hi2s);
#else
        HAL_I2SEx_TxRxCpltCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
      }
    }
  }
}

i have decided to try and experiment with the simpler thing. and i have added in the not provided else, to add it and from here call the callback function HAL_I2SEx_TxRxCpltCallback() , giving the next workaround code.

/**
  * @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 configured in DMA_NORMAL mode */
  if (hdma->Init.Mode == DMA_NORMAL)
  {
    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;
 
        /* Call user TxRx complete callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
        hi2s->TxRxCpltCallback(hi2s);
#else
        HAL_I2SEx_TxRxCpltCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
      }
    }
 
    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;
 
        /* Call user TxRx complete callback */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1U)
        hi2s->TxRxCpltCallback(hi2s);
#else
        HAL_I2SEx_TxRxCpltCallback(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
      }
    }
  }else{
         /* This else body code is the simple workaround */
	  HAL_I2SEx_TxRxCpltCallback(hi2s);
  }
}

and as you can see, the only thing that you need to do is add the else code, that corresponds in the line 69 to 72.

i dont know what repercussions implies that simple added snipped code, but for my application requierments all is pretty well. ( currently i am working with audio stream using I2S DMA in full duplex mode to apply some dsp algorithms.)

happy embedded coding.

best regards.

Jose Javier Leyva Lizarraga.

recall:

"ever try ever fail, no matter, try again fail again fail better".