cancel
Showing results for 
Search instead for 
Did you mean: 

I2C HAL_BUSY

sheqom
Associate III

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.

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

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.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

8 REPLIES 8
TDK
Guru

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.

If you feel a post has answered your question, please click "Accept as Solution".
sheqom
Associate III

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.

Pavel A.
Evangelist III

When you configure the pin back to I2C mode, do not forget to set GPIO_InitStruct.Alternate, GPIO_InitStruct.Speed.

 

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.

If you feel a post has answered your question, please click "Accept as Solution".
sheqom
Associate III
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 :(

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 🙂

Dear Sheqom,

thus the bus hang fixing fuction is the following:

 

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){
HAL_I2C_DeInit(&hi2c1);
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();
 
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);
}

 

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.