cancel
Showing results for 
Search instead for 
Did you mean: 

How do I fix a HAL_BUSY condition during I2C comms?

RCooke88
Senior

Hi Folks,

This has been driving me crazy. I'm using a Nucleo-L031 board and it's connected to a I2C TCA9548A 1:8 multiplexer. I am trying to read 4 sensors connected to the mux chip. I have 4.7K pullups installed at the Nucleo's I2C pins. The sensor boards come with 15K pullups already installed.

My code will operate correctly for anywhere between 15 - 60 seconds and then I get the HAL_BUSY error which doesn't go away and the I2C1 communication fails.

Is there a way to clear the HAL_BUSY condition?

Here's my code:

 

 

while (1)
  {
    HAL_GPIO_WritePin(GREEN_LED_GPIO_Port, GREEN_LED_Pin, GPIO_PIN_RESET);	// turn OFF green LED in pushbutton switch
    HAL_Delay(500);
    HAL_GPIO_WritePin(GREEN_LED_GPIO_Port, GREEN_LED_Pin, GPIO_PIN_SET);	// turn ON green LED in pushbutton switch
    HAL_Delay(500);
    for (uint8_t channel = 0; channel < 3; channel++) {
    	uint8_t sensor_number = 1 << channel;
    	ret = HAL_I2C_IsDeviceReady (&hi2c1, TCA9548A_ADDR, 8, 100);	// wait for I2C bus to be ready
    	ret = HAL_I2C_Master_Transmit_IT(&hi2c1, TCA9548A_ADDR, &sensor_number, 1);
		HAL_Delay(35);

    	if ( ret != HAL_OK ) {
				reset_i2c_mux_chip();	// Reset I2C mux chip 1:8
				ret = HAL_I2C_IsDeviceReady (&hi2c1, TCA9548A_ADDR, 8, 100);	// wait for I2C bus to be ready
				ret = HAL_I2C_Master_Transmit_IT(&hi2c1, TCA9548A_ADDR, &sensor_number, 1);
				HAL_Delay(35);
			}
// Sensor #1.................................................................................................
    ret = HAL_I2C_IsDeviceReady (&hi2c1, RTA5543_ADDR, 4, 50);	// wait for I2C bus to be ready
    ret = HAL_I2C_Mem_Read_IT(&hi2c1, RTA5543_ADDR, VOLTAGE_REG, I2C_MEMADD_SIZE_8BIT, (uint8_t*)sensor_data_buf, 2);
    if ( ret != HAL_OK ) {
    	reset_i2c_mux_chip();	// Reset I2C mux chip 1:8
    	ret = HAL_I2C_Master_Transmit_IT(&hi2c1, TCA9548A_ADDR, &sensor_number, 1);
		HAL_Delay(2);
    	ret = HAL_I2C_Mem_Read_IT(&hi2c1, RTA5543_ADDR, VOLTAGE_REG, I2C_MEMADD_SIZE_8BIT, (uint8_t*)sensor_data_buf, 2);
    }
	HAL_Delay(2);
	sen_data_buf[index_loop] = sensor_data_buf[0];
	sen_data_buf[index_loop+1] = sensor_data_buf[1];
	index_loop = index_loop + 2;

// Sensor #2...................................................................................................
	ret = HAL_I2C_IsDeviceReady (&hi2c1, RTA5543_ADDR, 4, 50);	// wait for I2C bus to be ready
	ret = HAL_I2C_Mem_Read_IT(&hi2c1, RTA5543_ADDR, CURRENT_REG, I2C_MEMADD_SIZE_8BIT, sensor_data_buf, 2);
	HAL_Delay(2);
	if ( ret != HAL_OK ) {
		reset_i2c_mux_chip();	// Reset I2C mux chip 1:8
		ret = HAL_I2C_Master_Transmit_IT(&hi2c1, TCA9548A_ADDR, &sensor_number, 1);
		HAL_Delay(2);
	    ret = HAL_I2C_Mem_Read_IT(&hi2c1, RTA5543_ADDR, CURRENT_REG, I2C_MEMADD_SIZE_8BIT, sensor_data_buf, 2);
	}
	sen_data_buf[index_loop] = sensor_data_buf[0];
	sen_data_buf[index_loop+1] = sensor_data_buf[1];
	index_loop = index_loop + 2;

// Sensor #3..................................................................................................
	ret = HAL_I2C_IsDeviceReady (&hi2c1, RTA5543_ADDR, 4, 50);	// wait for I2C bus to be ready
	ret = HAL_I2C_Mem_Read_IT(&hi2c1, RTA5543_ADDR, TEMP_REG, I2C_MEMADD_SIZE_8BIT, sensor_data_buf, 2);
	HAL_Delay(2);
	if ( ret != HAL_OK ) {
		reset_i2c_mux_chip();	// Reset I2C mux chip 1:8
		ret = HAL_I2C_Master_Transmit_IT(&hi2c1, TCA9548A_ADDR, &sensor_number, 1);
		HAL_Delay(2);
		ret = HAL_I2C_Mem_Read_IT(&hi2c1, RTA5543_ADDR, REMAINING_CAP_REG, I2C_MEMADD_SIZE_8BIT, sensor_data_buf, 2);
	}
	sen_data_buf[index_loop] = sensor_data_buf[0];
	sen_data_buf[index_loop+1] = sensor_data_buf[1];
	index_loop = index_loop + 2;
    } // end of for(channel = 0)
    index_loop = 0;
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
}

 

 

Thanks,

Richard

3 REPLIES 3
TDK
Guru

> Is there a way to clear the HAL_BUSY condition?

It depends on what the problem is. If the SDA or SCL lines are held low, this triggers the BUSY bit within I2C peripheral.

If your code works initially, then stops working after a while, this is probably due to a software bug, not a hardware issue.

The *real* solution here is to find out where the bug is occurring and fix it. Some possibilities:

  • Calling HAL_I2C_*_IT functions before the previous function is complete.
  • Not handling an error condition such as AF within the I2C error handler callback.

The bandaid solution is to reset the bus. To do this:

  • Deinitialize the I2C peripheral.
  • If SDA is stuck low, initialize SCL pin as an open drain output and send 9 negative-going pulses at 100 kHz or less.
  • Re-initialize the I2C peripheral (and SCL pin if needed).

 

Some comments on the code:

You appear to be waiting for functions to finish, so why not use blocking functions there instead? It will be conceptually easier.

Instead of silently ignoring the return values on HAL_I2C calls, record the result and do something useful if the result is other than HAL_OK. Such as logging to a debug stream, or otherwise indicating to the user that something has gone wrong and needs addressed. You do this in some cases, but not most of them. For example, the return value of HAL_I2C_IsDeviceReady isn't used anywhere.

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

Missing_stop_bit.JPG

I have highlighted the missing STOP bit. Channel 0 is the SCK line connected to the Nucleo board. Channel 1 is the SDA line connected to the Nucleo board. The yellow output is  connected to the SDA line of the 1:8 mux chip (TCA9548A).

From the image it looks like the Nucleo isn't setting the Stop bit. What can cause this?

Thanks,

Richard

Richard Li
Associate III

Hi, RCooke88,

There are some concern for your problem:

1. The waveform no good, I can't see detail for second byte last clock SDA status.

The I2C bus requested, SCK high time, SDA have to keep stable except start bit, your wave form show second byte last SCK and SDA change same time.

Please look for attached file page 7.

2. You send first should be control command, you enable three channels, this may cause problem. 

 

Regards,

Richard Li