From f5154364ac8aff6ab1ae261aa71130f1d4c5b0a5 Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 2 Aug 2023 11:26:47 +0800 Subject: [PATCH] feat(gptimer): support set interrupt priority Related forum post: https://esp32.com/viewtopic.php?f=13&t=34959 --- components/driver/gptimer.c | 15 +++++++++++++-- components/driver/include/driver/gptimer.h | 2 ++ .../driver/test_apps/gptimer/main/test_gptimer.c | 1 + docs/en/api-reference/peripherals/gptimer.rst | 2 ++ docs/zh_CN/api-reference/peripherals/gptimer.rst | 2 ++ 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/components/driver/gptimer.c b/components/driver/gptimer.c index e644d7d631..6c3669844b 100644 --- a/components/driver/gptimer.c +++ b/components/driver/gptimer.c @@ -44,6 +44,8 @@ #define GPTIMER_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED #endif +#define GPTIMER_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED + #define GPTIMER_PM_LOCK_NAME_LEN_MAX 16 static const char *TAG = "gptimer"; @@ -82,6 +84,7 @@ struct gptimer_t { timer_hal_context_t hal; _Atomic gptimer_fsm_t fsm; intr_handle_t intr; + int intr_priority; portMUX_TYPE spinlock; // to protect per-timer resources concurent accessed by task and ISR handler gptimer_alarm_cb_t on_alarm; void *user_ctx; @@ -167,8 +170,12 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re #endif esp_err_t ret = ESP_OK; gptimer_t *timer = NULL; - ESP_GOTO_ON_FALSE(config && ret_timer, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); - ESP_GOTO_ON_FALSE(config->resolution_hz, ESP_ERR_INVALID_ARG, err, TAG, "invalid timer resolution:%"PRIu32, config->resolution_hz); + ESP_RETURN_ON_FALSE(config && ret_timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(config->resolution_hz, ESP_ERR_INVALID_ARG, TAG, "invalid timer resolution:%"PRIu32, config->resolution_hz); + if (config->intr_priority) { + ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & GPTIMER_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, + TAG, "invalid interrupt priority:%d", config->intr_priority); + } timer = heap_caps_calloc(1, sizeof(gptimer_t), GPTIMER_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(timer, ESP_ERR_NO_MEM, err, TAG, "no mem for gptimer"); @@ -201,6 +208,7 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re // put the timer driver to the init state atomic_init(&timer->fsm, GPTIMER_FSM_INIT); timer->direction = config->direction; + timer->intr_priority = config->intr_priority; timer->flags.intr_shared = config->flags.intr_shared; ESP_LOGD(TAG, "new gptimer (%d,%d) at %p, resolution=%"PRIu32"Hz", group_id, timer_id, timer, timer->resolution_hz); *ret_timer = timer; @@ -268,6 +276,9 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer ESP_RETURN_ON_FALSE(atomic_load(&timer->fsm) == GPTIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state"); // if user wants to control the interrupt allocation more precisely, we can expose more flags in `gptimer_config_t` int isr_flags = timer->flags.intr_shared ? ESP_INTR_FLAG_SHARED | GPTIMER_INTR_ALLOC_FLAGS : GPTIMER_INTR_ALLOC_FLAGS; + if (timer->intr_priority) { + isr_flags |= 1 << (timer->intr_priority); + } ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(timer_group_periph_signals.groups[group_id].timer_irq_id[timer_id], isr_flags, (uint32_t)timer_ll_get_intr_status_reg(timer->hal.dev), TIMER_LL_EVENT_ALARM(timer_id), gptimer_default_isr, timer, &timer->intr), TAG, "install interrupt service failed"); diff --git a/components/driver/include/driver/gptimer.h b/components/driver/include/driver/gptimer.h index 3eb8ac1a63..279d2ff725 100644 --- a/components/driver/include/driver/gptimer.h +++ b/components/driver/include/driver/gptimer.h @@ -55,6 +55,8 @@ typedef struct { gptimer_count_direction_t direction; /*!< Count direction */ uint32_t resolution_hz; /*!< Counter resolution (working frequency) in Hz, hence, the step size of each count tick equals to (1 / resolution_hz) seconds */ + int intr_priority; /*!< GPTimer interrupt priority, + if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ struct { uint32_t intr_shared: 1; /*!< Set true, the timer interrupt number can be shared with other peripherals */ } flags; /*!< GPTimer config flags*/ diff --git a/components/driver/test_apps/gptimer/main/test_gptimer.c b/components/driver/test_apps/gptimer/main/test_gptimer.c index 674e098bf1..3f776075be 100644 --- a/components/driver/test_apps/gptimer/main/test_gptimer.c +++ b/components/driver/test_apps/gptimer/main/test_gptimer.c @@ -276,6 +276,7 @@ TEST_CASE("gptimer_one_shot_alarm", "[gptimer]") }; gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS]; for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) { + timer_config.intr_priority = i % 3 + 1; // test different priorities TEST_ESP_OK(gptimer_new_timer(&timer_config, &timers[i])); } diff --git a/docs/en/api-reference/peripherals/gptimer.rst b/docs/en/api-reference/peripherals/gptimer.rst index dc556cecf0..a156589674 100644 --- a/docs/en/api-reference/peripherals/gptimer.rst +++ b/docs/en/api-reference/peripherals/gptimer.rst @@ -45,6 +45,8 @@ To install a timer instance, there is a configuration structure that needs to be - :cpp:member:`gptimer_config_t::resolution_hz` sets the resolution of the internal counter. Each count step is equivalent to **1 / resolution_hz** seconds. +- :cpp:member:`gptimer_config::intr_priority` sets the priority of the timer interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. + - Optional :cpp:member:`gptimer_config_t::intr_shared` sets whether or not mark the timer interrupt source as a shared one. For the pros/cons of a shared interrupt, you can refer to :doc:`Interrupt Handling <../../api-reference/system/intr_alloc>`. With all the above configurations set in the structure, the structure can be passed to :cpp:func:`gptimer_new_timer` which will instantiate the timer instance and return a handle of the timer. diff --git a/docs/zh_CN/api-reference/peripherals/gptimer.rst b/docs/zh_CN/api-reference/peripherals/gptimer.rst index d20516d105..cb9dd02e3b 100644 --- a/docs/zh_CN/api-reference/peripherals/gptimer.rst +++ b/docs/zh_CN/api-reference/peripherals/gptimer.rst @@ -45,6 +45,8 @@ - :cpp:member:`gptimer_config_t::resolution_hz` 设置内部计数器的分辨率。计数器每滴答一次相当于 **1 / resolution_hz** 秒。 +- :cpp:member:`gptimer_config::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。 + - 选用 :cpp:member:`gptimer_config_t::intr_shared` 设置是否将定时器中断源标记为共享源。了解共享中断的优缺点,请参考 :doc:`Interrupt Handling <../../api-reference/system/intr_alloc>`。 完成上述结构配置之后,可以将结构传递给 :cpp:func:`gptimer_new_timer`,用以实例化定时器实例并返回定时器句柄。