cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 I2C HAL Driver problem

Issac Cheung
Associate

Hi STM,

I am using STM32F4 I2C with DMA as a slave device.

I found that the below snippet of code in I2C_ITError function (stm32f4xx_hal_i2c.c, line 6146) assumed that if hdmatx is not in HAL_DMA_STATE_READY, then it must be hdmarx in HAL_DMA_STATE_READY.

/* Abort DMA transfer */
if (READ_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN) == I2C_CR2_DMAEN)
{
hi2c->Instance->CR2 &= ~I2C_CR2_DMAEN;
 
if (hi2c->hdmatx->State != HAL_DMA_STATE_READY)
{
  /* Set the DMA Abort callback :
  will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */
  hi2c->hdmatx->XferAbortCallback = I2C_DMAAbort;
 
  if (HAL_DMA_Abort_IT(hi2c->hdmatx) != HAL_OK)
  {
	/* Disable I2C peripheral to prevent dummy data in buffer */
	__HAL_I2C_DISABLE(hi2c);
 
	hi2c->State = HAL_I2C_STATE_READY;
 
	/* Call Directly XferAbortCallback function in case of error */
	hi2c->hdmatx->XferAbortCallback(hi2c->hdmatx);
  }
}
else
{
  /* Set the DMA Abort callback :
  will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */
  hi2c->hdmarx->XferAbortCallback = I2C_DMAAbort;
 
  if (HAL_DMA_Abort_IT(hi2c->hdmarx) != HAL_OK)
  {
	/* Store Last receive data if any */
	if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET)
	{
	  /* Read data from DR */
	  *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
 
	  /* Increment Buffer pointer */
	  hi2c->pBuffPtr++;
	}
 
	/* Disable I2C peripheral to prevent dummy data in buffer */
	__HAL_I2C_DISABLE(hi2c);
 
	hi2c->State = HAL_I2C_STATE_READY;
 
	/* Call Directly hi2c->hdmarx->XferAbortCallback function in case of error */
	hi2c->hdmarx->XferAbortCallback(hi2c->hdmarx);
  }
}

However, in my scenario, STM32F4 (as I2C slave) transmitted all data in DMA. It triggered DMA transfer complete interrupt and set my I2C txdma state to HAL_DMA_STATE_READY. Then, when I2C master NACK to stop the frame, I2C_ITError called and forced my chip to run the else case.

Eventually, HAL_I2C_ListenCpltCallback was not called and I need to add a special handling in HAL_I2C_ErrorCallback.

I think this problem can be fixed by else case checking.

if (hi2c->hdmatx->State != HAL_DMA_STATE_READY)
{
    /* ... */
}
else if (hi2c->hdmarx->State != HAL_DMA_STATE_READY)
{
    /* ... */
}

Please let me know if it is a proper fix, or any other function should be called.

Thank you~

0 REPLIES 0