mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 10:47:19 +02:00
fix(i2c): I2C should not clear bus in a nack state
This commit is contained in:
@ -112,7 +112,7 @@ static esp_err_t s_i2c_master_clear_bus(i2c_bus_handle_t handle)
|
|||||||
*
|
*
|
||||||
* @param[in] i2c_master I2C master handle
|
* @param[in] i2c_master I2C master handle
|
||||||
*/
|
*/
|
||||||
static esp_err_t s_i2c_hw_fsm_reset(i2c_master_bus_handle_t i2c_master)
|
static esp_err_t s_i2c_hw_fsm_reset(i2c_master_bus_handle_t i2c_master, bool clear_bus)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
i2c_hal_context_t *hal = &i2c_master->base->hal;
|
i2c_hal_context_t *hal = &i2c_master->base->hal;
|
||||||
@ -124,7 +124,9 @@ static esp_err_t s_i2c_hw_fsm_reset(i2c_master_bus_handle_t i2c_master)
|
|||||||
i2c_ll_master_get_filter(hal->dev, &filter_cfg);
|
i2c_ll_master_get_filter(hal->dev, &filter_cfg);
|
||||||
|
|
||||||
//to reset the I2C hw module, we need re-enable the hw
|
//to reset the I2C hw module, we need re-enable the hw
|
||||||
ret = s_i2c_master_clear_bus(i2c_master->base);
|
if (clear_bus) {
|
||||||
|
ret = s_i2c_master_clear_bus(i2c_master->base);
|
||||||
|
}
|
||||||
I2C_RCC_ATOMIC() {
|
I2C_RCC_ATOMIC() {
|
||||||
i2c_ll_reset_register(i2c_master->base->port_num);
|
i2c_ll_reset_register(i2c_master->base->port_num);
|
||||||
}
|
}
|
||||||
@ -137,7 +139,9 @@ static esp_err_t s_i2c_hw_fsm_reset(i2c_master_bus_handle_t i2c_master)
|
|||||||
i2c_ll_master_set_filter(hal->dev, filter_cfg);
|
i2c_ll_master_set_filter(hal->dev, filter_cfg);
|
||||||
#else
|
#else
|
||||||
i2c_ll_master_fsm_rst(hal->dev);
|
i2c_ll_master_fsm_rst(hal->dev);
|
||||||
ret = s_i2c_master_clear_bus(i2c_master->base);
|
if (clear_bus) {
|
||||||
|
ret = s_i2c_master_clear_bus(i2c_master->base);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -488,7 +492,7 @@ static void s_i2c_send_commands(i2c_master_bus_handle_t i2c_master, TickType_t t
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (atomic_load(&i2c_master->status) == I2C_STATUS_TIMEOUT) {
|
if (atomic_load(&i2c_master->status) == I2C_STATUS_TIMEOUT) {
|
||||||
s_i2c_hw_fsm_reset(i2c_master);
|
s_i2c_hw_fsm_reset(i2c_master, true);
|
||||||
i2c_master->cmd_idx = 0;
|
i2c_master->cmd_idx = 0;
|
||||||
i2c_master->trans_idx = 0;
|
i2c_master->trans_idx = 0;
|
||||||
ESP_LOGE(TAG, "I2C hardware timeout detected");
|
ESP_LOGE(TAG, "I2C hardware timeout detected");
|
||||||
@ -604,7 +608,7 @@ static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xf
|
|||||||
// Sometimes when the FSM get stuck, the ACK_ERR interrupt will occur endlessly until we reset the FSM and clear bus.
|
// Sometimes when the FSM get stuck, the ACK_ERR interrupt will occur endlessly until we reset the FSM and clear bus.
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (atomic_load(&i2c_master->status) == I2C_STATUS_TIMEOUT || i2c_ll_is_bus_busy(hal->dev)) {
|
if (atomic_load(&i2c_master->status) == I2C_STATUS_TIMEOUT || i2c_ll_is_bus_busy(hal->dev)) {
|
||||||
ESP_RETURN_ON_ERROR(s_i2c_hw_fsm_reset(i2c_master), TAG, "reset hardware failed");
|
ESP_RETURN_ON_ERROR(s_i2c_hw_fsm_reset(i2c_master, true), TAG, "reset hardware failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c_master->base->pm_lock) {
|
if (i2c_master->base->pm_lock) {
|
||||||
@ -938,7 +942,7 @@ static esp_err_t s_i2c_synchronous_transaction(i2c_master_dev_handle_t i2c_dev,
|
|||||||
|
|
||||||
err:
|
err:
|
||||||
// When error occurs, reset hardware fsm in case not influence following transactions.
|
// When error occurs, reset hardware fsm in case not influence following transactions.
|
||||||
s_i2c_hw_fsm_reset(i2c_dev->master_bus);
|
s_i2c_hw_fsm_reset(i2c_dev->master_bus, false);
|
||||||
xSemaphoreGive(i2c_dev->master_bus->bus_lock_mux);
|
xSemaphoreGive(i2c_dev->master_bus->bus_lock_mux);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1153,7 +1157,7 @@ esp_err_t i2c_master_bus_reset(i2c_master_bus_handle_t bus_handle)
|
|||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE((bus_handle != NULL), ESP_ERR_INVALID_ARG, TAG, "This bus is not initialized");
|
ESP_RETURN_ON_FALSE((bus_handle != NULL), ESP_ERR_INVALID_ARG, TAG, "This bus is not initialized");
|
||||||
// Reset I2C master bus
|
// Reset I2C master bus
|
||||||
ESP_RETURN_ON_ERROR(s_i2c_hw_fsm_reset(bus_handle), TAG, "I2C master bus reset failed");
|
ESP_RETURN_ON_ERROR(s_i2c_hw_fsm_reset(bus_handle, true), TAG, "I2C master bus reset failed");
|
||||||
// Reset I2C status state
|
// Reset I2C status state
|
||||||
atomic_store(&bus_handle->status, I2C_STATUS_IDLE);
|
atomic_store(&bus_handle->status, I2C_STATUS_IDLE);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@ -1287,6 +1291,8 @@ esp_err_t i2c_master_probe(i2c_master_bus_handle_t bus_handle, uint16_t address,
|
|||||||
i2c_ll_set_source_clk(hal->dev, bus_handle->base->clk_src);
|
i2c_ll_set_source_clk(hal->dev, bus_handle->base->clk_src);
|
||||||
i2c_hal_set_bus_timing(hal, 100000, bus_handle->base->clk_src, bus_handle->base->clk_src_freq_hz);
|
i2c_hal_set_bus_timing(hal, 100000, bus_handle->base->clk_src, bus_handle->base->clk_src_freq_hz);
|
||||||
}
|
}
|
||||||
|
i2c_ll_txfifo_rst(hal->dev);
|
||||||
|
i2c_ll_rxfifo_rst(hal->dev);
|
||||||
i2c_ll_master_set_fractional_divider(hal->dev, 0, 0);
|
i2c_ll_master_set_fractional_divider(hal->dev, 0, 0);
|
||||||
i2c_ll_enable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR);
|
i2c_ll_enable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR);
|
||||||
// 20ms is sufficient for stretch, since there is no device config on probe operation.
|
// 20ms is sufficient for stretch, since there is no device config on probe operation.
|
||||||
|
Reference in New Issue
Block a user