2023-12-16 06:37 AM
Hello, I am receiving data on my STM32F411E board via the I2C interface with the Mpu9255 IMU sensor. I get HAL_BUSY status in case of any power outage or re-debug.
https://stackoverflow.com/questions/69912431/issue-in-the-i2c-communication-stm32-hal-library
When I apply the solution mentioned here, the problem is not solved directly. Additionally, I have to press the Reset button on the card. If I do this solution every time the card is turned on, the HAL_BUSY situation occurs less frequently, but I have tested it many times and sometimes it gets into this situation again.
Can I trigger the Reset button software for such situations? Unfortunately, the NVIC_SystemReset function did not work for me. I need your suggestions on this matter. Thanks.
Solved! Go to Solution.
2023-12-16 06:48 AM - edited 2023-12-16 06:49 AM
The fix is to reassign SCL as an open-drain GPIO output and send 9 pulses, then re-initialize it as an I2C pin.
> Can I trigger the Reset button software for such situations?
You can always perform a software reset with HAL_NVIC_SystemReset(), but it won't solve the problem.
If you're consistently getting into this state, there's likely a bug in your firmware (or hardware) that needs fixed.
2023-12-16 06:48 AM - edited 2023-12-16 06:49 AM
The fix is to reassign SCL as an open-drain GPIO output and send 9 pulses, then re-initialize it as an I2C pin.
> Can I trigger the Reset button software for such situations?
You can always perform a software reset with HAL_NVIC_SystemReset(), but it won't solve the problem.
If you're consistently getting into this state, there's likely a bug in your firmware (or hardware) that needs fixed.
2023-12-16 07:23 AM
Thank you for your answer, I tried to do as you said, I am not very experienced in STM32 and embedded systems, I tried to make a function like this in my own way;
void reset_I2C(){
GPIO_InitTypeDef GPIO_InitStruct = {0};
ret = HAL_I2C_Mem_Read(&hi2c1, 0xD1, 0x75, 1, &ok, 1, 1000);
if (ret != HAL_OK){
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
for (int i = 0; i < 21; i++) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
HAL_Delay(20);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
HAL_Delay(20);
}
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
MX_I2C1_Init();
ret = HAL_I2C_Mem_Read(&hi2c1, 0xD1, 0x75, 1, &ok, 1, 1000);
if (ret == HAL_OK){
MPU9255_Init(&hi2c1);
}
else{
reset_I2C();
}
}
}
It seems to be working fine. Are there any bugs you notice? I would be very happy if you could take a brief look at it.
2023-12-16 08:54 AM
When you configure the pin back to I2C mode, do not forget to set GPIO_InitStruct.Alternate, GPIO_InitStruct.Speed.
2023-12-16 09:10 AM
Looks good apart from what @Pavel A. says. You only need 9 pulses, but 21 won't hurt anything.
> MX_I2C1_Init()
The pins are re-initialized within here, so there's actually no need for you to do so yourself. May want to step through to verify.
Might want to look at the state machine within hi2c1 to make sure it gets re-initialized correctly. Might need to call HAL_I2C_DeInit() beforehand if it isn't.
2023-12-16 09:40 AM
HAL_StatusTypeDef ret;
uint8_t ok = 1;
void reset_I2C(){
GPIO_InitTypeDef GPIO_InitStruct = {0};
ret = HAL_I2C_Mem_Read(&hi2c1, 0xD1, 0x75, 1, &ok, 1, 1000);
if (ret != HAL_OK){
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
for (int i = 0; i < 10; i++) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
HAL_Delay(20);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
HAL_Delay(20);
}
MX_I2C1_Init();
HAL_I2C_DeInit(&hi2c1);
ret = HAL_I2C_Mem_Read(&hi2c1, 0xD1, 0x75, 1, &ok, 1, 1000);
if (ret == HAL_OK){
MPU9255_Init(&hi2c1);
}
else{
reset_I2C();
}
return;
}
MPU9255_Init(&hi2c1);
}
I followed what you said, but I still get the error when I debug again etc. My HAL_BUSY situation persists and this block of code cannot fix the problem automatically :(
2023-12-16 09:51 AM
HAL_I2C_DeInit(&hi2c1); Calling this before (just below if) fixed it. I think there is no problem right now, thank you everyone for your efforts, I will be here if there is a problem again :)
2024-01-11 01:23 AM - edited 2024-01-11 01:28 AM
Dear Sheqom,
thus the bus hang fixing fuction is the following:
HAL_I2C_DeInit call moved before setting the SCL pin as OD output and performing the 9 pulses.
Can you confirm? Many thanks for your kind reply.
2024-01-11 01:24 AM - edited 2024-01-11 01:25 AM
2024-11-11 07:32 PM
I2C was designed to speed up data read access. After reading a data, if no NACK signal is detected, another data will be read as well, as the NACK signal was not sent out, causing the bus to lock up.