diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index a4888fb088..1a4c074a64 100644 --- a/components/driver/include/driver/timer.h +++ b/components/driver/include/driver/timer.h @@ -27,7 +27,20 @@ extern "C" { #define TIMER_BASE_CLK (APB_CLK_FREQ) /*!< Frequency of the clock on the input of the timer groups */ -typedef void (*timer_isr_t)(void *); +/** + * @brief Interrupt handle callback function. User need to retrun a bool value + * in callback. + * + * @return + * - True Do task yield at the end of ISR + * - False Not do task yield at the end of ISR + * + * @note If you called FreeRTOS functions in callback, you need to return true or false based on + * the retrun value of argument `pxHigherPriorityTaskWoken`. + * For example, `xQueueSendFromISR` is called in callback, if the return value `pxHigherPriorityTaskWoken` + * of any FreeRTOS calls is pdTRUE, return true; otherwise return false. + */ +typedef bool (*timer_isr_t)(void *); /** * @brief Interrupt handle, used in order to free the isr after use. @@ -191,6 +204,9 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ * If you want to realize some specific applications or write the whole ISR, you can * call timer_isr_register(...) to register ISR. * + * The callback should return a bool value to determine whether need to do YIELD at + * the end of the ISR. + * * If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set, * the handler function must be declared with IRAM_ATTR attribute * and can only call functions in IRAM or ROM. It cannot call other timer APIs. diff --git a/components/driver/timer.c b/components/driver/timer.c index 6515d6cb86..5df314d034 100644 --- a/components/driver/timer.c +++ b/components/driver/timer.c @@ -198,6 +198,8 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ static void IRAM_ATTR timer_isr_default(void *arg) { + bool is_awoken = false; + timer_obj_t *timer_obj = (timer_obj_t *)arg; if (timer_obj == NULL) { return; @@ -211,7 +213,7 @@ static void IRAM_ATTR timer_isr_default(void *arg) uint32_t intr_status = 0; timer_hal_get_intr_status(&(timer_obj->hal), &intr_status); if (intr_status & BIT(timer_obj->hal.idx)) { - timer_obj->timer_isr_fun.fn(timer_obj->timer_isr_fun.args); + is_awoken = timer_obj->timer_isr_fun.fn(timer_obj->timer_isr_fun.args); //Clear intrrupt status timer_hal_clear_intr_status(&(timer_obj->hal)); //After the alarm has been triggered, we need enable it again, so it is triggered the next time. @@ -219,6 +221,10 @@ static void IRAM_ATTR timer_isr_default(void *arg) } } TIMER_EXIT_CRITICAL(&timer_spinlock[timer_obj->timer_isr_fun.isr_timer_group]); + + if (is_awoken) { + portYIELD_FROM_ISR(); + } } esp_err_t timer_isr_callback_add(timer_group_t group_num, timer_idx_t timer_num, timer_isr_t isr_handler, void *args, int intr_alloc_flags)