Просмотр исходного кода

Merge branch 'bugfix/add_return_task_awoken_for_timer_callback_v4.2' into 'release/v4.2'

timer: add return task awoken for timer callback (backport v4.2)

See merge request espressif/esp-idf!9149
Michael (XIAO Xufeng) 5 лет назад
Родитель
Сommit
ccdfbb865e
2 измененных файлов с 24 добавлено и 2 удалено
  1. 17 1
      components/driver/include/driver/timer.h
  2. 7 1
      components/driver/timer.c

+ 17 - 1
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.

+ 7 - 1
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)