Frank CA

STM32 HAL I2C MEM DMA Problem

Discussion created by Frank CA on Mar 29, 2018
Latest reply on Apr 6, 2018 by Marco Nehmelman

On an STM32F103 board and using CMX 4.24 I am transferring data to an external AT24C256 EEPROM. I encounter the following error when using I2C MEM transfer via DMA. There is no STOP bit and the SCL line remains LOW after the DMA transfer is completed, see trace below. I am using Atollic to trace and debug the code.

I2C DMA transfer complete but no STOP bit, SCL remains LOW.

I know the DMA transfer is successfully completed because the HAL_DMA_IRQHandler fires and the Transfer Complete Interrupt management code is executed. This causes the I2C callback to fire and executes I2C_DMAXferCplt. In there the I2C state is detected as HAL_I2C_STATE_BUSY_TX which is correct, and therefore the EVT interrupt is enabled in anticipation of a BTF = 1 event (byte transfer finished) which should follow when the I2C has completed the byte transfer. This is also in accordance with the RM0008 ref manual in 26.3.7 which states

When the number of data transfers which has been
programmed for the corresponding DMA stream is reached, the DMA controller sends an
End of Transfer EOT signal to the I
2C interface and generates a Transfer Complete interrupt
if enabled:
Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA
requests then wait for a BTF event before programming the Stop condition.

...

I never see the EVT interrupt - HAL_I2C_EV_IRQHandler never gets triggered. This implies that BTF is not set or the conditions for the event interrupt to  occurr are not met.

As a test I added the following code to the I2C_DMAXferCplt callback function: (some error detect code omitted)

    else if (CurrentState == HAL_I2C_STATE_BUSY_TX)
  {
        /* Wait until BTF flag is set */
        if(I2C_WaitOnBTFFlagUntilTimeout(hi2c, I2C_TIMEOUT_FLAG, tickstart) = HAL_OK)
        {
            /* Generate Stop */
            hi2c->Instance->CR1 |= I2C_CR1_STOP;

            hi2c->State = HAL_I2C_STATE_READY;
           if(hi2c->Mode == HAL_I2C_MODE_MEM)
            {
              hi2c->Mode = HAL_I2C_MODE_NONE;
               HAL_I2C_MemTxCpltCallback(hi2c);

            }

        }

  }

and this works giving me the following trace:

The stop bit is as expected, my user callback HAL_I2C_MemTxCpltCallback is activated and all is well.

I'm assuming this is a bug but it may of course be my misunderstanding but I have done the code by the book and have evidence as provided above to believe that there is a probability of error in the driver - this has been known to happen also my misunderstanding has been known to happen

Outcomes