Skip to main content
Visitor II
May 19, 2025
Question

HAL I2C abort DMA on I2C error

  • May 19, 2025
  • 2 replies
  • 491 views

On an STM32G4, if an I2C error occurs (e.g. a bus error) during a DMA driven I2C transaction, is the intention that the HAL I2C driver abort the DMA transfer?

Starting at line 6599 in stm32g4xx_hal_i2c.c (v1.2.5), I see code in the I2C_ITError function that looks like it's intending to cancel an ongoing DMA transfer.  However, when using the HAL_I2C_Master_Seq_*_DMA functions, it does not appear that it actually does.

Consider the case of a HAL_I2C_Master_Seq_Transmit_DMA, followed by a HAL_I2C_Master_Seq_Receive_DMA (a basic I2C write-read transaction with repeated start).  At the end of the initial transmit, the HAL_I2C_EV_IRQHandler will call I2C_Master_ISR_DMA, which in turn calls I2C_ITMasterSeqCplt (line 5477), which will set the PreviousState variable of the I2C handle to I2C_STATE_MASTER_BUSY_TX (line 6014).  Then, if an I2C error occurs during the receive DMA transfer, the HAL_I2C_ER_IRQHandler will call the I2C_ITError function (line 4699), which will fail to abort the receive DMA.  That is because it checks PreviousState, which was set to I2C_STATE_MASTER_BUSY_TX, and then tries to abort the transmit DMA that is already complete rather than the receive DMA actually in progress (line 6602).

Note that this is not entirely hypothetical.  While I can't be sure the sequence is exactly as I described above, I have encountered the case that an I2C error occurs during a DMA receive initiated by HAL_I2C_Master_Seq_Receive_DMA and the I2C_ITError function is called with hi2c->State = HAL_I2C_STATE_BUSY_RX and hi2c->PreviousState = I2C_STATE_MASTER_BUSY_TX, which by inspection will not abort the receive DMA.

I believe that this is the source (or at least a source) of an I2C interrupt storm that I have been tracking down.  Because the receive DMA transfer is not aborted, the DMA complete interrupt fires after I2C_ITError, calling the I2C_DMAMasterReceiveCplt callback.  That function re-enables the I2C interrupts (line 6823), specifically the STOP interrupt.  The I2C event interrupt then fires due to the STOP flag, calling HAL_I2C_EV_IRQHandler.  However, since hi2c->XferISR was set to NULL by the I2C_ITError function (line 6596), it immediately returns without clearing any interrupt flags, thus resulting in the interrupt firing again immediately, hanging the processor.

To me, this looks like a bug with the HAL, but maybe I'm misunderstanding the intention of the DMA abort code in I2C_ITError.

 

    This topic has been closed for replies.

    2 replies

    Technical Moderator
    May 19, 2025

    Hello @mjones37 

    How you can performe HAL_I2C_Master_Seq_Receive_DMA() after a transmit process not completed?

    mjones37Author
    Visitor II
    May 19, 2025

    The transmit process does complete.  From the application code, the sequence is this:

    - HAL_I2C_Master_Seq_Transmit_DMA(hi2c, addr, data, size, I2C_FIRST_FRAME)

    - wait for completion

    - HAL_I2C_Master_Seq_Receive_DMA(hi2c, addr, data, size, I2C_LAST_FRAME)

    Technical Moderator
    May 19, 2025

    Hello @mjones37 

    Thank you for bringing this issue to our attention.

    I reported this internally.

    Internal ticket number: 210078 (This is an internal tracking number and is not accessible or usable by customers).