Skip to main content
Arno1
Senior
Feb 10, 2023 3:11 PM UTC
Question

Lockup in I2C driver with STM32Cube_FW_H7_V1.11.0

This is more of a notice than a question.

I just spend the past week looking into an issue we had with reads from an I2C connected EEPROM. We noticed that our system started hanging after some time; sometimes after over 5h.

After a lot of searching we were able to find the time was related to the EEPROM reads at 10 minute intervals where the MCU would hang at a variable multiple of that interval. It was eventually narrowed down to the instance being locked (hi2c->Lock == HAL_LOCKED).

About a month ago I updated the ST HAL drivers to version STM32Cube_FW_H7_V1.11.0 from what I believe was STM32Cube_FW_H7_V1.10.0. There are quite a few changes in the file stm32h7xx_hal_i2c.c, including with how the instance is locked. Rolling back that file to the previous version fixes the issues for us.

For now we will stick to the older driver.

Regards,

Arno

This topic has been closed for replies.

9 replies

Pavel A.
Feb 10, 2023 3:30 PM UTC

Any details, please? Do you use interrupts (_IT) or _DMA HAL functions and callbacks?

Arno1
Arno1Author
Senior
Feb 10, 2023 4:01 PM UTC

Yeah, I probably should have included at least that bit of info :p

We use the memory call with DMA: HAL_I2C_Mem_Read_DMA.

The EEPROM reads and writes are all called from the same FreeRTOS task.

A read is as follows:

// Read
HAL_StatusTypeDef st = HAL_I2C_Mem_Read_DMA(handle, device_address, addr, I2C_MEMADD_SIZE_16BIT, buf, size);
 
// Wait loop until
HAL_I2C_GetState(handle) == HAL_I2C_STATE_READY

S.Ma
Principal
Feb 11, 2023 1:55 AM UTC

If wanting to investigate more, add a code that test SDA and SCL pin level just before initiating a "START bit" on the I2C bus, and if both pins are not high level, then place a NOP() to breakpoint to in debug mode. If you hit it, something went wrong on the I2C bus and maybe the slave EEPROM was interrupted transmitting 0x00-like data.(and the bus being still busy = NOT READY)

Arno1
Arno1Author
Senior
Feb 13, 2023 10:07 AM UTC

I don't intend to spend too much time with this, at least for now but that's a good advice. Thank you.

JRAUL.1
ST Employee
Feb 20, 2023 12:34 PM UTC

Hello,

The difference between the 2 versions, is the inclusion of treatment of address phase through interrupt instead of polling. This modification have been done on the HAL memory interface through interrupt and DMA.

Regarding the your usage on RTOS and the interface DMA that you use, may be your are face to a priority issue between I2C treatment and DMA treatment.

Ideally it will be better to have DMA higher priority than I2C. Mean have higher priority on Data treatment which is manage through DMA HAL than I2C control treatment which is manage through I2C HAL.

If this priority split is already correct on your application, to help investigation, can you share the content of the I2C and DMA view registers and HAL structure content ?

Thanks and Regards

Arno1
Arno1Author
Senior
Mar 3, 2023 8:11 AM UTC

Hi,

Sorry for the late reply. I2C5 uses DMA1 Streams 2 and 3 which have a Pre-emption Priority of 5. The Pre-emption priority of I2C5 event and error interrupts are 10. If a lower number is higher priority, than as you say, DMA has higher priority.

I'm not sure what you mean by 'view registers'.

Here is the HAL config:

I2C5:

void MX_I2C5_Init(void)
{
 
 /* USER CODE BEGIN I2C5_Init 0 */
 
 /* USER CODE END I2C5_Init 0 */
 
 /* USER CODE BEGIN I2C5_Init 1 */
 
 /* USER CODE END I2C5_Init 1 */
 hi2c5.Instance = I2C5;
 hi2c5.Init.Timing = 0x009034B6;
 hi2c5.Init.OwnAddress1 = 0;
 hi2c5.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
 hi2c5.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
 hi2c5.Init.OwnAddress2 = 0;
 hi2c5.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
 hi2c5.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
 hi2c5.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
 if (HAL_I2C_Init(&hi2c5) != HAL_OK)
 {
 Error_Handler();
 }
 
 /** Configure Analogue filter
 */
 if (HAL_I2CEx_ConfigAnalogFilter(&hi2c5, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
 {
 Error_Handler();
 }
 
 /** Configure Digital filter
 */
 if (HAL_I2CEx_ConfigDigitalFilter(&hi2c5, 0) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN I2C5_Init 2 */
 
 /* USER CODE END I2C5_Init 2 */
 
}

DMA:

void MX_DMA_Init(void)
{
 
 /* DMA controller clock enable */
 __HAL_RCC_DMA1_CLK_ENABLE();
 __HAL_RCC_DMA2_CLK_ENABLE();
 
 /* DMA interrupt init */
 /* DMA1_Stream0_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
 /* DMA1_Stream1_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
 /* DMA1_Stream2_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);
 /* DMA1_Stream3_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
 /* DMA2_Stream2_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
 
}

Thanks

JRAUL.1
ST Employee
Mar 3, 2023 9:31 AM UTC

hello

thanks for this sharing, as you mentioned the interrupt prio seems correct.

Regarding the register view, that i have propose to share, is the register content of I2C and DMA at the moment of lockup, that you can find usually through your IDE with a display of register content.

Regards

JRAUL.1
ST Employee
Mar 3, 2023 10:05 AM UTC

and other interrogation, how many data did you transfer ?