AnsweredAssumed Answered

[Bug] I2C I2C_WaitOnRXNEFlagUntilTimeout

Question asked by Vinci on Aug 20, 2017

The L4 1.8.1 drivers contains a tedious race condition inside the "I2C_WaitOnRXNEFlagUntilTimeout" function. There is a chance that RXNE reads 0 (RESET), which causes the while {} to execute. Potentially RXNE and STOPF could get set now right (e.g. if there are IRQs running in between) before the STOPF bit gets checked. If we're about to poll the last byte of a transmission, the function might return a HAL_ERROR, altough we received a perfectly legal sequence of RXNE being set right before STOPF.

 

Also, I believe this question here is related, although about the F7 driver:

STM32 FW_F7_V1.3.1 I2C HAL_I2C_Master_Receive() BUG 

 

I suggest working on the internal communication between whoever is responsible for keeping the drivers up-to-date...

 

Also, the insert-code function won't work, although I've got all the *** damn JS stuff enabled, so here is a plain text copy of "I2C_WaitOnRXNEFlagUntilTimeout" ->

 

static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart)
{
  while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET)
  {
    /* Check if a NACK is detected */
    if(I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK)
    {
      return HAL_ERROR;
    }
 
    /* Check if a STOPF is detected */
    if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET)
    {
      /* Clear STOP Flag */
      __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
 
      /* Clear Configuration Register 2 */
      I2C_RESET_CR2(hi2c);
 
      hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
      hi2c->State= HAL_I2C_STATE_READY;
      hi2c->Mode = HAL_I2C_MODE_NONE;
 
      /* Process Unlocked */
      __HAL_UNLOCK(hi2c);
 
      return HAL_ERROR;
    }
 
    /* Check for the Timeout */
    if((Timeout == 0U)||((HAL_GetTick() - Tickstart) > Timeout))
    {
      hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
      hi2c->State= HAL_I2C_STATE_READY;
 
      /* Process Unlocked */
      __HAL_UNLOCK(hi2c);
 
      return HAL_TIMEOUT;
    }
  }
  return HAL_OK;
}

Outcomes