2020-05-29 01:44 AM
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~