Merge branch 'bugfix/fix_i2c_issues_v4.3' into 'release/v4.3'

I2C: Fix task wait too long on an event & timeout WDT triggered (backport v4.3)

See merge request espressif/esp-idf!18770
This commit is contained in:
Jiang Jiang Jian
2022-08-19 14:01:14 +08:00
3 changed files with 47 additions and 30 deletions

View File

@ -199,7 +199,7 @@ static i2c_clk_alloc_t i2c_clk_alloc[I2C_SCLK_MAX] = {
static i2c_obj_t *p_i2c_obj[I2C_NUM_MAX] = {0};
static void i2c_isr_handler_default(void *arg);
static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num);
static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num, portBASE_TYPE* HPTaskAwoken);
static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num);
static void i2c_hw_disable(i2c_port_t i2c_num)
@ -478,6 +478,7 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg)
}
i2c_intr_event_t evt_type = I2C_INTR_EVENT_ERR;
portBASE_TYPE HPTaskAwoken = pdFALSE;
portBASE_TYPE HPTaskAwokenCallee = pdFALSE;
if (p_i2c->mode == I2C_MODE_MASTER) {
if (p_i2c->status == I2C_STATUS_WRITE) {
i2c_hal_master_handle_tx_event(&(i2c_context[i2c_num].hal), &evt_type);
@ -486,18 +487,18 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg)
}
if (evt_type == I2C_INTR_EVENT_NACK) {
p_i2c_obj[i2c_num]->status = I2C_STATUS_ACK_ERROR;
i2c_master_cmd_begin_static(i2c_num);
i2c_master_cmd_begin_static(i2c_num, &HPTaskAwokenCallee);
} else if (evt_type == I2C_INTR_EVENT_TOUT) {
p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT;
i2c_master_cmd_begin_static(i2c_num);
i2c_master_cmd_begin_static(i2c_num, &HPTaskAwokenCallee);
} else if (evt_type == I2C_INTR_EVENT_ARBIT_LOST) {
p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT;
i2c_master_cmd_begin_static(i2c_num);
i2c_master_cmd_begin_static(i2c_num, &HPTaskAwokenCallee);
} else if (evt_type == I2C_INTR_EVENT_END_DET) {
i2c_master_cmd_begin_static(i2c_num);
i2c_master_cmd_begin_static(i2c_num, &HPTaskAwokenCallee);
} else if (evt_type == I2C_INTR_EVENT_TRANS_DONE) {
if (p_i2c->status != I2C_STATUS_ACK_ERROR && p_i2c->status != I2C_STATUS_IDLE) {
i2c_master_cmd_begin_static(i2c_num);
i2c_master_cmd_begin_static(i2c_num, &HPTaskAwokenCallee);
}
} else {
// Do nothing if there is no proper event.
@ -530,7 +531,7 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg)
}
}
//We only need to check here if there is a high-priority task needs to be switched.
if (HPTaskAwoken == pdTRUE) {
if (HPTaskAwoken == pdTRUE || HPTaskAwokenCallee == pdTRUE) {
portYIELD_FROM_ISR();
}
}
@ -542,6 +543,7 @@ esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode,
I2C_CHECK(rx_trans_mode < I2C_DATA_MODE_MAX, I2C_TRANS_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_data_mode(&(i2c_context[i2c_num].hal), tx_trans_mode, rx_trans_mode);
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
@ -678,13 +680,13 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf)
i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), I2C_SLAVE_SDA_SAMPLE_DEFAULT, I2C_SLAVE_SDA_HOLD_DEFAULT);
i2c_hal_set_tout(&(i2c_context[i2c_num].hal), I2C_SLAVE_TIMEOUT_DEFAULT);
i2c_hal_enable_slave_rx_it(&(i2c_context[i2c_num].hal));
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
} else {
i2c_hal_master_init(&(i2c_context[i2c_num].hal), i2c_num);
//Default, we enable hardware filter
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), I2C_FILTER_CYC_NUM_DEF);
i2c_hal_set_bus_timing(&(i2c_context[i2c_num].hal), i2c_conf->master.clk_speed, i2c_get_clk_src(i2c_conf));
}
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
@ -697,6 +699,7 @@ esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period)
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_scl_timing(&(i2c_context[i2c_num].hal), high_period, low_period);
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
@ -716,6 +719,7 @@ esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num)
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), cyc_num);
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
@ -725,6 +729,7 @@ esp_err_t i2c_filter_disable(i2c_port_t i2c_num)
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), 0);
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
@ -737,6 +742,7 @@ esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_start_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time);
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
@ -758,6 +764,7 @@ esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_stop_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time);
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
@ -779,6 +786,7 @@ esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), sample_time, hold_time);
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
@ -1050,11 +1058,10 @@ esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t *data, size_t dat
}
}
static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num, portBASE_TYPE* HPTaskAwoken)
{
i2c_obj_t *p_i2c = p_i2c_obj[i2c_num];
portBASE_TYPE HPTaskAwoken = pdFALSE;
i2c_cmd_evt_t evt;
i2c_cmd_evt_t evt = { 0 };
if (p_i2c->cmd_link.head != NULL && p_i2c->status == I2C_STATUS_READ) {
i2c_cmd_t *cmd = &p_i2c->cmd_link.head->cmd;
i2c_hal_read_rxfifo(&(i2c_context[i2c_num].hal), cmd->data, p_i2c->rx_cnt);
@ -1066,17 +1073,19 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
}
} else if ((p_i2c->status == I2C_STATUS_ACK_ERROR)
|| (p_i2c->status == I2C_STATUS_TIMEOUT)) {
assert(HPTaskAwoken != NULL);
evt.type = I2C_CMD_EVT_DONE;
xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken);
xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, HPTaskAwoken);
return;
} else if (p_i2c->status == I2C_STATUS_DONE) {
return;
}
if (p_i2c->cmd_link.head == NULL) {
assert(HPTaskAwoken != NULL);
p_i2c->cmd_link.cur = NULL;
evt.type = I2C_CMD_EVT_DONE;
xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken);
xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, HPTaskAwoken);
// Return to the IDLE status after cmd_eve_done signal were send out.
p_i2c->status = I2C_STATUS_IDLE;
return;
@ -1205,7 +1214,7 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK);
i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK);
//start send commands, at most 32 bytes one time, isr handler will process the remaining commands.
i2c_master_cmd_begin_static(i2c_num);
i2c_master_cmd_begin_static(i2c_num, NULL);
// Wait event bits
i2c_cmd_evt_t evt;

