i2c issues on i2c_hw_fsm_reset
Posted: Fri Jun 16, 2023 10:14 am
Hi everyone,
i am working on a project using the ESP32-S2, i am communicating with a sensor using I2C. Everything works fine if the I2C connection is kept working. If i try disconnecting and reconnecting the sensor (thus powering it off), when i connect it back again, sometimes the ESP32S2 is capable to restoring the communication back to normal but sometimes it is not.
To explain it better, i added some log into the i2c_master_cmd_begin() function. I report here below the meaningful part of the function:
[Codebox]
// In master mode, since we don't have an interrupt to detective bus error or FSM state, what we do here is to make
// sure the interrupt mechanism for master mode is still working.
// If the command sending is not finished and there is no interrupt any more, the bus is probably dead caused by external noise.
portBASE_TYPE evt_res = xQueueReceive(p_i2c->cmd_evt_queue, &evt, wait_time);
if (evt_res == pdTRUE) {
if (evt.type == I2C_CMD_EVT_DONE) {
if (p_i2c->status == I2C_STATUS_TIMEOUT) {
// If the I2C slave are powered off or the SDA/SCL are connected to ground, for example,
// I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case.
i2c_hw_fsm_reset(i2c_num);
clear_bus_cnt[i2c_num] = 0;
ret = ESP_ERR_TIMEOUT;
ESP_LOGI("DEBUG", "COMMAND LINK TIMEOUT"); <------------------------ DEBUG
} else if (p_i2c->status == I2C_STATUS_ACK_ERROR) {
clear_bus_cnt[i2c_num]++;
if (clear_bus_cnt[i2c_num] >= I2C_ACKERR_CNT_MAX) {
clear_bus_cnt[i2c_num] = 0;
i2c_hw_fsm_reset(i2c_num);
}
ESP_LOGI("DEBUG", "COMMAND LINK FAIL"); <------------------------ DEBUG
ret = ESP_FAIL;
} else {
ESP_LOGI("DEBUG", "COMMAND LINK OK"); <------------------------ DEBUG
ret = ESP_OK;
}
break;
}
if (evt.type == I2C_CMD_EVT_ALIVE) {
}
} else {
ret = ESP_ERR_TIMEOUT;
// If the I2C slave are powered off or the SDA/SCL are connected to ground, for example,
// I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case.
i2c_hw_fsm_reset(i2c_num);
clear_bus_cnt[i2c_num] = 0;
break;
}[/Codebox]
Summarizing:
1) when communication is working "COMMAND LINK OK" is printed;
2) when i disconnect the sensor "COMMAND LINK FAIL" is printed;
3) when i reconnect the sensor "COMMAND LINK OK" is printed when the communication is restored correctly, "COMMAND LINK TIMEOUT" is printed when the communication stop working. The only way to restore the communication when "COMMAND LINK TIMEOUT" is output, is to switch on and off the ESP32S2.
i am working on a project using the ESP32-S2, i am communicating with a sensor using I2C. Everything works fine if the I2C connection is kept working. If i try disconnecting and reconnecting the sensor (thus powering it off), when i connect it back again, sometimes the ESP32S2 is capable to restoring the communication back to normal but sometimes it is not.
To explain it better, i added some log into the i2c_master_cmd_begin() function. I report here below the meaningful part of the function:
[Codebox]
// In master mode, since we don't have an interrupt to detective bus error or FSM state, what we do here is to make
// sure the interrupt mechanism for master mode is still working.
// If the command sending is not finished and there is no interrupt any more, the bus is probably dead caused by external noise.
portBASE_TYPE evt_res = xQueueReceive(p_i2c->cmd_evt_queue, &evt, wait_time);
if (evt_res == pdTRUE) {
if (evt.type == I2C_CMD_EVT_DONE) {
if (p_i2c->status == I2C_STATUS_TIMEOUT) {
// If the I2C slave are powered off or the SDA/SCL are connected to ground, for example,
// I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case.
i2c_hw_fsm_reset(i2c_num);
clear_bus_cnt[i2c_num] = 0;
ret = ESP_ERR_TIMEOUT;
ESP_LOGI("DEBUG", "COMMAND LINK TIMEOUT"); <------------------------ DEBUG
} else if (p_i2c->status == I2C_STATUS_ACK_ERROR) {
clear_bus_cnt[i2c_num]++;
if (clear_bus_cnt[i2c_num] >= I2C_ACKERR_CNT_MAX) {
clear_bus_cnt[i2c_num] = 0;
i2c_hw_fsm_reset(i2c_num);
}
ESP_LOGI("DEBUG", "COMMAND LINK FAIL"); <------------------------ DEBUG
ret = ESP_FAIL;
} else {
ESP_LOGI("DEBUG", "COMMAND LINK OK"); <------------------------ DEBUG
ret = ESP_OK;
}
break;
}
if (evt.type == I2C_CMD_EVT_ALIVE) {
}
} else {
ret = ESP_ERR_TIMEOUT;
// If the I2C slave are powered off or the SDA/SCL are connected to ground, for example,
// I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case.
i2c_hw_fsm_reset(i2c_num);
clear_bus_cnt[i2c_num] = 0;
break;
}[/Codebox]
Summarizing:
1) when communication is working "COMMAND LINK OK" is printed;
2) when i disconnect the sensor "COMMAND LINK FAIL" is printed;
3) when i reconnect the sensor "COMMAND LINK OK" is printed when the communication is restored correctly, "COMMAND LINK TIMEOUT" is printed when the communication stop working. The only way to restore the communication when "COMMAND LINK TIMEOUT" is output, is to switch on and off the ESP32S2.