Skip to main content
Visitor II
May 31, 2017
Solved

I2C Receive getting extra invalid byte using HAL

  • May 31, 2017
  • 13 replies
  • 6872 views

Posted on May 31, 2017 at 19:33

I am using an stm32f030x8. I am using the HAL. Normal operation I can use I2C reads/writes with no problems; however, I can occasionally have errors in the receive data when more activity is taking place on the MCU. I scoped the lines and the bytes on the line are correct/as expected. While step debugging, I can see that the data seemingly gets shifted by a byte when this occurs (i.e. byte 0 in the receive array is some garbage value that was not actually on the bus (verified from scoping the lines), byte 1, 2 etc are the expected data. 

Things to note: using synchronous reads here, interrupts are not in play. this system uses single priority interrupts (no nesting)

Things I have verified:

  • The actual data on the physical line is correct (scope + logic analyzer verifies this)
  • I verified that the pointer address for the buffer being passed in does not get changed (rules out memory corruption of that pointer)
  • Verified that the bad data byte is being read out of the rx hw register. The following line shows that RXDR is holding the 'garbage' byte during step debug: (*hi2c->pBuffPtr++) = hi2c->Instance->RXDR;
  • Verified that worse case memory does not corrupt stack/heap (this was my initial thought since we are pretty close to utilizing the full RAM capabilities of this device). We have ~800 bytes to spare between heap/stack region in worse case scenario.♯

    This topic has been closed for replies.
    Best answer by Ross Yeager
    Posted on June 20, 2017 at 09:25

    Turns out the solution here was to flush the stale byte out of the data register.  Seems like it may be a HAL or HW bug that that byte was not cleared during previous reads, but reading the data register before making the call to the HAL_I2C_Master_Read() call gets it to work as expected.

    13 replies

    Ross YeagerAuthorAnswer
    Visitor II
    June 20, 2017
    Posted on June 20, 2017 at 09:25

    Turns out the solution here was to flush the stale byte out of the data register.  Seems like it may be a HAL or HW bug that that byte was not cleared during previous reads, but reading the data register before making the call to the HAL_I2C_Master_Read() call gets it to work as expected.

    Explorer
    June 20, 2017
    Posted on June 20, 2017 at 15:27

    had the same problem with an STM32F051 chip reading 18bytes of a hall angle detector chip. For about 5min everything runs fine, after that, the extra byte seems always to be there. Since I knew the result bit pattern, and the ghost byte always being zero I could detect and fix the reading. Doing a dummy read like x=hi2c1.Instance->RXDR; right before HAL_I2C_Master_Read() seems to fix it. Thank you Ross. It feels better like that. I would appreciate a statement from ST, and especially if it is a HW bug, find it's way into the official 'device limitations' document

    Visitor II
    August 7, 2017
    Posted on August 07, 2017 at 03:19

    Thanks for the suggestion to do the dummy read!

    I was having the same issue with an STM32F303.  If an interrupt hit while an I2C read sequence was in process, and the IRQ took long enough, I would get an extra byte in the I2C data.

    I have sense added the dummy read at the top of the 

    HAL_I2C_Master_Read() function itself, and I don't seem to get the extra byte anymore.

    On a side note, I ported my code over to an F4 nucleo board, and wasn't able to replicate the bug.  

    Visitor II
    November 14, 2017
    Posted on November 14, 2017 at 07:28

    i had the same problem on my stm32l082czw. fun thing is, the problem only occured when the usb driver was enablet and transmitting data besides the i2c. but the dummy read on top of the HAL i2c read function cleared out the problem! thank you so much! is this bug reported yet?

    Visitor II
    November 14, 2017

    Posted on November 14, 2017 at 19:19

    I also have been experiencing this issue with an STM32F769 connected to an STMPE811 Touchscreen Controller over I2C3. It has been driving me crazy as the I2C bus transactions all look OK (as seen by a Logic Analyzer) .

    When the HAL gets into this state, even reading registers from the STMPE811 results in garbage. e.g. The CHIP_ID register (which should return 0x0811) returns 0x??08 (where ?? is some random value). Reading the ID_VER register (next register address) in the next HAL_I2C_Mem_Read() transaction then returns the remaining 0x11 from the CHIP_ID register instead of the 0x03 that is expected. You can imagine what this does for the rest of the touchscreen interface !

    To date, my solution has been to periodically read the CHIP_ID register and, if 'corrupt', perform both an I2C3 re-initialisation AND an STMPE811 re-initialisation. None of this should be necessary in a properly tested HAL. I will look into your suggestion Ross, but would like to echo Werner's call for ST to provide some sort of an update. This appears to be the same issue as

    https://community.st.com/s/question/0D50X00009XkepL/stm32f7-hal-i2c-reading-bytes-out-of-sync

    which has been outstanding for 18 months.

    Is it just me or do ST make a general habit of going silent when a problem is raised ? There is still an outstanding issue awaiting comment (after almost seven months) on

    https://community.st.com/s/question/0D50X00009XkgKx/stm32-cyptolib-with-iar-811

    . Even acknowledging the issues would be a significant step forward.

    Visitor II
    January 22, 2018
    Posted on January 22, 2018 at 21:24

    I had a similar behaviuor :

    - In Master Polling mode I had to read back 4 Bytes from HiH6130.

    It worrked pretty much ok for some minutes.

    After that I realized that the STM32 was always sending the right number of clock edges to the slave that sent B0, B1, B2, B3 back.

    Received Byte0 was indeed stored one byte ahead in the memory. Say mi buffer was located @ 0x200083d0, the first received byte was stored @ 0x200083d1. This was not the case a few seconds before.

    Location 0x200083d0  was indeed filled with Byte 3 from the previous read!!

    Say STM32 started reading  and stored first the last byte B3' of the previous transmission  @ location 0x200083d0, than the first 'real byte' B0 came in and was stored  @0x200083d1. Of course the first byte on the bus was B0. 

    The last byte being stored was B2 @0x200083d3.

    Proper operation, B are the bytes on the bus seen with my protocol analyzer

    0x200083d0    B0

    0x200083d1    B1

    0x200083d2    B2

    0x200083d3    B3

    Real operation, after few minutes

    0x200083d0    B3'

    0x200083d1    B0

    0x200083d2    B1

    0x200083d3    B2

    where B3' is the last byte from the previous transfer.

    The 4th byte B3 was not stored this time but would be used the next one as B0.

    After reading I reset the peripheral and get rid of this issue.

    Fabio

    Visitor II
    August 31, 2018

    Hi guys,

    I can easily join you in this conversation as I have similar problem with my STM32F072 and polling MPU6050. However I haven't implemented the solution yet.

    It happens similar to me... I am reading 14 bytes and works fine but then after some time something happens and data seems to be shifted by one byte. So first read byte is always wrong and next bytes are fine.

    I used logic analyzer to inspect communication and it looks ok on wires.

    So data on wire looks as follows:

    1. packet: 0xcc, 0xdd, 0xee, 0xff
    2. packet: 0x11, 0x22, 0x33, 0x44
    3. pacekt: 0x55, 0x66, 0x77, 0x88....

    But the reading out of that second packet looks that in the code:

    data[] = 0xff, 0x11, 0x22, 0x33,

    the next packet reading will be:

    data[] = 0x44, 0x55, 0x66, 0x77 .... (logic analyzer will show 0x55, 0x66, 0x77, 0x88)

    As you can see it's shifted by one byte...

    what exactly you did to solve that problem? ¸I am reading that you made dummy read. But how do you detect that first byte get's corrupted to perform dummy read?

    Thanks for your help.

    Visitor II
    July 28, 2020

    Think I mentioned this way above, but if you always flush the data register before performing a read transaction, that should do the trick.

    Graduate
    July 27, 2020

    I seem to be having exactly the same problem...except for me a failure takes many hours (usually over night) and if I'm running 4 separate targets with the same code not all the boards will fail at the same time. I have also noticed that if I'm running a debugger attached and running the problem doesn't seem to occur at all. I see the last post here was 2 years ago...has this problem been solved by or even acknowledged by ST yet? what is the exact code I need to add to fix this issue?

    Visitor II
    July 28, 2020

    I found some workarounds instead of solutions. It seems there's problem with I2C on F1 series and workaround is explained in ERRATA. I spoke with some of my friends who are also working with I2C and they complained about similar issues. Workaround is first to detect that I2C stopped working (eg. timer watchdog checking line activities) then you manually reconfigure lines and toggle levels to clockout data line, then you reconfigure it back to I2C and it (usually) will work again. This can be done quite fast so the data will be corrupted only for short time. I had similar experience with STM32L101, STM32F07 and STM32F403 I2C peripherals. Solution for us was not to use I2C sensors anymore. We rathere use sensors with SPI which work much better in my experience.

    Graduate
    July 28, 2020

    So I got in touch with ST and they said there was a problem that was fixed in v.1.7.1 of the HAL Libraries where if an interrupt occured during an I2C read it would cause the I2C receive register to get out of sync by 1 byte. I was using v.1.7.0 and they are currently on v. 1.7.3. I tried doing a "dummy read" as others in this thread have suggested and that did not work 100% (though it seemed to help for a while). ST recommended that I update my HAL Library files to v.1.7.3 and reprogram my targets. Here is a detailed explanation of the problem I received in e-mail.

    The issue was relevant to how the RXNE and STOP flag were managed inside the static function I2C_WaitOnRXNEFlagUntilTimeout, which is used in polling mode.

    Basically the bug could happen if the function would be interrupted in a specific point by an interrupt, like the systick. In the following the details:

     

    static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout

    (I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart)

     while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET)

     {

       /* Check if a NACK is detected */

       if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK)

       {

         return HAL_ERROR;

       }

       // At this moment the last byte is being received but not

    completely received (let's say few bits received)

       // Systick gets fired and loads the CPU for few microseconds

       // I2C hardware receives the last byte in RXDR and generates the

    NAK and STOP condition as it was set to auto end in I2C_TransferConfig

    ()

       // Systick finishes the processing

       // CPU gets back to I2C_WaitOnRXNEFlagUntilTimeout() and the first

    thing to check the STOP flag which is already set

        // The HAL driver returns a timeout and the last byte is not

    copied in the user buffer but the RXDR register does have that data

       /* Check if a STOPF is detected */

       if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET)

       {

         /* Clear STOP Flag */

         __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);

     

         /* Clear Configuration Register 2 */

         I2C_RESET_CR2(hi2c);

     

         hi2c->ErrorCode = HAL_I2C_ERROR_NONE;

         hi2c->State = HAL_I2C_STATE_READY;

         hi2c->Mode = HAL_I2C_MODE_NONE;

     

         /* Process Unlocked */

         __HAL_UNLOCK(hi2c);

     

         return HAL_ERROR;

       }

    Visitor II
    July 28, 2020

    Thanks for sharing your findings with ST. That's great to know. I will have a look again at my old code.... I am quite sure my HAL drivers I had used in that project are dated to the version you're mentioning and I think this might help solving my issues. Thanks again.

    Graduate
    July 28, 2020

    glad I could help. I am currently testing the fix, but it could take me a few days to see any failures if there are any. I'll re-post if I see any issues.