cancel
Showing results for 
Search instead for 
Did you mean: 

Lockup in I2C driver with STM32Cube_FW_H7_V1.11.0

Arno1
Senior

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

9 REPLIES 9
Pavel A.
Evangelist III

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

Arno1
Senior

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

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
Senior

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

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

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

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

and other interrogation, how many data did you transfer ?

Hello,

It's been a while. For now we resolved to using the older drivers but that's not sustainable.

Here are the register contents of hi2c5 (which also contains the registers of hdma_i2c5_rx and hdma_i2c5_tx). Structure is `field name<tab>data type<tab>value`

hi2c	struct __I2C_HandleTypeDef *	0x2402ff20
	Instance	I2C_TypeDef *	0x40006400
		CR1	volatile uint32_t	0x3
		CR2	volatile uint32_t	0x200a0
		OAR1	volatile uint32_t	0x8000
		OAR2	volatile uint32_t	0x0
		TIMINGR	volatile uint32_t	0x9034b6
		TIMEOUTR	volatile uint32_t	0x0
		ISR	volatile uint32_t	0x8003
		ICR	volatile uint32_t	0x0
		PECR	volatile uint32_t	0x0
		RXDR	volatile uint32_t	0x0
		TXDR	volatile uint32_t	0x2d
	Init	I2C_InitTypeDef	{...}
		Timing	uint32_t	0x9034b6
		OwnAddress1	uint32_t	0x0
		AddressingMode	uint32_t	0x1
		DualAddressMode	uint32_t	0x0
		OwnAddress2	uint32_t	0x0
		OwnAddress2Masks	uint32_t	0x0
		GeneralCallMode	uint32_t	0x0
		NoStretchMode	uint32_t	0x0
	pBuffPtr	uint8_t *	0x24018cb8
		*pBuffPtr	uint8_t	0x1c
	XferSize	uint16_t	0x8
	XferCount	volatile uint16_t	0x8
	XferOptions	volatile uint32_t	0xffff0000
	PreviousState	volatile uint32_t	0x0
	XferISR	HAL_StatusTypeDef (*)(struct __I2C_HandleTypeDef *, uint32_t, uint32_t)	0x804e779
	hdmatx	DMA_HandleTypeDef *	0x2402ff74
		Instance	void *	0x40020058
		Init	DMA_InitTypeDef	{...}
			Request	uint32_t	0x7d
			Direction	uint32_t	0x40
			PeriphInc	uint32_t	0x0
			MemInc	uint32_t	0x400
			PeriphDataAlignment	uint32_t	0x0
			MemDataAlignment	uint32_t	0x0
			Mode	uint32_t	0x0
			Priority	uint32_t	0x0
			FIFOMode	uint32_t	0x0
			FIFOThreshold	uint32_t	0x0
			MemBurst	uint32_t	0x0
			PeriphBurst	uint32_t	0x0
		Lock	HAL_LockTypeDef	0x0
		State	volatile HAL_DMA_StateTypeDef	0x1
		Parent	void *	0x2402ff20
		XferCpltCallback	void (*)(struct __DMA_HandleTypeDef *)	0x804e6d1
		XferHalfCpltCallback	void (*)(struct __DMA_HandleTypeDef *)	0x0
		XferM1CpltCallback	void (*)(struct __DMA_HandleTypeDef *)	0x0
		XferM1HalfCpltCallback	void (*)(struct __DMA_HandleTypeDef *)	0x0
		XferErrorCallback	void (*)(struct __DMA_HandleTypeDef *)	0x804e5ed
		XferAbortCallback	void (*)(struct __DMA_HandleTypeDef *)	0x0
		ErrorCode	volatile uint32_t	0x0
		StreamBaseAddress	uint32_t	0x40020000
		StreamIndex	uint32_t	0x16
		DMAmuxChannel	DMAMUX_Channel_TypeDef *	0x4002080c
			CCR	volatile uint32_t	0x7d
		DMAmuxChannelStatus	DMAMUX_ChannelStatus_TypeDef *	0x40020880
			CSR	volatile uint32_t	0x0
			CFR	volatile uint32_t	0x0
		DMAmuxChannelStatusMask	uint32_t	0x8
		DMAmuxRequestGen	DMAMUX_RequestGen_TypeDef *	0x0
			RGCR	volatile uint32_t	0xa8a003c6
		DMAmuxRequestGenStatus	DMAMUX_RequestGenStatus_TypeDef *	0x0
			RGSR	volatile uint32_t	0xa8a003c6
			RGCFR	volatile uint32_t	0xd4480080
		DMAmuxRequestGenStatusMask	uint32_t	0x0
	hdmarx	DMA_HandleTypeDef *	0x2402ffec
		Instance	void *	0x40020040
		Init	DMA_InitTypeDef	{...}
			Request	uint32_t	0x7c
			Direction	uint32_t	0x0
			PeriphInc	uint32_t	0x0
			MemInc	uint32_t	0x400
			PeriphDataAlignment	uint32_t	0x0
			MemDataAlignment	uint32_t	0x0
			Mode	uint32_t	0x0
			Priority	uint32_t	0x0
			FIFOMode	uint32_t	0x0
			FIFOThreshold	uint32_t	0x0
			MemBurst	uint32_t	0x0
			PeriphBurst	uint32_t	0x0
		Lock	HAL_LockTypeDef	0x1
		State	volatile HAL_DMA_StateTypeDef	0x2
		Parent	void *	0x2402ff20
		XferCpltCallback	void (*)(struct __DMA_HandleTypeDef *)	0x804e725
		XferHalfCpltCallback	void (*)(struct __DMA_HandleTypeDef *)	0x0
		XferM1CpltCallback	void (*)(struct __DMA_HandleTypeDef *)	0x0
		XferM1HalfCpltCallback	void (*)(struct __DMA_HandleTypeDef *)	0x0
		XferErrorCallback	void (*)(struct __DMA_HandleTypeDef *)	0x804e5ed
		XferAbortCallback	void (*)(struct __DMA_HandleTypeDef *)	0x0
		ErrorCode	volatile uint32_t	0x0
		StreamBaseAddress	uint32_t	0x40020000
		StreamIndex	uint32_t	0x10
		DMAmuxChannel	DMAMUX_Channel_TypeDef *	0x40020808
			CCR	volatile uint32_t	0x7c
		DMAmuxChannelStatus	DMAMUX_ChannelStatus_TypeDef *	0x40020880
			CSR	volatile uint32_t	0x0
			CFR	volatile uint32_t	0x0
		DMAmuxChannelStatusMask	uint32_t	0x4
		DMAmuxRequestGen	DMAMUX_RequestGen_TypeDef *	0x0
			RGCR	volatile uint32_t	0xa8a003c6
		DMAmuxRequestGenStatus	DMAMUX_RequestGenStatus_TypeDef *	0x0
			RGSR	volatile uint32_t	0xa8a003c6
			RGCFR	volatile uint32_t	0xd4480080
		DMAmuxRequestGenStatusMask	uint32_t	0x0
	Lock	HAL_LockTypeDef	0x1
	State	volatile HAL_I2C_StateTypeDef	0x22
	Mode	volatile HAL_I2C_ModeTypeDef	0x40
	ErrorCode	volatile uint32_t	0x0
	AddrEventCount	volatile uint32_t	0x0
	Devaddress	volatile uint32_t	0xa0
	Memaddress	volatile uint32_t	0x40
ITFlags	uint32_t	0x8003
ITSources	uint32_t	0x3
direction	uint32_t	0x80002000

Taken from I2C_Mem_ISR_DMA during lock up (HAL_LOCK fails) with its parameters ITFlags and ITSources and the 'direction' variable included above.

Data is stored in a block of 8 bytes followed by reads of about 240 8-byte blocks in a loop.

Best regards,

Arno