stm32f4xx_hal_driver icon indicating copy to clipboard operation
stm32f4xx_hal_driver copied to clipboard

Problem in HAL_I2C_Mem_Read, no NAK generated in rare cases

Open ks000 opened this issue 3 years ago • 0 comments

Describe the set-up

  • The board: custom board with STM32F407ZET6
  • IDE: STM32CubeIDE 1.9.0

Describe the bug (skip if none)

In some cases HAL_I2C_Mem_Read will finish reading given number of bytes from I2C slave, but will not NAK the last byte. This may cause the slave to pull SDA low if its next byte's MSb is 0, thus freezing the I2C bus.

How to reproduce the bug (skip if none)

  1. My code is reading the data from slave via I2C bus using HAL_I2C_Mem_Read function.
  2. List the modules that you suspect to be the cause of the problem:
  • stm32f4xx_hal_i2c.c
  1. Describe the use case that generates the problem The problem appears when receiving >3 data bytes and HAL_I2C_Mem_Read function can be pre-empted. This could be also caused by an interrupt (I did not check this).

  2. How we can reproduce the problem: Run HAL_I2C_Mem_Read from a task which can be pre-empted by FreeRTOS (or some interrupt) in order to read >3 data bytes via I2C.

Additional context

It seems that I localized the problem to lines 2812-2823 in file stm32f4xx_hal_i2c.c (looking at the latest commit 3d6be4b)

  • The check of BTF flag and DR readout in these lines seems to be wrong and causing the erroneous behavior.
  • Under normal circumstances (when task is not pre-empted by RTOS) BTF flag should be never high immediately after DR readout (line 2803). Even if BTF was high before DR read, according to reference manual it will be cleared when DR is read. So, this check seems unnecessary.
  • Under normal circumstances last 3 data bytes will be handled by code in lines 2744-2792 which disables ACK for correct ending of data reception (with NAK).
  • When there are exactly 4 bytes left to receive, the code will go to RXNE flag loop as usual in lines 2795-2824. If RTOS will switch to another task (or some interrupt happens) while code in lines 2806-2810 is being executed (after receiving 4th last byte) and some other task (or ISR) takes sufficient time for I2C DR and the shift register to be filled by incoming I2C data (3rd and 2nd last bytes), the problem will manifest itself:
    • BTF flag will be set and the following check in line 2812 will yield TRUE, so the code inside IF clause gets executed.
    • The code will read 3rd last data byte from I2C DR register and reduce the counter to 2.
    • On the next loop the data reception will not be handled in lines 2744-2792 which disable ACK, but in lines 2711-2741 which will only generate STOP (if possible), but not disable ACK. This causes the described behavior on I2C bus when slave does not get NAK and prepares to send the next byte which can freeze the bus.
    • My solution: remove the code in lines 2812-2823.

Screenshots

I used logic analyzer to drill down to the reason of the no-NAK behavior and used 4 extra GPIO outputs to understand what the code is doing. On screenshots, there is I2C bus SCL and SDA signals, as well as 4 GPIO lines:

  • DBG0 (yellow) corresponds to execution of code in lines 2795-2824 (RXNE flag poll loop)
  • DBG1 (green) corresponds to execution of code in lines 2692-2709 (1 byte left to receive)
  • DBG2 (blue) corresponds to execution of code in lines 2711-2741 (2 bytes left to receive)
  • DBG3 (purple) corresponds to execution of code in lines 2744-2792 (3 bytes left to receive)

On screenshot with normal data reception the 6 data bytes are received as expected: first three bytes with RXNE loop (DBG0 high), last three bytes in lines 2744-2792 (DBG3 high), NAK in the end.

On screenshot with the problematic behavior, the last bytes are handled in code lines 2711-2741 (DBG2 high), no NAK in the end.

ks000 avatar Aug 03 '22 13:08 ks000