Skip to content

Commit

Permalink
Merge branch 'feature/gptimer_interrupt_priority' into 'master'
Browse files Browse the repository at this point in the history
feat(gptimer): support set interrupt priority

Closes IDF-7954

See merge request espressif/esp-idf!25125
  • Loading branch information
suda-morris committed Aug 3, 2023
2 parents 87d8273 + c32cabc commit 6eabfc2
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 3 deletions.
12 changes: 10 additions & 2 deletions components/driver/gptimer/gptimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,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");
Expand Down Expand Up @@ -138,6 +142,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;
Expand Down Expand Up @@ -234,6 +239,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");
Expand Down
3 changes: 3 additions & 0 deletions components/driver/gptimer/gptimer_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ extern "C" {
#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

typedef struct gptimer_t gptimer_t;
Expand Down Expand Up @@ -62,6 +64,7 @@ struct gptimer_t {
gptimer_count_direction_t direction;
timer_hal_context_t hal;
_Atomic gptimer_fsm_t fsm;
int intr_priority;
intr_handle_t intr;
portMUX_TYPE spinlock; // to protect per-timer resources concurrent accessed by task and ISR handler
gptimer_alarm_cb_t on_alarm;
Expand Down
2 changes: 2 additions & 0 deletions components/driver/gptimer/include/driver/gptimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,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*/
Expand Down
2 changes: 1 addition & 1 deletion components/driver/test_apps/gptimer/main/test_gptimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,6 @@ TEST_CASE("gptimer_auto_reload_on_alarm", "[gptimer]")
}
}


TEST_ALARM_CALLBACK_ATTR static bool test_gptimer_alarm_normal_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
{
TaskHandle_t task_handle = (TaskHandle_t)user_data;
Expand Down Expand Up @@ -316,6 +315,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]));
}

Expand Down
2 changes: 2 additions & 0 deletions docs/en/api-reference/peripherals/gptimer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,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.
Expand Down
2 changes: 2 additions & 0 deletions docs/zh_CN/api-reference/peripherals/gptimer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,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`,用以实例化定时器实例并返回定时器句柄。
Expand Down

0 comments on commit 6eabfc2

Please sign in to comment.