2017-05-31 10:33 AM
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:
Solved! Go to Solution.
2020-07-28 12:17 AM
Think I mentioned this way above, but if you always flush the data register before performing a read transaction, that should do the trick.
2020-07-28 12:18 AM
No problem!
2020-07-28 12:59 PM
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;
}
2020-07-28 01:04 PM
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.
2020-07-28 01:07 PM
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.
2020-07-29 12:18 AM
Hi Nicholas,
thanks for sharing ST's answer!
I am also still not sure if I can skip the dummy read which I left in all my projects, since I had no more issues.
static void EEprom_ReadI2C_Page(void)
{
uint32_t x;
aCommand[0]=0;
Eeprom.Init=HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDRESS, (uint8_t *)aCommand, 1, 2);
x=hi2c1.Instance->RXDR; // dummy read -> bugfix // todo ???
Eeprom.Response=HAL_I2C_Master_Receive(&hi2c1, EEPROM_ADDRESS, (uint8_t *)EEpromData, 256, 100);
}
Maybe it was never necessary in L4xx family.
My current hardware is a STM32L431. Halversion is defined:
#define STM32L4XX_HAL_VERSION_MAIN (0x01U) /*!< [31:24] main version */
#define STM32L4XX_HAL_VERSION_SUB1 (0x0BU) /*!< [23:16] sub1 version */
#define STM32L4XX_HAL_VERSION_SUB2 (0x01U) /*!< [15:8] sub2 version */
does this expand to v1.11.1 ? (STM32F0xx has v1.7.3)
a few days ago with CubeMX 6 it got updated to
#define STM32L4XX_HAL_VERSION_MAIN (0x01U) /*!< [31:24] main version */
#define STM32L4XX_HAL_VERSION_SUB1 (0x0CU) /*!< [23:16] sub1 version */
#define STM32L4XX_HAL_VERSION_SUB2 (0x00U) /*!< [15:8] sub2 version */
but I feel a bit reluctant to update right now to this latest version,
Werner
2020-07-29 05:09 AM
I removed the dummy reads from my code and ran it over night with the updated HAL libraries and so far no failures. Encouraging results.
2020-07-29 05:31 AM
That's very encouraging, indeed. It was my main concern should I change my old working code on live projects or not. I will probably leave is as it is and do a rework for newer versions and other projects. Anyway I am really glad that there is some light at the end of that tunel. :) Take care guys!
2020-08-03 10:39 AM
Been testing for almost a week non-stop now and the I2C has not failed. We are calling it fixed by the newest release of HAL libraries.
2020-08-03 11:39 AM
Great to hear that! Thanks for letting us know! Take care!