View File

@ -801,9 +801,12 @@ static inline void i2c_ll_master_fsm_rst(i2c_dev_t *hw)
static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw)
{
hw->scl_sp_conf.scl_rst_slv_num = 9;
hw->scl_sp_conf.scl_rst_slv_en = 0;
hw->ctr.conf_upgate = 1;
hw->scl_sp_conf.scl_rst_slv_en = 1;
hw->ctr.conf_upgate = 1;
// hardward will clear scl_rst_slv_en after sending SCL pulses,
// and we should set conf_upgate bit to synchronize register value.
while (hw->scl_sp_conf.scl_rst_slv_en);
hw->ctr.conf_upgate = 1;
}
/**

View File

@ -16,25 +16,30 @@
void i2c_hal_master_handle_tx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event)
{
i2c_ll_master_get_event(hal->dev, event);
if ((*event < I2C_INTR_EVENT_END_DET) ||
(*event == I2C_INTR_EVENT_TRANS_DONE)) {
i2c_ll_master_disable_tx_it(hal->dev);
i2c_ll_master_clr_tx_it(hal->dev);
} else if (*event == I2C_INTR_EVENT_END_DET) {
i2c_ll_master_clr_tx_it(hal->dev);
if (i2c_ll_get_intsts_mask(hal->dev) != 0) {
// If intr status is 0, no need to handle it.
i2c_ll_master_get_event(hal->dev, event);
if ((*event < I2C_INTR_EVENT_END_DET) ||
(*event == I2C_INTR_EVENT_TRANS_DONE)) {
i2c_ll_master_disable_tx_it(hal->dev);
i2c_ll_master_clr_tx_it(hal->dev);
} else if (*event == I2C_INTR_EVENT_END_DET) {
i2c_ll_master_clr_tx_it(hal->dev);
}
}
}
void i2c_hal_master_handle_rx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event)
{
i2c_ll_master_get_event(hal->dev, event);
if ((*event < I2C_INTR_EVENT_END_DET) ||
(*event == I2C_INTR_EVENT_TRANS_DONE)) {
i2c_ll_master_disable_rx_it(hal->dev);
i2c_ll_master_clr_rx_it(hal->dev);
} else if (*event == I2C_INTR_EVENT_END_DET) {
i2c_ll_master_clr_rx_it(hal->dev);
if (i2c_ll_get_intsts_mask(hal->dev) != 0) {
i2c_ll_master_get_event(hal->dev, event);
if ((*event < I2C_INTR_EVENT_END_DET) ||
(*event == I2C_INTR_EVENT_TRANS_DONE)) {
i2c_ll_master_disable_rx_it(hal->dev);
i2c_ll_master_clr_rx_it(hal->dev);
} else if (*event == I2C_INTR_EVENT_END_DET) {
i2c_ll_master_clr_rx_it(hal->dev);
}
}
}