2024-10-07 04:13 PM - edited 2024-10-07 07:02 PM
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
2024-10-07 06:03 PM - edited 2024-10-07 06:06 PM
> 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:
The bandaid solution is to reset the bus. To do this:
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.
2024-10-07 07:13 PM
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
2024-10-07 07:51 PM
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