2023-02-10 07:11 AM
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
2023-02-10 07:30 AM
Any details, please? Do you use interrupts (_IT) or _DMA HAL functions and callbacks?
2023-02-10 08:01 AM
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
2023-02-10 05:55 PM
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)
2023-02-13 02:07 AM
I don't intend to spend too much time with this, at least for now but that's a good advice. Thank you.
2023-02-20 04:34 AM
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
2023-03-03 12:11 AM
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
2023-03-03 01:31 AM
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
2023-03-03 02:05 AM
and other interrogation, how many data did you transfer ?
2023-04-27 07:19 AM
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