Skip to main content
Arno1
Senior
February 10, 2023
Question

Lockup in I2C driver with STM32Cube_FW_H7_V1.11.0

  • February 10, 2023
  • 6 replies
  • 3525 views

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.

6 replies

Pavel A.
Super User
February 10, 2023

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

Arno1
Arno1Author
Senior
February 10, 2023

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
February 11, 2023

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
February 13, 2023

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
February 20, 2023

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
March 3, 2023

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
March 3, 2023

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
March 3, 2023

and other interrogation, how many data did you transfer ?