From 872a4311f28ac2e7c036bd46266ede87716e83bd Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Sat, 7 May 2022 12:31:36 +0800 Subject: [PATCH] I2C: Fix a bug making the I2C task wait too long on an event The I2C ISR will now notify the task waiting on an event. Thus, the task can stop waiting on the event queue as soon as possible. --- components/driver/i2c.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/components/driver/i2c.c b/components/driver/i2c.c index c2bdc6d652..10619c37f0 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -213,7 +213,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 i2c_master_cmd_begin_static(i2c_port_t i2c_num); +static void 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) @@ -507,6 +507,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); @@ -515,18 +516,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. @@ -562,7 +563,7 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg) } #endif // SOC_I2C_SUPPORT_SLAVE //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(); } } @@ -1307,10 +1308,9 @@ static inline bool i2c_cmd_is_single_byte(const i2c_cmd_t *cmd) { return cmd->total_bytes == 1; } -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 = { 0 }; if (p_i2c->cmd_link.head != NULL && p_i2c->status == I2C_STATUS_READ) { i2c_cmd_t *cmd = &p_i2c->cmd_link.head->cmd; @@ -1329,17 +1329,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; @@ -1485,7 +1487,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;