AnsweredAssumed Answered

F4 I2S CubeMX problem in HAL_I2S_DMAStop

Question asked by shamaev.eugene on Jan 5, 2016
Latest reply on Mar 31, 2016 by FTITI.Walid
I would like to point the attention of ST to the problem they have in the CubeMX generated code.
In HAL_StatusTypeDef HAL_I2S_DMAStop(I2S_HandleTypeDef *hi2s) function the procedure described in 26.6.4 I2S master mode of RM0390 is NOT followed!

It is clearly stated that "To switch off the I2S, by clearing I2SE, it is mandatory to wait for TXE = 1 and BSY = 0."

It is not done so and in 24 and 32 bit mode the next start usually gets shifted by 16 bit because of incompleted sequence during stop!

Following should be added before the __HAL_I2S_DISABLE(hi2s):

while(__HAL_I2S_GET_FLAG(hi2s, I2S_FLAG_TXE) != 1 || __HAL_I2S_GET_FLAG(hi2s, I2S_FLAG_BSY) != 0);

Also the timeout should be added and some protection of course in production version.

This bug has costed me about a day to track down.



Update. The fully define function:

__weak HAL_StatusTypeDef HAL_I2S_DMAStop(I2S_HandleTypeDef *hi2s)
{
    /* Process Locked */
    __HAL_LOCK(hi2s);


    /* Disable the I2S Tx/Rx DMA requests */
    hi2s->Instance->CR2 &= ~SPI_CR2_TXDMAEN;
    hi2s->Instance->CR2 &= ~SPI_CR2_RXDMAEN;


    /* Abort the I2S DMA Stream tx */
    if(hi2s->hdmatx != NULL)
    {
        HAL_DMA_Abort(hi2s->hdmatx);
    }
    /* Abort the I2S DMA Stream rx */
    if(hi2s->hdmarx != NULL)
    {
        HAL_DMA_Abort(hi2s->hdmarx);
    }


    // To switch off the I2S, by clearing I2SE, it is mandatory to wait for TXE = 1 and BSY = 0.
    uint32_t tickstart = 0;
    tickstart = HAL_GetTick();
    while(__HAL_I2S_GET_FLAG(hi2s, I2S_FLAG_TXE) != 1 || __HAL_I2S_GET_FLAG(hi2s, I2S_FLAG_BSY) != 0)
    {
         if((HAL_GetTick() - tickstart ) > HAL_TIMEOUT_I2S_ABORT)
          {
               /* Update error code */
              hi2s->ErrorCode |= HAL_I2S_ERROR_TIMEOUT;


               /* Process Unlocked */
               __HAL_UNLOCK(hi2s);


               /* Change the I2S state */
               hi2s->State = HAL_I2S_STATE_TIMEOUT;


               return HAL_TIMEOUT;
          }
    }
    /* Disable I2S peripheral */
    __HAL_I2S_DISABLE(hi2s);


    hi2s->State = HAL_I2S_STATE_READY;


    /* Process Unlocked */
    __HAL_UNLOCK(hi2s);


    return HAL_OK;
}

In .h:
#define HAL_TIMEOUT_I2S_ABORT    ((uint32_t)1000)  /* 1s */
#define HAL_I2S_ERROR_TIMEOUT       ((uint32_t)0x00000040)    /*!< I2S transfer error          */

Outcomes