diff --git a/components/app_trace/test/test_trace.c b/components/app_trace/test/test_trace.c index 75815ce778..a6c132c9c2 100644 --- a/components/app_trace/test/test_trace.c +++ b/components/app_trace/test/test_trace.c @@ -67,15 +67,15 @@ const static char *TAG = "esp_apptrace_test"; static void esp_apptrace_test_timer_init(int timer_group, int timer_idx, uint32_t period) { - timer_config_t config; uint64_t alarm_val = (period * (TIMER_BASE_CLK / 1000000UL)) / 2; - - config.alarm_en = 1; - config.auto_reload = 1; - config.counter_dir = TIMER_COUNT_UP; - config.divider = 2; //Range is 2 to 65536 - config.intr_type = TIMER_INTR_LEVEL; - config.counter_en = TIMER_PAUSE; + timer_config_t config = { + .alarm_en = 1, + .auto_reload = 1, + .counter_dir = TIMER_COUNT_UP, + .divider = 2, //Range is 2 to 65536 + .intr_type = TIMER_INTR_LEVEL, + .counter_en = TIMER_PAUSE, + }; /*Configure timer*/ timer_init(timer_group, timer_idx, &config); /*Stop timer counter*/ @@ -358,7 +358,6 @@ static uint64_t esp_apptrace_test_ts_get(void) static void esp_apptrace_test_ts_init(int timer_group, int timer_idx) { - timer_config_t config; //uint64_t alarm_val = period * (TIMER_BASE_CLK / 1000000UL); ESP_APPTRACE_TEST_LOGI("Use timer%d.%d for TS", timer_group, timer_idx); @@ -366,11 +365,13 @@ static void esp_apptrace_test_ts_init(int timer_group, int timer_idx) s_ts_timer_group = timer_group; s_ts_timer_idx = timer_idx; - config.alarm_en = 0; - config.auto_reload = 0; - config.counter_dir = TIMER_COUNT_UP; - config.divider = 2; //Range is 2 to 65536 - config.counter_en = 0; + timer_config_t config = { + .alarm_en = 0, + .auto_reload = 0, + .counter_dir = TIMER_COUNT_UP, + .divider = 2, //Range is 2 to 65536 + .counter_en = 0, + }; /*Configure timer*/ timer_init(timer_group, timer_idx, &config); /*Load counter value */ @@ -381,13 +382,13 @@ static void esp_apptrace_test_ts_init(int timer_group, int timer_idx) static void esp_apptrace_test_ts_cleanup(void) { - timer_config_t config; - - config.alarm_en = 0; - config.auto_reload = 0; - config.counter_dir = TIMER_COUNT_UP; - config.divider = 2; //Range is 2 to 65536 - config.counter_en = 0; + timer_config_t config = { + .alarm_en = 0, + .auto_reload = 0, + .counter_dir = TIMER_COUNT_UP, + .divider = 2, //Range is 2 to 65536 + .counter_en = 0, + }; /*Configure timer*/ timer_init(s_ts_timer_group, s_ts_timer_idx, &config); } diff --git a/components/cxx/test/test_cxx.cpp b/components/cxx/test/test_cxx.cpp index 50ff3103ea..e1765c2092 100644 --- a/components/cxx/test/test_cxx.cpp +++ b/components/cxx/test/test_cxx.cpp @@ -324,5 +324,5 @@ template __attribute__((unused)) static void test_binary_operators() } //Add more types here. If any flags cannot pass the build, use FLAG_ATTR in esp_attr.h -#include "hal/timer_types.h" +#include "driver/timer.h" template void test_binary_operators(); diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index a3ab39267c..d2290c27f2 100644 --- a/components/driver/include/driver/timer.h +++ b/components/driver/include/driver/timer.h @@ -9,6 +9,7 @@ #include "esp_err.h" #include "esp_attr.h" #include "soc/soc.h" +#include "soc/soc_caps.h" #include "soc/timer_periph.h" #include "esp_intr_alloc.h" #include "hal/timer_types.h" @@ -17,7 +18,115 @@ extern "C" { #endif -#define TIMER_BASE_CLK (APB_CLK_FREQ) /*!< Frequency of the clock on the input of the timer groups */ +/** + * @brief Frequency of the clock on the input of the timer groups + * @note This macro is not correct for Timer Groups with multiple clock sources (e.g. APB, XTAL) + * So please don't use it in your application, we keep it here only for backward compatible + */ +#define TIMER_BASE_CLK (APB_CLK_FREQ) + +/** + * @brief Selects a Timer-Group out of 2 available groups + */ +typedef enum { + TIMER_GROUP_0 = 0, /*!< Hw timer group 0 */ +#if SOC_TIMER_GROUPS > 1 + TIMER_GROUP_1 = 1, /*!< Hw timer group 1 */ +#endif + TIMER_GROUP_MAX /*!< Maximum number of Hw timer groups */ +} timer_group_t; + +/** + * @brief Select a hardware timer from timer groups + */ +typedef enum { + TIMER_0 = 0, /*! 1 + TIMER_INTR_T1 = 1 << 1, /*!< interrupt of timer 1 */ + TIMER_INTR_WDT = 1 << 2, /*!< interrupt of watchdog */ +#else + TIMER_INTR_WDT = 1 << 1, /*!< interrupt of watchdog */ +#endif + TIMER_INTR_NONE = 0 +} timer_intr_t; +FLAG_ATTR(timer_intr_t) + +/** + * @brief Decides the direction of counter + */ +typedef enum { + TIMER_COUNT_DOWN = GPTIMER_COUNT_DOWN, /*!< Descending Count from cnt.high|cnt.low*/ + TIMER_COUNT_UP = GPTIMER_COUNT_UP, /*!< Ascending Count from Zero*/ + TIMER_COUNT_MAX /*!< Maximum number of timer count directions */ +} timer_count_dir_t; + +/** + * @brief Decides whether timer is on or paused + */ +typedef enum { + TIMER_PAUSE, /*!hal), timer_val); + *timer_val = timer_ll_get_counter_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -64,19 +73,22 @@ esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_ ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR); ESP_RETURN_ON_FALSE(time != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); - uint64_t timer_val; - esp_err_t err = timer_get_counter_value(group_num, timer_num, &timer_val); - if (err == ESP_OK) { - uint32_t div; - timer_hal_get_divider(&(p_timer_obj[group_num][timer_num]->hal), &div); + uint64_t timer_val = timer_ll_get_counter_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num); + uint32_t div = p_timer_obj[group_num][timer_num]->divider; + switch (p_timer_obj[group_num][timer_num]->clk_src) { + case GPTIMER_CLK_SRC_APB: *time = (double)timer_val * div / rtc_clk_apb_freq_get(); + break; #if SOC_TIMER_GROUP_SUPPORT_XTAL - if (timer_hal_get_use_xtal(&(p_timer_obj[group_num][timer_num]->hal))) { - *time = (double)timer_val * div / ((int)rtc_clk_xtal_freq_get() * 1000000); - } + case GPTIMER_CLK_SRC_XTAL: + *time = (double)timer_val * div / ((int)rtc_clk_xtal_freq_get() * MHZ); + break; #endif + default: + ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TIMER_TAG, "invalid clock source"); + break; } - return err; + return ESP_OK; } esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val) @@ -96,7 +108,8 @@ esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num) ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_set_counter_enable(&(p_timer_obj[group_num][timer_num]->hal), TIMER_START); + timer_ll_enable_counter(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, true); + p_timer_obj[group_num][timer_num]->counter_en = true; TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -107,7 +120,8 @@ esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num) ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_set_counter_enable(&(p_timer_obj[group_num][timer_num]->hal), TIMER_PAUSE); + timer_ll_enable_counter(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, false); + p_timer_obj[group_num][timer_num]->counter_en = false; TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -119,7 +133,7 @@ esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, ESP_RETURN_ON_FALSE(counter_dir < TIMER_COUNT_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_COUNT_DIR_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_set_counter_increase(&(p_timer_obj[group_num][timer_num]->hal), counter_dir); + timer_ll_set_count_direction(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, counter_dir); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -131,7 +145,8 @@ esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, ESP_RETURN_ON_FALSE(reload < TIMER_AUTORELOAD_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_AUTORELOAD_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_set_auto_reload(&(p_timer_obj[group_num][timer_num]->hal), reload); + timer_ll_enable_auto_reload(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, reload); + p_timer_obj[group_num][timer_num]->auto_reload_en = reload; TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -143,7 +158,8 @@ esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint ESP_RETURN_ON_FALSE(divider > 1 && divider < 65537, ESP_ERR_INVALID_ARG, TIMER_TAG, DIVIDER_RANGE_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_set_divider(&(p_timer_obj[group_num][timer_num]->hal), divider); + timer_ll_set_clock_prescale(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, divider); + p_timer_obj[group_num][timer_num]->divider = divider; TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -154,7 +170,7 @@ esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_set_alarm_value(&(p_timer_obj[group_num][timer_num]->hal), alarm_value); + timer_ll_set_alarm_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, alarm_value); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -166,7 +182,7 @@ esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, ESP_RETURN_ON_FALSE(alarm_value != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_get_alarm_value(&(p_timer_obj[group_num][timer_num]->hal), alarm_value); + *alarm_value = timer_ll_get_alarm_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -178,7 +194,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ ESP_RETURN_ON_FALSE(alarm_en < TIMER_ALARM_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_ALARM_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_set_alarm_enable(&(p_timer_obj[group_num][timer_num]->hal), alarm_en); + timer_ll_enable_alarm(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, alarm_en); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -186,30 +202,20 @@ 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) { + if (timer_obj == NULL || timer_obj->timer_isr_fun.fn == NULL) { return; } - if (timer_obj->timer_isr_fun.fn == NULL) { - return; - } - + uint32_t timer_id = timer_obj->hal.timer_id; + timer_hal_context_t *hal = &timer_obj->hal; TIMER_ENTER_CRITICAL(&timer_spinlock[timer_obj->timer_isr_fun.isr_timer_group]); - { - uint32_t intr_status = 0; - timer_hal_get_intr_status(&(timer_obj->hal), &intr_status); - if (intr_status & BIT(timer_obj->hal.idx)) { - 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)); - //If the timer is set to auto reload, we need enable it again, so it is triggered the next time. - if (timer_hal_get_auto_reload(&timer_obj->hal)) { - timer_hal_set_alarm_enable(&(timer_obj->hal), TIMER_ALARM_EN); - } else { - timer_hal_set_alarm_enable(&(timer_obj->hal), TIMER_ALARM_DIS); - } - } + uint32_t intr_status = timer_ll_get_intr_status(hal->dev); + if (intr_status & TIMER_LL_EVENT_ALARM(timer_id)) { + //Clear intrrupt status + timer_ll_clear_intr_status(hal->dev, TIMER_LL_EVENT_ALARM(timer_id)); + is_awoken = timer_obj->timer_isr_fun.fn(timer_obj->timer_isr_fun.args); + //If the timer is set to auto reload, we need enable it again, so it is triggered the next time + timer_ll_enable_alarm(hal->dev, timer_id, timer_obj->auto_reload_en); } TIMER_EXIT_CRITICAL(&timer_spinlock[timer_obj->timer_isr_fun.isr_timer_group]); @@ -256,11 +262,11 @@ esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR); ESP_RETURN_ON_FALSE(fn != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); - - uint32_t status_reg = 0; - uint32_t mask = 0; - timer_hal_get_status_reg_mask_bit(&(p_timer_obj[group_num][timer_num]->hal), &status_reg, &mask); - return esp_intr_alloc_intrstatus(timer_group_periph_signals.groups[group_num].t0_irq_id + timer_num, intr_alloc_flags, status_reg, mask, fn, arg, handle); + timer_hal_context_t *hal = &p_timer_obj[group_num][timer_num]->hal; + return esp_intr_alloc_intrstatus(timer_group_periph_signals.groups[group_num].timer_irq_id[timer_num], + intr_alloc_flags, + (uint32_t)timer_ll_get_intr_status_reg(hal->dev), + TIMER_LL_EVENT_ALARM(timer_num), fn, arg, handle); } esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer_config_t *config) @@ -269,33 +275,32 @@ esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR); ESP_RETURN_ON_FALSE(config != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR); ESP_RETURN_ON_FALSE(config->divider > 1 && config->divider < 65537, ESP_ERR_INVALID_ARG, TIMER_TAG, DIVIDER_RANGE_ERROR); + ESP_RETURN_ON_FALSE(config->intr_type < TIMER_INTR_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, "only support Level Interrupt"); + if (p_timer_obj[group_num][timer_num] == NULL) { + p_timer_obj[group_num][timer_num] = (timer_obj_t *) heap_caps_calloc(1, sizeof(timer_obj_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num], ESP_ERR_NO_MEM, TIMER_TAG, "no mem for timer object"); + } + timer_hal_context_t *hal = &p_timer_obj[group_num][timer_num]->hal; periph_module_enable(timer_group_periph_signals.groups[group_num].module); - if (p_timer_obj[group_num][timer_num] == NULL) { - p_timer_obj[group_num][timer_num] = (timer_obj_t *) heap_caps_calloc(1, sizeof(timer_obj_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - if (p_timer_obj[group_num][timer_num] == NULL) { - ESP_LOGE(TIMER_TAG, "TIMER driver malloc error"); - return ESP_FAIL; - } - } - TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_init(&(p_timer_obj[group_num][timer_num]->hal), group_num, timer_num); - timer_hal_reset_periph(&(p_timer_obj[group_num][timer_num]->hal)); - timer_hal_clear_intr_status(&(p_timer_obj[group_num][timer_num]->hal)); - timer_hal_set_auto_reload(&(p_timer_obj[group_num][timer_num]->hal), config->auto_reload); - timer_hal_set_divider(&(p_timer_obj[group_num][timer_num]->hal), config->divider); - timer_hal_set_counter_increase(&(p_timer_obj[group_num][timer_num]->hal), config->counter_dir); - timer_hal_set_alarm_enable(&(p_timer_obj[group_num][timer_num]->hal), config->alarm_en); - timer_hal_set_level_int_enable(&(p_timer_obj[group_num][timer_num]->hal), config->intr_type == TIMER_INTR_LEVEL); - if (config->intr_type != TIMER_INTR_LEVEL) { - ESP_LOGW(TIMER_TAG, "only support Level Interrupt, switch to Level Interrupt instead"); - } - timer_hal_set_counter_enable(&(p_timer_obj[group_num][timer_num]->hal), config->counter_en); -#if SOC_TIMER_GROUP_SUPPORT_XTAL - timer_hal_set_use_xtal(&(p_timer_obj[group_num][timer_num]->hal), config->clk_src); -#endif + timer_hal_init(hal, group_num, timer_num); + timer_hal_set_counter_value(hal, 0); + timer_ll_set_clock_source(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, config->clk_src); + timer_ll_set_clock_prescale(hal->dev, timer_num, config->divider); + timer_ll_set_count_direction(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, config->counter_dir); + timer_ll_enable_intr(hal->dev, TIMER_LL_EVENT_ALARM(timer_num), false); + timer_ll_clear_intr_status(hal->dev, TIMER_LL_EVENT_ALARM(timer_num)); + timer_ll_enable_alarm(hal->dev, timer_num, config->alarm_en); + timer_ll_enable_auto_reload(hal->dev, timer_num, config->auto_reload); + timer_ll_enable_counter(hal->dev, timer_num, config->counter_en); + p_timer_obj[group_num][timer_num]->clk_src = config->clk_src; + p_timer_obj[group_num][timer_num]->alarm_en = config->alarm_en; + p_timer_obj[group_num][timer_num]->auto_reload_en = config->auto_reload; + p_timer_obj[group_num][timer_num]->direction = config->counter_dir; + p_timer_obj[group_num][timer_num]->counter_en = config->counter_en; + p_timer_obj[group_num][timer_num]->divider = config->divider; TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; @@ -306,14 +311,15 @@ esp_err_t timer_deinit(timer_group_t group_num, timer_idx_t timer_num) ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR); ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); + timer_hal_context_t *hal = &p_timer_obj[group_num][timer_num]->hal; TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_set_counter_enable(&(p_timer_obj[group_num][timer_num]->hal), TIMER_PAUSE); - timer_hal_intr_disable(&(p_timer_obj[group_num][timer_num]->hal)); - timer_hal_clear_intr_status(&(p_timer_obj[group_num][timer_num]->hal)); + timer_ll_enable_counter(hal->dev, timer_num, false); + timer_ll_enable_intr(hal->dev, TIMER_LL_EVENT_ALARM(timer_num), false); + timer_ll_clear_intr_status(hal->dev, TIMER_LL_EVENT_ALARM(timer_num)); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); - heap_caps_free(p_timer_obj[group_num][timer_num]); + free(p_timer_obj[group_num][timer_num]); p_timer_obj[group_num][timer_num] = NULL; return ESP_OK; @@ -327,20 +333,12 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - config->alarm_en = timer_hal_get_alarm_enable(&(p_timer_obj[group_num][timer_num]->hal)); - config->auto_reload = timer_hal_get_auto_reload(&(p_timer_obj[group_num][timer_num]->hal)); - config->counter_dir = timer_hal_get_counter_increase(&(p_timer_obj[group_num][timer_num]->hal)); - config->counter_en = timer_hal_get_counter_enable(&(p_timer_obj[group_num][timer_num]->hal)); - - uint32_t div; - timer_hal_get_divider(&(p_timer_obj[group_num][timer_num]->hal), &div); - config->divider = div; - - if (timer_hal_get_level_int_enable(&(p_timer_obj[group_num][timer_num]->hal))) { - config->intr_type = TIMER_INTR_LEVEL; - } else { - config->intr_type = TIMER_INTR_MAX; - } + config->alarm_en = p_timer_obj[group_num][timer_num]->alarm_en; + config->auto_reload = p_timer_obj[group_num][timer_num]->auto_reload_en; + config->counter_dir = p_timer_obj[group_num][timer_num]->direction; + config->counter_en = p_timer_obj[group_num][timer_num]->counter_en; + config->divider = p_timer_obj[group_num][timer_num]->divider; + config->intr_type = TIMER_INTR_LEVEL; TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -350,11 +348,7 @@ esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t en_mask) ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - for (int i = 0; i < TIMER_MAX; i++) { - if (en_mask & BIT(i)) { - timer_hal_intr_enable(&(p_timer_obj[group_num][i]->hal)); - } - } + timer_ll_enable_intr(p_timer_obj[group_num][0]->hal.dev, en_mask, true); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -364,11 +358,7 @@ esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t disable ESP_RETURN_ON_FALSE(group_num < TIMER_GROUP_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_GROUP_NUM_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - for (int i = 0; i < TIMER_MAX; i++) { - if (disable_mask & BIT(i)) { - timer_hal_intr_disable(&(p_timer_obj[group_num][i]->hal)); - } - } + timer_ll_enable_intr(p_timer_obj[group_num][0]->hal.dev, disable_mask, false); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -379,7 +369,7 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num) ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_intr_enable(&(p_timer_obj[group_num][timer_num]->hal)); + timer_ll_enable_intr(p_timer_obj[group_num][timer_num]->hal.dev, TIMER_LL_EVENT_ALARM(timer_num), true); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -390,7 +380,7 @@ esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num) ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - timer_hal_intr_disable(&(p_timer_obj[group_num][timer_num]->hal)); + timer_ll_enable_intr(p_timer_obj[group_num][timer_num]->hal.dev, TIMER_LL_EVENT_ALARM(timer_num), false); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -398,20 +388,18 @@ esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num) /* This function is deprecated */ timer_intr_t IRAM_ATTR timer_group_intr_get_in_isr(timer_group_t group_num) { - uint32_t intr_raw_status = 0; - timer_hal_get_intr_raw_status(group_num, &intr_raw_status); - return intr_raw_status; + return timer_ll_get_intr_status(TIMER_LL_GET_HW(group_num)); } uint32_t IRAM_ATTR timer_group_get_intr_status_in_isr(timer_group_t group_num) { uint32_t intr_status = 0; if (p_timer_obj[group_num][TIMER_0] != NULL) { - timer_hal_get_intr_status(&(p_timer_obj[group_num][TIMER_0]->hal), &intr_status); + intr_status = timer_ll_get_intr_status(TIMER_LL_GET_HW(group_num)) & TIMER_LL_EVENT_ALARM(0); } #if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1 else if (p_timer_obj[group_num][TIMER_1] != NULL) { - timer_hal_get_intr_status(&(p_timer_obj[group_num][TIMER_1]->hal), &intr_status); + intr_status = timer_ll_get_intr_status(TIMER_LL_GET_HW(group_num)) & TIMER_LL_EVENT_ALARM(1); } #endif return intr_status; @@ -425,29 +413,29 @@ void IRAM_ATTR timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t void IRAM_ATTR timer_group_clr_intr_status_in_isr(timer_group_t group_num, timer_idx_t timer_num) { - timer_hal_clear_intr_status(&(p_timer_obj[group_num][timer_num]->hal)); + timer_ll_clear_intr_status(p_timer_obj[group_num][timer_num]->hal.dev, TIMER_LL_EVENT_ALARM(timer_num)); } void IRAM_ATTR timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num) { - timer_hal_set_alarm_enable(&(p_timer_obj[group_num][timer_num]->hal), true); + timer_ll_enable_alarm(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, true); } uint64_t IRAM_ATTR timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num) { - uint64_t val; - timer_hal_get_counter_value(&(p_timer_obj[group_num][timer_num]->hal), &val); + uint64_t val = timer_ll_get_counter_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num); return val; } void IRAM_ATTR timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val) { - timer_hal_set_alarm_value(&(p_timer_obj[group_num][timer_num]->hal), alarm_val); + timer_ll_set_alarm_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, alarm_val); } void IRAM_ATTR timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en) { - timer_hal_set_counter_enable(&(p_timer_obj[group_num][timer_num]->hal), counter_en); + timer_ll_enable_counter(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, counter_en); + p_timer_obj[group_num][timer_num]->counter_en = counter_en; } /* This function is deprecated */ @@ -462,7 +450,7 @@ void IRAM_ATTR timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_in bool IRAM_ATTR timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num) { - return timer_hal_get_auto_reload(&(p_timer_obj[group_num][timer_num]->hal)); + return p_timer_obj[group_num][timer_num]->auto_reload_en; } esp_err_t IRAM_ATTR timer_spinlock_take(timer_group_t group_num) @@ -478,3 +466,10 @@ esp_err_t IRAM_ATTR timer_spinlock_give(timer_group_t group_num) TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } + + +STATIC_HAL_REG_CHECK(TIMER_TAG, TIMER_INTR_T0, TIMG_T0_INT_CLR); +#if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1 +STATIC_HAL_REG_CHECK(TIMER_TAG, TIMER_INTR_T1, TIMG_T1_INT_CLR); +#endif +STATIC_HAL_REG_CHECK(TIMER_TAG, TIMER_INTR_WDT, TIMG_WDT_INT_CLR); diff --git a/components/esp_event/test/test_event.c b/components/esp_event/test/test_event.c index 605cbc3381..0dc636cf5c 100644 --- a/components/esp_event/test/test_event.c +++ b/components/esp_event/test/test_event.c @@ -2000,13 +2000,14 @@ TEST_CASE("can post events from interrupt handler", "[event]") SemaphoreHandle_t sem = xSemaphoreCreateBinary(); /* Select and initialize basic parameters of the timer */ - timer_config_t config; - config.divider = TIMER_DIVIDER; - config.counter_dir = TIMER_COUNT_UP; - config.counter_en = TIMER_PAUSE; - config.alarm_en = TIMER_ALARM_EN; - config.intr_type = TIMER_INTR_LEVEL; - config.auto_reload = false; + timer_config_t config = { + .divider = TIMER_DIVIDER, + .counter_dir = TIMER_COUNT_UP, + .counter_en = TIMER_PAUSE, + .alarm_en = TIMER_ALARM_EN, + .intr_type = TIMER_INTR_LEVEL, + .auto_reload = false, + }; timer_init(TIMER_GROUP_0, TIMER_0, &config); /* Timer's counter will initially start from value below. diff --git a/components/esp_hw_support/test/test_dport.c b/components/esp_hw_support/test/test_dport.c index 039e183b8c..7f1b49a192 100644 --- a/components/esp_hw_support/test/test_dport.c +++ b/components/esp_hw_support/test/test_dport.c @@ -27,7 +27,6 @@ #include "soc/rtc.h" #include "hal/cpu_hal.h" #include "esp_intr_alloc.h" -#include "driver/timer.h" #define MHZ (1000000) @@ -347,7 +346,7 @@ TEST_CASE("BENCHMARK for DPORT access performance", "[freertos]") uint32_t xt_highint5_read_apb; #ifndef CONFIG_FREERTOS_UNICORE -timer_isr_handle_t inth; +intr_handle_t inth; xSemaphoreHandle sync_sema; static void init_hi_interrupt(void *arg) diff --git a/components/esp_ringbuf/test/test_ringbuf.c b/components/esp_ringbuf/test/test_ringbuf.c index 77f4b5235a..29554b13a2 100644 --- a/components/esp_ringbuf/test/test_ringbuf.c +++ b/components/esp_ringbuf/test/test_ringbuf.c @@ -401,13 +401,14 @@ static void setup_timer(void) //Setup timer for ISR int timer_group = TIMER_GROUP; int timer_idx = TIMER_NUMBER; - timer_config_t config; - config.alarm_en = 1; - config.auto_reload = 1; - config.counter_dir = TIMER_COUNT_UP; - config.divider = 10000; - config.intr_type = TIMER_INTR_LEVEL; - config.counter_en = TIMER_PAUSE; + timer_config_t config = { + .alarm_en = 1, + .auto_reload = 1, + .counter_dir = TIMER_COUNT_UP, + .divider = 10000, + .intr_type = TIMER_INTR_LEVEL, + .counter_en = TIMER_PAUSE, + }; timer_init(timer_group, timer_idx, &config); //Configure timer timer_pause(timer_group, timer_idx); //Stop timer counter timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); //Load counter value diff --git a/components/esp_system/int_wdt.c b/components/esp_system/int_wdt.c index 3205422af2..bb0e476b9f 100644 --- a/components/esp_system/int_wdt.c +++ b/components/esp_system/int_wdt.c @@ -1,16 +1,8 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include #include @@ -25,7 +17,6 @@ #include "esp_attr.h" #include "esp_freertos_hooks.h" #include "soc/timer_periph.h" -#include "driver/timer.h" #include "driver/periph_ctrl.h" #include "esp_int_wdt.h" #include "esp_private/system_internal.h" diff --git a/components/esp_system/task_wdt.c b/components/esp_system/task_wdt.c index cde04ce719..fe379982da 100644 --- a/components/esp_system/task_wdt.c +++ b/components/esp_system/task_wdt.c @@ -22,7 +22,6 @@ #include "esp_freertos_hooks.h" #include "soc/timer_periph.h" #include "esp_log.h" -#include "driver/timer.h" #include "driver/periph_ctrl.h" #include "esp_task_wdt.h" #include "esp_private/system_internal.h" diff --git a/components/freemodbus/port/porttimer.c b/components/freemodbus/port/porttimer.c index 565d58ed02..58ddba0d54 100644 --- a/components/freemodbus/port/porttimer.c +++ b/components/freemodbus/port/porttimer.c @@ -1,16 +1,7 @@ -/* Copyright 2018 Espressif Systems (Shanghai) PTE LTD +/* + * SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 */ /* * FreeModbus Libary: ESP32 Port Demo Application @@ -57,7 +48,7 @@ #define MB_US50_FREQ (20000) // 20kHz 1/20000 = 50mks #define MB_DISCR_TIME_US (50) // 50uS = one discreet for timer -#define MB_TIMER_PRESCALLER ((TIMER_BASE_CLK / MB_US50_FREQ) - 1); +#define MB_TIMER_PRESCALLER ((TIMER_BASE_CLK / MB_US50_FREQ) - 1) #define MB_TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds #define MB_TIMER_DIVIDER ((TIMER_BASE_CLK / 1000000UL) * MB_DISCR_TIME_US - 1) // divider for 50uS #define MB_TIMER_WITH_RELOAD (1) @@ -84,13 +75,14 @@ BOOL xMBPortTimersInit(USHORT usTim1Timerout50us) MB_PORT_CHECK((usTim1Timerout50us > 0), FALSE, "Modbus timeout discreet is incorrect."); esp_err_t xErr; - timer_config_t config; - config.alarm_en = TIMER_ALARM_EN; - config.auto_reload = MB_TIMER_WITH_RELOAD; - config.counter_dir = TIMER_COUNT_UP; - config.divider = MB_TIMER_PRESCALLER; - config.intr_type = TIMER_INTR_LEVEL; - config.counter_en = TIMER_PAUSE; + timer_config_t config = { + .alarm_en = TIMER_ALARM_EN, + .auto_reload = MB_TIMER_WITH_RELOAD, + .counter_dir = TIMER_COUNT_UP, + .divider = MB_TIMER_PRESCALLER, + .intr_type = TIMER_INTR_LEVEL, + .counter_en = TIMER_PAUSE, + }; // Configure timer xErr = timer_init(usTimerGroupIndex, usTimerIndex, &config); MB_PORT_CHECK((xErr == ESP_OK), FALSE, diff --git a/components/freemodbus/port/porttimer_m.c b/components/freemodbus/port/porttimer_m.c index e473195ef3..4bcd1ac03b 100644 --- a/components/freemodbus/port/porttimer_m.c +++ b/components/freemodbus/port/porttimer_m.c @@ -1,16 +1,7 @@ -/* Copyright 2018 Espressif Systems (Shanghai) PTE LTD +/* + * SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 */ /* * FreeModbus Libary: ESP32 Port Demo Application @@ -45,7 +36,7 @@ #define MB_US50_FREQ (20000) // 20kHz 1/20000 = 50mks #define MB_TICK_TIME_US (50) // 50uS = one tick for timer -#define MB_TIMER_PRESCALLER ((TIMER_BASE_CLK / MB_US50_FREQ) - 1); +#define MB_TIMER_PRESCALLER ((TIMER_BASE_CLK / MB_US50_FREQ) - 1) #define MB_TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) #define MB_TIMER_DIVIDER ((TIMER_BASE_CLK / 1000000UL) * MB_TICK_TIME_US - 1) // divider for 50uS #define MB_TIMER_WITH_RELOAD (1) @@ -77,13 +68,14 @@ BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us) // Save timer reload value for Modbus T35 period usT35TimeOut50us = usTimeOut50us; esp_err_t xErr; - timer_config_t config; - config.alarm_en = TIMER_ALARM_EN; - config.auto_reload = MB_TIMER_WITH_RELOAD; - config.counter_dir = TIMER_COUNT_UP; - config.divider = MB_TIMER_PRESCALLER; - config.intr_type = TIMER_INTR_LEVEL; - config.counter_en = TIMER_PAUSE; + timer_config_t config = { + .alarm_en = TIMER_ALARM_EN, + .auto_reload = MB_TIMER_WITH_RELOAD, + .counter_dir = TIMER_COUNT_UP, + .divider = MB_TIMER_PRESCALLER, + .intr_type = TIMER_INTR_LEVEL, + .counter_en = TIMER_PAUSE, + }; // Configure timer xErr = timer_init(usTimerGroupIndex, usTimerIndex, &config); MB_PORT_CHECK((xErr == ESP_OK), FALSE, diff --git a/components/freertos/test/test_freertos_eventgroups.c b/components/freertos/test/test_freertos_eventgroups.c index db298504c0..2ebe6f7dfc 100644 --- a/components/freertos/test/test_freertos_eventgroups.c +++ b/components/freertos/test/test_freertos_eventgroups.c @@ -168,13 +168,14 @@ static void setup_timer(void) //Setup timer for ISR int timer_group = TIMER_GROUP_0; int timer_idx = TIMER_NUMBER; - timer_config_t config; - config.alarm_en = 1; - config.auto_reload = 1; - config.counter_dir = TIMER_COUNT_UP; - config.divider = TIMER_DIVIDER; - config.intr_type = TIMER_INTR_LEVEL; - config.counter_en = TIMER_PAUSE; + timer_config_t config = { + .alarm_en = 1, + .auto_reload = 1, + .counter_dir = TIMER_COUNT_UP, + .divider = TIMER_DIVIDER, + .intr_type = TIMER_INTR_LEVEL, + .counter_en = TIMER_PAUSE, + }; timer_init(timer_group, timer_idx, &config); //Configure timer timer_pause(timer_group, timer_idx); //Stop timer counter timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); //Load counter value diff --git a/components/freertos/test/test_freertos_task_notify.c b/components/freertos/test/test_freertos_task_notify.c index 812fdbd746..5d5168bc04 100644 --- a/components/freertos/test/test_freertos_task_notify.c +++ b/components/freertos/test/test_freertos_task_notify.c @@ -127,13 +127,14 @@ static void timerg0_init(void *isr_handle) int timer_group = TIMER_GROUP_0; int timer_idx = xPortGetCoreID(); - timer_config_t config; - config.alarm_en = 1; - config.auto_reload = 1; - config.counter_dir = TIMER_COUNT_UP; - config.divider = TIMER_DIVIDER; - config.intr_type = TIMER_INTR_LEVEL; - config.counter_en = TIMER_PAUSE; + timer_config_t config = { + .alarm_en = 1, + .auto_reload = 1, + .counter_dir = TIMER_COUNT_UP, + .divider = TIMER_DIVIDER, + .intr_type = TIMER_INTR_LEVEL, + .counter_en = TIMER_PAUSE, + }; /*Configure timer*/ timer_init(timer_group, timer_idx, &config); diff --git a/components/hal/esp32/include/hal/mwdt_ll.h b/components/hal/esp32/include/hal/mwdt_ll.h index 267f15ef2c..85a4e7445e 100644 --- a/components/hal/esp32/include/hal/mwdt_ll.h +++ b/components/hal/esp32/include/hal/mwdt_ll.h @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ // The LL layer for Timer Group register operations. // Note that most of the register operations in this layer are non-atomic operations. @@ -24,6 +16,7 @@ extern "C" { #include #include #include "hal/misc.h" +#include "hal/assert.h" #include "soc/timer_periph.h" #include "soc/timer_group_struct.h" #include "hal/wdt_types.h" @@ -51,7 +44,7 @@ _Static_assert(WDT_RESET_SIG_LENGTH_3_2us == TIMG_WDT_RESET_LENGTH_3200_NS, "Add */ FORCE_INLINE_ATTR void mwdt_ll_enable(timg_dev_t *hw) { - hw->wdt_config0.en = 1; + hw->wdtconfig0.wdt_en = 1; } /** @@ -64,7 +57,7 @@ FORCE_INLINE_ATTR void mwdt_ll_enable(timg_dev_t *hw) */ FORCE_INLINE_ATTR void mwdt_ll_disable(timg_dev_t *hw) { - hw->wdt_config0.en = 0; + hw->wdtconfig0.wdt_en = 0; } /** @@ -75,7 +68,7 @@ FORCE_INLINE_ATTR void mwdt_ll_disable(timg_dev_t *hw) */ FORCE_INLINE_ATTR bool mwdt_ll_check_if_enabled(timg_dev_t *hw) { - return (hw->wdt_config0.en) ? true : false; + return (hw->wdtconfig0.wdt_en) ? true : false; } /** @@ -89,24 +82,25 @@ FORCE_INLINE_ATTR bool mwdt_ll_check_if_enabled(timg_dev_t *hw) FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, uint32_t timeout, wdt_stage_action_t behavior) { switch (stage) { - case WDT_STAGE0: - hw->wdt_config0.stg0 = behavior; - hw->wdt_config2 = timeout; - break; - case WDT_STAGE1: - hw->wdt_config0.stg1 = behavior; - hw->wdt_config3 = timeout; - break; - case WDT_STAGE2: - hw->wdt_config0.stg2 = behavior; - hw->wdt_config4 = timeout; - break; - case WDT_STAGE3: - hw->wdt_config0.stg3 = behavior; - hw->wdt_config5 = timeout; - break; - default: - break; + case WDT_STAGE0: + hw->wdtconfig0.wdt_stg0 = behavior; + hw->wdtconfig2.wdt_stg0_hold = timeout; + break; + case WDT_STAGE1: + hw->wdtconfig0.wdt_stg1 = behavior; + hw->wdtconfig3.wdt_stg1_hold = timeout; + break; + case WDT_STAGE2: + hw->wdtconfig0.wdt_stg2 = behavior; + hw->wdtconfig4.wdt_stg2_hold = timeout; + break; + case WDT_STAGE3: + hw->wdtconfig0.wdt_stg3 = behavior; + hw->wdtconfig5.wdt_stg3_hold = timeout; + break; + default: + HAL_ASSERT(false && "unsupported WDT stage"); + break; } } @@ -119,20 +113,21 @@ FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, u FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage) { switch (stage) { - case WDT_STAGE0: - hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF; - break; - case WDT_STAGE1: - hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF; - break; - case WDT_STAGE2: - hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF; - break; - case WDT_STAGE3: - hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF; - break; - default: - break; + case WDT_STAGE0: + hw->wdtconfig0.wdt_stg0 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE1: + hw->wdtconfig0.wdt_stg1 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE2: + hw->wdtconfig0.wdt_stg2 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE3: + hw->wdtconfig0.wdt_stg3 = WDT_STAGE_ACTION_OFF; + break; + default: + HAL_ASSERT(false && "unsupported WDT stage"); + break; } } @@ -144,7 +139,7 @@ FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage) */ FORCE_INLINE_ATTR void mwdt_ll_set_edge_intr(timg_dev_t *hw, bool enable) { - hw->wdt_config0.edge_int_en = (enable) ? 1 : 0; + hw->wdtconfig0.wdt_edge_int_en = enable; } /** @@ -155,7 +150,7 @@ FORCE_INLINE_ATTR void mwdt_ll_set_edge_intr(timg_dev_t *hw, bool enable) */ FORCE_INLINE_ATTR void mwdt_ll_set_level_intr(timg_dev_t *hw, bool enable) { - hw->wdt_config0.level_int_en = (enable) ? 1 : 0; + hw->wdtconfig0.wdt_level_int_en = enable; } /** @@ -166,7 +161,7 @@ FORCE_INLINE_ATTR void mwdt_ll_set_level_intr(timg_dev_t *hw, bool enable) */ FORCE_INLINE_ATTR void mwdt_ll_set_cpu_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length) { - hw->wdt_config0.cpu_reset_length = length; + hw->wdtconfig0.wdt_cpu_reset_length = length; } /** @@ -177,7 +172,7 @@ FORCE_INLINE_ATTR void mwdt_ll_set_cpu_reset_length(timg_dev_t *hw, wdt_reset_si */ FORCE_INLINE_ATTR void mwdt_ll_set_sys_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length) { - hw->wdt_config0.sys_reset_length = length; + hw->wdtconfig0.wdt_sys_reset_length = length; } /** @@ -190,9 +185,9 @@ FORCE_INLINE_ATTR void mwdt_ll_set_sys_reset_length(timg_dev_t *hw, wdt_reset_si * WDT's enable bit is set to 0. Flashboot mode for TG0 is automatically enabled * on flashboot, and should be disabled by software when flashbooting completes. */ -FORCE_INLINE_ATTR void mwdt_ll_set_flashboot_en(timg_dev_t* hw, bool enable) +FORCE_INLINE_ATTR void mwdt_ll_set_flashboot_en(timg_dev_t *hw, bool enable) { - hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0; + hw->wdtconfig0.wdt_flashboot_mod_en = (enable) ? 1 : 0; } /** @@ -203,7 +198,7 @@ FORCE_INLINE_ATTR void mwdt_ll_set_flashboot_en(timg_dev_t* hw, bool enable) */ FORCE_INLINE_ATTR void mwdt_ll_set_prescaler(timg_dev_t *hw, uint32_t prescaler) { - HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wdt_config1, clk_prescale, prescaler); + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wdtconfig1, wdt_clk_prescaler, prescaler); } /** @@ -215,7 +210,7 @@ FORCE_INLINE_ATTR void mwdt_ll_set_prescaler(timg_dev_t *hw, uint32_t prescaler) */ FORCE_INLINE_ATTR void mwdt_ll_feed(timg_dev_t *hw) { - hw->wdt_feed = 1; + hw->wdtfeed.wdt_feed = 1; } /** @@ -225,7 +220,7 @@ FORCE_INLINE_ATTR void mwdt_ll_feed(timg_dev_t *hw) */ FORCE_INLINE_ATTR void mwdt_ll_write_protect_enable(timg_dev_t *hw) { - hw->wdt_wprotect = 0; + hw->wdtwprotect.wdt_wkey = 0; } /** @@ -235,7 +230,7 @@ FORCE_INLINE_ATTR void mwdt_ll_write_protect_enable(timg_dev_t *hw) */ FORCE_INLINE_ATTR void mwdt_ll_write_protect_disable(timg_dev_t *hw) { - hw->wdt_wprotect = TIMG_WDT_WKEY_VALUE; + hw->wdtwprotect.wdt_wkey = TIMG_WDT_WKEY_VALUE; } /** @@ -243,9 +238,9 @@ FORCE_INLINE_ATTR void mwdt_ll_write_protect_disable(timg_dev_t *hw) * * @param hw Start address of the peripheral registers. */ -FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t* hw) +FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t *hw) { - hw->int_clr_timers.wdt = 1; + hw->int_clr_timers.wdt_int_clr = 1; } /** @@ -254,9 +249,9 @@ FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t* hw) * @param hw Beginning address of the peripheral registers. * @param enable Whether to enable the MWDT interrupt */ -FORCE_INLINE_ATTR void mwdt_ll_set_intr_enable(timg_dev_t* hw, bool enable) +FORCE_INLINE_ATTR void mwdt_ll_set_intr_enable(timg_dev_t *hw, bool enable) { - hw->int_ena.wdt = (enable) ? 1 : 0; + hw->int_ena_timers.wdt_int_ena = enable; } #ifdef __cplusplus diff --git a/components/hal/esp32/include/hal/timer_ll.h b/components/hal/esp32/include/hal/timer_ll.h index 35ce7d1025..fbd44ddb1f 100644 --- a/components/hal/esp32/include/hal/timer_ll.h +++ b/components/hal/esp32/include/hal/timer_ll.h @@ -1,382 +1,250 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ -// The LL layer for Timer Group register operations. // Note that most of the register operations in this layer are non-atomic operations. #pragma once +#include +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/timer_types.h" +#include "soc/timer_group_struct.h" + #ifdef __cplusplus extern "C" { #endif -#include -#include "hal/misc.h" -#include "hal/assert.h" -#include "hal/timer_types.h" -#include "soc/timer_periph.h" -#include "soc/timer_group_struct.h" - -_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); -_Static_assert(TIMER_INTR_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); -_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); - -// Get timer group instance with giving group number -#define TIMER_LL_GET_HW(num) ((num == 0) ? (&TIMERG0) : (&TIMERG1)) +// Get timer group register base address with giving group number +#define TIMER_LL_GET_HW(group_id) ((group_id == 0) ? (&TIMERG0) : (&TIMERG1)) +#define TIMER_LL_EVENT_ALARM(timer_id) (1 << (timer_id)) /** - * @brief Set timer clock prescale value + * @brief Set clock source for timer * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param divider Prescale value (0 and 1 are not valid) - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param clk_src Clock source */ -static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t divider) +static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num, gptimer_clock_source_t clk_src) +{ + switch (clk_src) { + case GPTIMER_CLK_SRC_APB: + break; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + +/** + * @brief Enable alarm event + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable alarm + * False: disable alarm + */ +__attribute__((always_inline)) +static inline void timer_ll_enable_alarm(timg_dev_t *hw, uint32_t timer_num, bool en) +{ + hw->hw_timer[timer_num].config.tx_alarm_en = en; + // use level type interrupt + hw->hw_timer[timer_num].config.tx_level_int_en = en; +} + +/** + * @brief Set clock prescale for timer + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param divider Prescale value (0 and 1 are not valid) + */ +static inline void timer_ll_set_clock_prescale(timg_dev_t *hw, uint32_t timer_num, uint32_t divider) { HAL_ASSERT(divider >= 2 && divider <= 65536); if (divider >= 65536) { divider = 0; } - int timer_en = hw->hw_timer[timer_num].config.enable; - hw->hw_timer[timer_num].config.enable = 0; - HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hw_timer[timer_num].config, divider, divider); - hw->hw_timer[timer_num].config.enable = timer_en; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hw_timer[timer_num].config, tx_divider, divider); } /** - * @brief Get timer clock prescale value + * @brief Enable auto-reload mode * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param divider Pointer to accept the prescale value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable auto reload mode + * False: disable auto reload mode */ -static inline void timer_ll_get_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t *divider) +static inline void timer_ll_enable_auto_reload(timg_dev_t *hw, uint32_t timer_num, bool en) { - uint32_t d = HAL_FORCE_READ_U32_REG_FIELD(hw->hw_timer[timer_num].config, divider); - if (d == 0) { - d = 65536; - } else if (d == 1) { - d = 2; + hw->hw_timer[timer_num].config.tx_autoreload = en; +} + +/** + * @brief Set count direction + * + * @param hw Timer peripheral register base address + * @param timer_num Timer number in the group + * @param direction Count direction + */ +static inline void timer_ll_set_count_direction(timg_dev_t *hw, uint32_t timer_num, gptimer_count_direction_t direction) +{ + hw->hw_timer[timer_num].config.tx_increase = direction == GPTIMER_COUNT_UP; +} + +/** + * @brief Enable timer, start couting + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable the counter + * False: disable the counter + */ +__attribute__((always_inline)) +static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, bool en) +{ + hw->hw_timer[timer_num].config.tx_en = en; +} + +/** + * @brief Get counter value + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * + * @return counter value + */ +__attribute__((always_inline)) +static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) +{ + hw->hw_timer[timer_num].update.tx_update = 1; + // Timer register is in a different clock domain from Timer hardware logic + // We need to wait for the update to take effect before fetching the count value + while (hw->hw_timer[timer_num].update.tx_update) { } - *divider = d; + return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); } /** - * @brief Load counter value into time-base counter + * @brief Set alarm value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param load_val Counter value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param alarm_value When counter reaches alarm value, alarm event will be triggered */ -static inline void timer_ll_set_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t load_val) +__attribute__((always_inline)) +static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, uint64_t alarm_value) { - hw->hw_timer[timer_num].load_high = (uint32_t) (load_val >> 32); - hw->hw_timer[timer_num].load_low = (uint32_t) load_val; - hw->hw_timer[timer_num].reload = 1; + hw->hw_timer[timer_num].alarmhi.tx_alarm_hi = (uint32_t) (alarm_value >> 32); + hw->hw_timer[timer_num].alarmlo.tx_alarm_lo = (uint32_t) alarm_value; } /** - * @brief Get counter value from time-base counter + * @brief Get alarm value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param timer_val Pointer to accept the counter value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @return Counter value to trigger the alarm event */ -FORCE_INLINE_ATTR void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val) +static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) { - hw->hw_timer[timer_num].update = 1; - while (hw->hw_timer[timer_num].update) {} - *timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low); + return ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); } /** - * @brief Set counter mode, include increment mode and decrement mode. + * @brief Set reload value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param increase_en True to increment mode, fasle to decrement mode - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param reload_val Reload counter value */ -static inline void timer_ll_set_counter_increase(timg_dev_t *hw, timer_idx_t timer_num, bool increase_en) +static inline void timer_ll_set_reload_value(timg_dev_t *hw, uint32_t timer_num, uint64_t load_val) { - hw->hw_timer[timer_num].config.increase = increase_en; + hw->hw_timer[timer_num].loadhi.tx_load_hi = (uint32_t) (load_val >> 32); + hw->hw_timer[timer_num].loadlo.tx_load_lo = (uint32_t) load_val; } /** - * @brief Get counter mode, include increment mode and decrement mode. + * @brief Get reload value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Increment mode - * - false Decrement mode + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @return reload count value */ -static inline bool timer_ll_get_counter_increase(timg_dev_t *hw, timer_idx_t timer_num) +static inline uint64_t timer_ll_get_reload_value(timg_dev_t *hw, uint32_t timer_num) { - return hw->hw_timer[timer_num].config.increase; + return ((uint64_t)hw->hw_timer[timer_num].loadhi.tx_load_hi << 32) | (hw->hw_timer[timer_num].loadlo.tx_load_lo); } /** - * @brief Set counter status, enable or disable counter. + * @brief Trigger software reload, value set by `timer_ll_set_reload_value()` will be reflected into counter immediately * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param counter_en True to enable counter, false to disable counter - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group */ -FORCE_INLINE_ATTR void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, bool counter_en) +static inline void timer_ll_trigger_soft_reload(timg_dev_t *hw, uint32_t timer_num) { - hw->hw_timer[timer_num].config.enable = counter_en; + hw->hw_timer[timer_num].load.tx_load = 1; } /** - * @brief Get counter status. + * @brief Enable timer interrupt by mask * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable counter - * - false Disable conuter + * @param hw Timer Group register base address + * @param mask Mask of interrupt events + * @param en True: enable interrupt + * False: disable interrupt */ -static inline bool timer_ll_get_counter_enable(timg_dev_t *hw, timer_idx_t timer_num) +__attribute__((always_inline)) +static inline void timer_ll_enable_intr(timg_dev_t *hw, uint32_t mask, bool en) { - return hw->hw_timer[timer_num].config.enable; + if (en) { + hw->int_ena_timers.val |= mask; + } else { + hw->int_ena_timers.val &= ~mask; + } } /** - * @brief Set auto reload mode. + * @brief Get interrupt status * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode + * @param hw Timer Group register base address * - * @return None + * @return Interrupt status */ -static inline void timer_ll_set_auto_reload(timg_dev_t *hw, timer_idx_t timer_num, bool auto_reload_en) +__attribute__((always_inline)) +static inline uint32_t timer_ll_get_intr_status(timg_dev_t *hw) { - hw->hw_timer[timer_num].config.autoreload = auto_reload_en; + return hw->int_st_timers.val & 0x03; } /** - * @brief Get auto reload mode. + * @brief Clear interrupt status by mask * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable auto reload mode - * - false Disable auto reload mode + * @param hw Timer Group register base address + * @param mask Interrupt events mask */ -FORCE_INLINE_ATTR bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num) +__attribute__((always_inline)) +static inline void timer_ll_clear_intr_status(timg_dev_t *hw, uint32_t mask) { - return hw->hw_timer[timer_num].config.autoreload; + hw->int_clr_timers.val = mask; } /** - * @brief Set the counter value to trigger the alarm. + * @brief Enable the register clock forever * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_value Counter value to trigger the alarm - * - * @return None + * @param hw Timer Group register base address + * @param en True: Enable the register clock forever + * False: Register clock is enabled only when register operation happens */ -FORCE_INLINE_ATTR void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value) +static inline void timer_ll_enable_register_clock_always_on(timg_dev_t *hw, bool en) { - hw->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32); - hw->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value; -} - -/** - * @brief Get the counter value to trigger the alarm. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_value Pointer to accept the counter value to trigger the alarm - * - * @return None - */ -static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value) -{ - *alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarm_high << 32) | (hw->hw_timer[timer_num].alarm_low); -} - -/** - * @brief Set the alarm status, enable or disable the alarm. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_en True to enable alarm, false to disable alarm - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en) -{ - hw->hw_timer[timer_num].config.alarm_en = alarm_en; -} - -/** - * @brief Get the alarm status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable alarm - * - false Disable alarm - */ -static inline bool timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.alarm_en; -} - -/** - * @brief Enable timer interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_intr_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - hw->int_ena.val |= BIT(timer_num); - hw->hw_timer[timer_num].config.level_int_en = 1; -} - -/** - * @brief Disable timer interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_intr_disable(timg_dev_t *hw, timer_idx_t timer_num) -{ - hw->int_ena.val &= (~BIT(timer_num)); - hw->hw_timer[timer_num].config.level_int_en = 0; -} - -/** - * @brief Disable timer interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_clear_intr_status(timg_dev_t *hw, timer_idx_t timer_num) -{ - hw->int_clr_timers.val |= BIT(timer_num); -} - -/** - * @brief Get interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param intr_status Interrupt status - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_get_intr_status(timg_dev_t *hw, uint32_t *intr_status) -{ - *intr_status = hw->int_st_timers.val & 0x03; -} - -/** - * @brief Get interrupt raw status. - * - * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param intr_raw_status Interrupt raw status - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_get_intr_raw_status(timer_group_t group_num, uint32_t *intr_raw_status) -{ - timg_dev_t *hw = TIMER_LL_GET_HW(group_num); - *intr_raw_status = hw->int_raw.val & 0x03; -} - -/** - * @brief Set the level interrupt status, enable or disable the level interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param level_int_en True to enable level interrupt, false to disable level interrupt - * - * @return None - */ -static inline void timer_ll_set_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool level_int_en) -{ - hw->hw_timer[timer_num].config.level_int_en = level_int_en; -} - -/** - * @brief Get the level interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable level interrupt - * - false Disable level interrupt - */ -static inline bool timer_ll_get_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.level_int_en; -} - -/** - * @brief Set the edge interrupt status, enable or disable the edge interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param edge_int_en True to enable edge interrupt, false to disable edge interrupt - * - * @return None - */ -static inline void timer_ll_set_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool edge_int_en) -{ - hw->hw_timer[timer_num].config.edge_int_en = edge_int_en; -} - -/** - * @brief Get the edge interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable edge interrupt - * - false Disable edge interrupt - */ -static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.edge_int_en; + hw->regclk.clk_en = en; } /** @@ -386,14 +254,9 @@ static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t time * * @return Interrupt status register address */ -static inline uint32_t timer_ll_get_intr_status_reg(timg_dev_t *hw) +static inline volatile void *timer_ll_get_intr_status_reg(timg_dev_t *hw) { - return (uint32_t) & (hw->int_st_timers.val); -} - -static inline uint32_t timer_ll_get_intr_mask_bit(timg_dev_t *hw, timer_idx_t timer_num) -{ - return (1U << timer_num); + return &hw->int_st_timers.val; } #ifdef __cplusplus diff --git a/components/hal/esp32c3/include/hal/mwdt_ll.h b/components/hal/esp32c3/include/hal/mwdt_ll.h index 944108439e..328af264e1 100644 --- a/components/hal/esp32c3/include/hal/mwdt_ll.h +++ b/components/hal/esp32c3/include/hal/mwdt_ll.h @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ // The LL layer for Timer Group register operations. // Note that most of the register operations in this layer are non-atomic operations. @@ -26,6 +18,7 @@ extern "C" { #include "soc/timer_periph.h" #include "soc/timer_group_struct.h" #include "hal/wdt_types.h" +#include "hal/assert.h" #include "esp_attr.h" //Type check wdt_stage_action_t @@ -112,6 +105,7 @@ FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, u hw->wdtconfig5.wdt_stg3_hold = timeout; break; default: + HAL_ASSERT(false && "unsupported WDT stage"); break; } //Config registers are updated asynchronously @@ -140,6 +134,7 @@ FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage) hw->wdtconfig0.wdt_stg3 = WDT_STAGE_ACTION_OFF; break; default: + HAL_ASSERT(false && "unsupported WDT stage"); break; } //Config registers are updated asynchronously diff --git a/components/hal/esp32c3/include/hal/timer_ll.h b/components/hal/esp32c3/include/hal/timer_ll.h index 5e51b102f1..8f2d633f1c 100644 --- a/components/hal/esp32c3/include/hal/timer_ll.h +++ b/components/hal/esp32c3/include/hal/timer_ll.h @@ -1,431 +1,265 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ -// The LL layer for Timer Group register operations. // Note that most of the register operations in this layer are non-atomic operations. #pragma once +#include +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/timer_types.h" +#include "soc/timer_group_struct.h" + #ifdef __cplusplus extern "C" { #endif -#include -#include "hal/misc.h" -#include "soc/timer_periph.h" -#include "soc/timer_group_struct.h" -#include "hal/timer_types.h" -#include "hal/assert.h" - -_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); -_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); - -typedef struct { - timg_dev_t *dev; - timer_idx_t idx; -} timer_ll_context_t; - -// Get timer group instance with giving group number -#define TIMER_LL_GET_HW(num) ((num == 0) ? (&TIMERG0) : (&TIMERG1)) +// Get timer group register base address with giving group number +#define TIMER_LL_GET_HW(group_id) ((group_id == 0) ? (&TIMERG0) : (&TIMERG1)) +#define TIMER_LL_EVENT_ALARM(timer_id) (1 << (timer_id)) /** - * @brief Set timer clock prescale value + * @brief Set clock source for timer * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param divider Prescale value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param clk_src Clock source */ -static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t divider) +static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num, gptimer_clock_source_t clk_src) +{ + switch (clk_src) { + case GPTIMER_CLK_SRC_APB: + hw->hw_timer[timer_num].config.tx_use_xtal = 0; + break; + case GPTIMER_CLK_SRC_XTAL: + hw->hw_timer[timer_num].config.tx_use_xtal = 1; + break; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + +/** + * @brief Enable alarm event + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable alarm + * False: disable alarm + */ +__attribute__((always_inline)) +static inline void timer_ll_enable_alarm(timg_dev_t *hw, uint32_t timer_num, bool en) +{ + hw->hw_timer[timer_num].config.tx_alarm_en = en; +} + +/** + * @brief Set clock prescale for timer + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param divider Prescale value (0 and 1 are not valid) + */ +static inline void timer_ll_set_clock_prescale(timg_dev_t *hw, uint32_t timer_num, uint32_t divider) { HAL_ASSERT(divider >= 2 && divider <= 65536); if (divider >= 65536) { divider = 0; } - int timer_en = hw->hw_timer[timer_num].config.tx_en; - hw->hw_timer[timer_num].config.tx_en = 0; - hw->hw_timer[timer_num].config.tx_divcnt_rst = 1; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hw_timer[timer_num].config, tx_divider, divider); - hw->hw_timer[timer_num].config.tx_en = timer_en; + hw->hw_timer[timer_num].config.tx_divcnt_rst = 1; } /** - * @brief Get timer clock prescale value + * @brief Enable auto-reload mode * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param divider Pointer to accept the prescale value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable auto reload mode + * False: disable auto reload mode */ -static inline void timer_ll_get_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t *divider) +static inline void timer_ll_enable_auto_reload(timg_dev_t *hw, uint32_t timer_num, bool en) { - uint32_t d = HAL_FORCE_READ_U32_REG_FIELD(hw->hw_timer[timer_num].config, tx_divider); - if (d == 0) { - d = 65536; - } else if (d == 1) { - d = 2; - } - *divider = d; + hw->hw_timer[timer_num].config.tx_autoreload = en; } /** - * @brief Load counter value into time-base counter + * @brief Set count direction * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param load_val Counter value - * - * @return None + * @param hw Timer peripheral register base address + * @param timer_num Timer number in the group + * @param direction Count direction */ -static inline void timer_ll_set_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t load_val) +static inline void timer_ll_set_count_direction(timg_dev_t *hw, uint32_t timer_num, gptimer_count_direction_t direction) { - hw->hw_timer[timer_num].loadhi.tx_load_hi = (uint32_t) (load_val >> 32); - hw->hw_timer[timer_num].loadlo.tx_load_lo = (uint32_t) load_val; - hw->hw_timer[timer_num].load.tx_load = 1; + hw->hw_timer[timer_num].config.tx_increase = direction == GPTIMER_COUNT_UP; } /** - * @brief Get counter value from time-base counter + * @brief Enable timer, start couting * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param timer_val Pointer to accept the counter value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable the counter + * False: disable the counter */ -FORCE_INLINE_ATTR void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val) +__attribute__((always_inline)) +static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, bool en) +{ + hw->hw_timer[timer_num].config.tx_en = en; +} + +/** + * @brief Get counter value + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * + * @return counter value + */ +__attribute__((always_inline)) +static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) { hw->hw_timer[timer_num].update.tx_update = 1; - while (hw->hw_timer[timer_num].update.tx_update) {} - *timer_val = ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); + // Timer register is in a different clock domain from Timer hardware logic + // We need to wait for the update to take effect before fetching the count value + while (hw->hw_timer[timer_num].update.tx_update) { + } + return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); } /** - * @brief Set counter mode, include increment mode and decrement mode. + * @brief Set alarm value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param increase_en True to increment mode, fasle to decrement mode - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param alarm_value When counter reaches alarm value, alarm event will be triggered */ -static inline void timer_ll_set_counter_increase(timg_dev_t *hw, timer_idx_t timer_num, bool increase_en) -{ - hw->hw_timer[timer_num].config.tx_increase = increase_en; -} - -/** - * @brief Get counter mode, include increment mode and decrement mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Increment mode - * - false Decrement mode - */ -static inline bool timer_ll_get_counter_increase(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_increase; -} - -/** - * @brief Set counter status, enable or disable counter. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param counter_en True to enable counter, false to disable counter - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, bool counter_en) -{ - hw->hw_timer[timer_num].config.tx_en = counter_en; -} - -/** - * @brief Get counter status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable counter - * - false Disable conuter - */ -static inline bool timer_ll_get_counter_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_en; -} - -/** - * @brief Set auto reload mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode - * - * @return None - */ -static inline void timer_ll_set_auto_reload(timg_dev_t *hw, timer_idx_t timer_num, bool auto_reload_en) -{ - hw->hw_timer[timer_num].config.tx_autoreload = auto_reload_en; -} - -/** - * @brief Get auto reload mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable auto reload mode - * - false Disable auto reload mode - */ -FORCE_INLINE_ATTR bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_autoreload; -} - -/** - * @brief Set the counter value to trigger the alarm. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_value Counter value to trigger the alarm - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value) +__attribute__((always_inline)) +static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, uint64_t alarm_value) { hw->hw_timer[timer_num].alarmhi.tx_alarm_hi = (uint32_t) (alarm_value >> 32); hw->hw_timer[timer_num].alarmlo.tx_alarm_lo = (uint32_t) alarm_value; } /** - * @brief Get the counter value to trigger the alarm. + * @brief Get alarm value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_value Pointer to accept the counter value to trigger the alarm - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @return Counter value to trigger the alarm event */ -static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value) +static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) { - *alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); + return ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); } /** - * @brief Set the alarm status, enable or disable the alarm. + * @brief Set reload value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_en True to enable alarm, false to disable alarm - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param reload_val Reload counter value */ -FORCE_INLINE_ATTR void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en) +static inline void timer_ll_set_reload_value(timg_dev_t *hw, uint32_t timer_num, uint64_t load_val) { - hw->hw_timer[timer_num].config.tx_alarm_en = alarm_en; + hw->hw_timer[timer_num].loadhi.tx_load_hi = (uint32_t) (load_val >> 32); + hw->hw_timer[timer_num].loadlo.tx_load_lo = (uint32_t) load_val; } /** - * @brief Get the alarm status. + * @brief Get reload value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable alarm - * - false Disable alarm + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @return reload count value */ -static inline bool timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num) +static inline uint64_t timer_ll_get_reload_value(timg_dev_t *hw, uint32_t timer_num) { - return hw->hw_timer[timer_num].config.tx_alarm_en; + return ((uint64_t)hw->hw_timer[timer_num].loadhi.tx_load_hi << 32) | (hw->hw_timer[timer_num].loadlo.tx_load_lo); } /** - * @brief Enable timer interrupt. + * @brief Trigger software reload, value set by `timer_ll_set_reload_value()` will be reflected into counter immediately * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group */ -FORCE_INLINE_ATTR void timer_ll_intr_enable(timg_dev_t *hw, timer_idx_t timer_num) +static inline void timer_ll_trigger_soft_reload(timg_dev_t *hw, uint32_t timer_num) { - hw->int_ena_timers.val |= BIT(timer_num); + hw->hw_timer[timer_num].load.tx_load = 1; } /** - * @brief Disable timer interrupt. + * @brief Enable timer interrupt by mask * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None + * @param hw Timer Group register base address + * @param mask Mask of interrupt events + * @param en True: enable interrupt + * False: disable interrupt */ -FORCE_INLINE_ATTR void timer_ll_intr_disable(timg_dev_t *hw, timer_idx_t timer_num) +__attribute__((always_inline)) +static inline void timer_ll_enable_intr(timg_dev_t *hw, uint32_t mask, bool en) { - hw->int_ena_timers.val &= (~BIT(timer_num)); + if (en) { + hw->int_ena_timers.val |= mask; + } else { + hw->int_ena_timers.val &= ~mask; + } } /** - * @brief Disable timer interrupt. + * @brief Get interrupt status * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number + * @param hw Timer Group register base address * - * @return None + * @return Interrupt status */ -FORCE_INLINE_ATTR void timer_ll_clear_intr_status(timg_dev_t *hw, timer_idx_t timer_num) +__attribute__((always_inline)) +static inline uint32_t timer_ll_get_intr_status(timg_dev_t *hw) { - hw->int_clr_timers.val |= BIT(timer_num); + return hw->int_st_timers.val & 0x01; } /** - * @brief Get interrupt status. + * @brief Clear interrupt status by mask * - * @param hw Beginning address of the peripheral registers. - * @param intr_status Interrupt status - * - * @return None + * @param hw Timer Group register base address + * @param mask Interrupt events mask */ -FORCE_INLINE_ATTR void timer_ll_get_intr_status(timg_dev_t *hw, uint32_t *intr_status) +__attribute__((always_inline)) +static inline void timer_ll_clear_intr_status(timg_dev_t *hw, uint32_t mask) { - *intr_status = hw->int_st_timers.val & 0x01; + hw->int_clr_timers.val = mask; } /** - * @brief Get interrupt raw status. + * @brief Enable the register clock forever * - * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param intr_raw_status Interrupt raw status - * - * @return None + * @param hw Timer Group register base address + * @param en True: Enable the register clock forever + * False: Register clock is enabled only when register operation happens */ -FORCE_INLINE_ATTR void timer_ll_get_intr_raw_status(timer_group_t group_num, uint32_t *intr_raw_status) +static inline void timer_ll_enable_register_clock_always_on(timg_dev_t *hw, bool en) { - timg_dev_t *hw = TIMER_LL_GET_HW(group_num); - *intr_raw_status = hw->int_raw_timers.val & 0x01; + hw->regclk.clk_en = en; } /** - * @brief Set the level interrupt status, enable or disable the level interrupt. + * @brief Get interrupt status register address * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param level_int_en True to enable level interrupt, false to disable level interrupt + * @param hw Timer Group register base address * - * @return None + * @return Interrupt status register address */ -static inline void timer_ll_set_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool level_int_en) +static inline volatile void *timer_ll_get_intr_status_reg(timg_dev_t *hw) { - // Only "level" interrupts are supported on this target -} - -/** - * @brief Get the level interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable level interrupt - * - false Disable level interrupt - */ -static inline bool timer_ll_get_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - // Only "level" interrupts are supported on this target - return true; -} - -/** - * @brief Set the edge interrupt status, enable or disable the edge interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param edge_int_en True to enable edge interrupt, false to disable edge interrupt - * - * @return None - */ -static inline void timer_ll_set_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool edge_int_en) -{ - // edge interrupt is not supported on C3 -} - -/** - * @brief Get the edge interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable edge interrupt - * - false Disable edge interrupt - */ -static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - // edge interrupt is not supported on C3 - return false; -} - -/** - * @brief Get interrupt status register address. - * - * @param hw Beginning address of the peripheral registers. - * - * @return uint32_t Interrupt status register address - */ -static inline uint32_t timer_ll_get_intr_status_reg(timg_dev_t *hw) -{ - return (uint32_t) & (hw->int_st_timers.val); -} - -static inline uint32_t timer_ll_get_intr_mask_bit(timg_dev_t *hw, timer_idx_t timer_num) -{ - return (1U << timer_num); -} - -/** - * @brief Set clock source. - * - * @param hal Context of the HAL layer - * @param use_xtal_en True to use XTAL clock, flase to use APB clock - * - * @return None - */ -static inline void timer_ll_set_use_xtal(timg_dev_t *hw, timer_idx_t timer_num, bool use_xtal_en) -{ - hw->hw_timer[timer_num].config.tx_use_xtal = use_xtal_en; -} - -/** - * @brief Get clock source. - * - * @param hal Context of the HAL layer - * - * @return - * - true Use XTAL clock - * - false Use APB clock - */ -static inline bool timer_ll_get_use_xtal(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_use_xtal; + return &hw->int_st_timers.val; } #ifdef __cplusplus diff --git a/components/hal/esp32h2/include/hal/mwdt_ll.h b/components/hal/esp32h2/include/hal/mwdt_ll.h index 944108439e..328af264e1 100644 --- a/components/hal/esp32h2/include/hal/mwdt_ll.h +++ b/components/hal/esp32h2/include/hal/mwdt_ll.h @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ // The LL layer for Timer Group register operations. // Note that most of the register operations in this layer are non-atomic operations. @@ -26,6 +18,7 @@ extern "C" { #include "soc/timer_periph.h" #include "soc/timer_group_struct.h" #include "hal/wdt_types.h" +#include "hal/assert.h" #include "esp_attr.h" //Type check wdt_stage_action_t @@ -112,6 +105,7 @@ FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, u hw->wdtconfig5.wdt_stg3_hold = timeout; break; default: + HAL_ASSERT(false && "unsupported WDT stage"); break; } //Config registers are updated asynchronously @@ -140,6 +134,7 @@ FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage) hw->wdtconfig0.wdt_stg3 = WDT_STAGE_ACTION_OFF; break; default: + HAL_ASSERT(false && "unsupported WDT stage"); break; } //Config registers are updated asynchronously diff --git a/components/hal/esp32h2/include/hal/timer_ll.h b/components/hal/esp32h2/include/hal/timer_ll.h index 4032a1b1dd..8f2d633f1c 100644 --- a/components/hal/esp32h2/include/hal/timer_ll.h +++ b/components/hal/esp32h2/include/hal/timer_ll.h @@ -1,431 +1,265 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ -// The LL layer for Timer Group register operations. // Note that most of the register operations in this layer are non-atomic operations. #pragma once +#include +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/timer_types.h" +#include "soc/timer_group_struct.h" + #ifdef __cplusplus extern "C" { #endif -#include -#include "hal/misc.h" -#include "soc/timer_periph.h" -#include "soc/timer_group_struct.h" -#include "hal/timer_types.h" -#include "hal/assert.h" - -_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); -_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); - -typedef struct { - timg_dev_t *dev; - timer_idx_t idx; -} timer_ll_context_t; - -// Get timer group instance with giving group number -#define TIMER_LL_GET_HW(num) ((num == 0) ? (&TIMERG0) : (&TIMERG1)) +// Get timer group register base address with giving group number +#define TIMER_LL_GET_HW(group_id) ((group_id == 0) ? (&TIMERG0) : (&TIMERG1)) +#define TIMER_LL_EVENT_ALARM(timer_id) (1 << (timer_id)) /** - * @brief Set timer clock prescale value + * @brief Set clock source for timer * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param divider Prescale value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param clk_src Clock source */ -static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t divider) +static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num, gptimer_clock_source_t clk_src) +{ + switch (clk_src) { + case GPTIMER_CLK_SRC_APB: + hw->hw_timer[timer_num].config.tx_use_xtal = 0; + break; + case GPTIMER_CLK_SRC_XTAL: + hw->hw_timer[timer_num].config.tx_use_xtal = 1; + break; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + +/** + * @brief Enable alarm event + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable alarm + * False: disable alarm + */ +__attribute__((always_inline)) +static inline void timer_ll_enable_alarm(timg_dev_t *hw, uint32_t timer_num, bool en) +{ + hw->hw_timer[timer_num].config.tx_alarm_en = en; +} + +/** + * @brief Set clock prescale for timer + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param divider Prescale value (0 and 1 are not valid) + */ +static inline void timer_ll_set_clock_prescale(timg_dev_t *hw, uint32_t timer_num, uint32_t divider) { HAL_ASSERT(divider >= 2 && divider <= 65536); if (divider >= 65536) { divider = 0; } - int timer_en = hw->hw_timer[timer_num].config.tx_en; - hw->hw_timer[timer_num].config.tx_en = 0; - hw->hw_timer[timer_num].config.tx_divcnt_rst = 1; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hw_timer[timer_num].config, tx_divider, divider); - hw->hw_timer[timer_num].config.tx_en = timer_en; + hw->hw_timer[timer_num].config.tx_divcnt_rst = 1; } /** - * @brief Get timer clock prescale value + * @brief Enable auto-reload mode * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param divider Pointer to accept the prescale value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable auto reload mode + * False: disable auto reload mode */ -static inline void timer_ll_get_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t *divider) +static inline void timer_ll_enable_auto_reload(timg_dev_t *hw, uint32_t timer_num, bool en) { - uint32_t d = HAL_FORCE_READ_U32_REG_FIELD(hw->hw_timer[timer_num].config, tx_divider); - if (d == 0) { - d = 65536; - } else if (d == 1) { - d = 2; - } - *divider = d; + hw->hw_timer[timer_num].config.tx_autoreload = en; } /** - * @brief Load counter value into time-base counter + * @brief Set count direction * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param load_val Counter value - * - * @return None + * @param hw Timer peripheral register base address + * @param timer_num Timer number in the group + * @param direction Count direction */ -static inline void timer_ll_set_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t load_val) +static inline void timer_ll_set_count_direction(timg_dev_t *hw, uint32_t timer_num, gptimer_count_direction_t direction) { - hw->hw_timer[timer_num].loadhi.tx_load_hi = (uint32_t) (load_val >> 32); - hw->hw_timer[timer_num].loadlo.tx_load_lo = (uint32_t) load_val; - hw->hw_timer[timer_num].load.tx_load = 1; + hw->hw_timer[timer_num].config.tx_increase = direction == GPTIMER_COUNT_UP; } /** - * @brief Get counter value from time-base counter + * @brief Enable timer, start couting * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param timer_val Pointer to accept the counter value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable the counter + * False: disable the counter */ -FORCE_INLINE_ATTR void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val) +__attribute__((always_inline)) +static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, bool en) +{ + hw->hw_timer[timer_num].config.tx_en = en; +} + +/** + * @brief Get counter value + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * + * @return counter value + */ +__attribute__((always_inline)) +static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) { hw->hw_timer[timer_num].update.tx_update = 1; - while (hw->hw_timer[timer_num].update.tx_update) {} - *timer_val = ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); + // Timer register is in a different clock domain from Timer hardware logic + // We need to wait for the update to take effect before fetching the count value + while (hw->hw_timer[timer_num].update.tx_update) { + } + return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); } /** - * @brief Set counter mode, include increment mode and decrement mode. + * @brief Set alarm value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param increase_en True to increment mode, fasle to decrement mode - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param alarm_value When counter reaches alarm value, alarm event will be triggered */ -static inline void timer_ll_set_counter_increase(timg_dev_t *hw, timer_idx_t timer_num, bool increase_en) -{ - hw->hw_timer[timer_num].config.tx_increase = increase_en; -} - -/** - * @brief Get counter mode, include increment mode and decrement mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Increment mode - * - false Decrement mode - */ -static inline bool timer_ll_get_counter_increase(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_increase; -} - -/** - * @brief Set counter status, enable or disable counter. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param counter_en True to enable counter, false to disable counter - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, bool counter_en) -{ - hw->hw_timer[timer_num].config.tx_en = counter_en; -} - -/** - * @brief Get counter status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable counter - * - false Disable conuter - */ -static inline bool timer_ll_get_counter_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_en; -} - -/** - * @brief Set auto reload mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode - * - * @return None - */ -static inline void timer_ll_set_auto_reload(timg_dev_t *hw, timer_idx_t timer_num, bool auto_reload_en) -{ - hw->hw_timer[timer_num].config.tx_autoreload = auto_reload_en; -} - -/** - * @brief Get auto reload mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable auto reload mode - * - false Disable auto reload mode - */ -FORCE_INLINE_ATTR bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_autoreload; -} - -/** - * @brief Set the counter value to trigger the alarm. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_value Counter value to trigger the alarm - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value) +__attribute__((always_inline)) +static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, uint64_t alarm_value) { hw->hw_timer[timer_num].alarmhi.tx_alarm_hi = (uint32_t) (alarm_value >> 32); hw->hw_timer[timer_num].alarmlo.tx_alarm_lo = (uint32_t) alarm_value; } /** - * @brief Get the counter value to trigger the alarm. + * @brief Get alarm value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_value Pointer to accept the counter value to trigger the alarm - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @return Counter value to trigger the alarm event */ -static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value) +static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) { - *alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); + return ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); } /** - * @brief Set the alarm status, enable or disable the alarm. + * @brief Set reload value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_en True to enable alarm, false to disable alarm - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param reload_val Reload counter value */ -FORCE_INLINE_ATTR void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en) +static inline void timer_ll_set_reload_value(timg_dev_t *hw, uint32_t timer_num, uint64_t load_val) { - hw->hw_timer[timer_num].config.tx_alarm_en = alarm_en; + hw->hw_timer[timer_num].loadhi.tx_load_hi = (uint32_t) (load_val >> 32); + hw->hw_timer[timer_num].loadlo.tx_load_lo = (uint32_t) load_val; } /** - * @brief Get the alarm status. + * @brief Get reload value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable alarm - * - false Disable alarm + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @return reload count value */ -static inline bool timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num) +static inline uint64_t timer_ll_get_reload_value(timg_dev_t *hw, uint32_t timer_num) { - return hw->hw_timer[timer_num].config.tx_alarm_en; + return ((uint64_t)hw->hw_timer[timer_num].loadhi.tx_load_hi << 32) | (hw->hw_timer[timer_num].loadlo.tx_load_lo); } /** - * @brief Enable timer interrupt. + * @brief Trigger software reload, value set by `timer_ll_set_reload_value()` will be reflected into counter immediately * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group */ -FORCE_INLINE_ATTR void timer_ll_intr_enable(timg_dev_t *hw, timer_idx_t timer_num) +static inline void timer_ll_trigger_soft_reload(timg_dev_t *hw, uint32_t timer_num) { - hw->int_ena_timers.val |= BIT(timer_num); + hw->hw_timer[timer_num].load.tx_load = 1; } /** - * @brief Disable timer interrupt. + * @brief Enable timer interrupt by mask * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None + * @param hw Timer Group register base address + * @param mask Mask of interrupt events + * @param en True: enable interrupt + * False: disable interrupt */ -FORCE_INLINE_ATTR void timer_ll_intr_disable(timg_dev_t *hw, timer_idx_t timer_num) +__attribute__((always_inline)) +static inline void timer_ll_enable_intr(timg_dev_t *hw, uint32_t mask, bool en) { - hw->int_ena_timers.val &= (~BIT(timer_num)); + if (en) { + hw->int_ena_timers.val |= mask; + } else { + hw->int_ena_timers.val &= ~mask; + } } /** - * @brief Disable timer interrupt. + * @brief Get interrupt status * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number + * @param hw Timer Group register base address * - * @return None + * @return Interrupt status */ -FORCE_INLINE_ATTR void timer_ll_clear_intr_status(timg_dev_t *hw, timer_idx_t timer_num) +__attribute__((always_inline)) +static inline uint32_t timer_ll_get_intr_status(timg_dev_t *hw) { - hw->int_clr_timers.val |= BIT(timer_num); + return hw->int_st_timers.val & 0x01; } /** - * @brief Get interrupt status. + * @brief Clear interrupt status by mask * - * @param hw Beginning address of the peripheral registers. - * @param intr_status Interrupt status - * - * @return None + * @param hw Timer Group register base address + * @param mask Interrupt events mask */ -FORCE_INLINE_ATTR void timer_ll_get_intr_status(timg_dev_t *hw, uint32_t *intr_status) +__attribute__((always_inline)) +static inline void timer_ll_clear_intr_status(timg_dev_t *hw, uint32_t mask) { - *intr_status = hw->int_st_timers.val & 0x01; + hw->int_clr_timers.val = mask; } /** - * @brief Get interrupt raw status. + * @brief Enable the register clock forever * - * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param intr_raw_status Interrupt raw status - * - * @return None + * @param hw Timer Group register base address + * @param en True: Enable the register clock forever + * False: Register clock is enabled only when register operation happens */ -FORCE_INLINE_ATTR void timer_ll_get_intr_raw_status(timer_group_t group_num, uint32_t *intr_raw_status) +static inline void timer_ll_enable_register_clock_always_on(timg_dev_t *hw, bool en) { - timg_dev_t *hw = TIMER_LL_GET_HW(group_num); - *intr_raw_status = hw->int_raw_timers.val & 0x01; + hw->regclk.clk_en = en; } /** - * @brief Set the level interrupt status, enable or disable the level interrupt. + * @brief Get interrupt status register address * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param level_int_en True to enable level interrupt, false to disable level interrupt + * @param hw Timer Group register base address * - * @return None + * @return Interrupt status register address */ -static inline void timer_ll_set_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool level_int_en) +static inline volatile void *timer_ll_get_intr_status_reg(timg_dev_t *hw) { - // Only "level" interrupts are supported on this target -} - -/** - * @brief Get the level interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable level interrupt - * - false Disable level interrupt - */ -static inline bool timer_ll_get_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - // Only "level" interrupts are supported on this target - return true; -} - -/** - * @brief Set the edge interrupt status, enable or disable the edge interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param edge_int_en True to enable edge interrupt, false to disable edge interrupt - * - * @return None - */ -static inline void timer_ll_set_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool edge_int_en) -{ - // edge interrupt is not supported on H2 -} - -/** - * @brief Get the edge interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable edge interrupt - * - false Disable edge interrupt - */ -static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - // edge interrupt is not supported on H2 - return false; -} - -/** - * @brief Get interrupt status register address. - * - * @param hw Beginning address of the peripheral registers. - * - * @return uint32_t Interrupt status register address - */ -static inline uint32_t timer_ll_get_intr_status_reg(timg_dev_t *hw) -{ - return (uint32_t) & (hw->int_st_timers.val); -} - -static inline uint32_t timer_ll_get_intr_mask_bit(timg_dev_t *hw, timer_idx_t timer_num) -{ - return (1U << timer_num); -} - -/** - * @brief Set clock source. - * - * @param hal Context of the HAL layer - * @param use_xtal_en True to use XTAL clock, flase to use APB clock - * - * @return None - */ -static inline void timer_ll_set_use_xtal(timg_dev_t *hw, timer_idx_t timer_num, bool use_xtal_en) -{ - hw->hw_timer[timer_num].config.tx_use_xtal = use_xtal_en; -} - -/** - * @brief Get clock source. - * - * @param hal Context of the HAL layer - * - * @return - * - true Use XTAL clock - * - false Use APB clock - */ -static inline bool timer_ll_get_use_xtal(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_use_xtal; + return &hw->int_st_timers.val; } #ifdef __cplusplus diff --git a/components/hal/esp32s2/include/hal/mwdt_ll.h b/components/hal/esp32s2/include/hal/mwdt_ll.h index 6d50f740b6..f552e86399 100644 --- a/components/hal/esp32s2/include/hal/mwdt_ll.h +++ b/components/hal/esp32s2/include/hal/mwdt_ll.h @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ // The LL layer for Timer Group register operations. // Note that most of the register operations in this layer are non-atomic operations. @@ -26,6 +18,7 @@ extern "C" { #include "soc/timer_periph.h" #include "soc/timer_group_struct.h" #include "hal/wdt_types.h" +#include "hal/assert.h" #include "esp_attr.h" //Type check wdt_stage_action_t @@ -95,24 +88,25 @@ FORCE_INLINE_ATTR bool mwdt_ll_check_if_enabled(timg_dev_t *hw) FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, uint32_t timeout, wdt_stage_action_t behavior) { switch (stage) { - case WDT_STAGE0: - hw->wdtconfig0.wdt_stg0 = behavior; - hw->wdtconfig2.wdt_stg0_hold = timeout; - break; - case WDT_STAGE1: - hw->wdtconfig0.wdt_stg1 = behavior; - hw->wdtconfig3.wdt_stg1_hold = timeout; - break; - case WDT_STAGE2: - hw->wdtconfig0.wdt_stg2 = behavior; - hw->wdtconfig4.wdt_stg2_hold = timeout; - break; - case WDT_STAGE3: - hw->wdtconfig0.wdt_stg3 = behavior; - hw->wdtconfig5.wdt_stg3_hold = timeout; - break; - default: - break; + case WDT_STAGE0: + hw->wdtconfig0.wdt_stg0 = behavior; + hw->wdtconfig2.wdt_stg0_hold = timeout; + break; + case WDT_STAGE1: + hw->wdtconfig0.wdt_stg1 = behavior; + hw->wdtconfig3.wdt_stg1_hold = timeout; + break; + case WDT_STAGE2: + hw->wdtconfig0.wdt_stg2 = behavior; + hw->wdtconfig4.wdt_stg2_hold = timeout; + break; + case WDT_STAGE3: + hw->wdtconfig0.wdt_stg3 = behavior; + hw->wdtconfig5.wdt_stg3_hold = timeout; + break; + default: + HAL_ASSERT(false && "unsupported WDT stage"); + break; } } @@ -125,20 +119,21 @@ FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, u FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage) { switch (stage) { - case WDT_STAGE0: - hw->wdtconfig0.wdt_stg0 = WDT_STAGE_ACTION_OFF; - break; - case WDT_STAGE1: - hw->wdtconfig0.wdt_stg1 = WDT_STAGE_ACTION_OFF; - break; - case WDT_STAGE2: - hw->wdtconfig0.wdt_stg2 = WDT_STAGE_ACTION_OFF; - break; - case WDT_STAGE3: - hw->wdtconfig0.wdt_stg3 = WDT_STAGE_ACTION_OFF; - break; - default: - break; + case WDT_STAGE0: + hw->wdtconfig0.wdt_stg0 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE1: + hw->wdtconfig0.wdt_stg1 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE2: + hw->wdtconfig0.wdt_stg2 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE3: + hw->wdtconfig0.wdt_stg3 = WDT_STAGE_ACTION_OFF; + break; + default: + HAL_ASSERT(false && "unsupported WDT stage"); + break; } } @@ -196,7 +191,7 @@ FORCE_INLINE_ATTR void mwdt_ll_set_sys_reset_length(timg_dev_t *hw, wdt_reset_si * WDT's enable bit is set to 0. Flashboot mode for TG0 is automatically enabled * on flashboot, and should be disabled by software when flashbooting completes. */ -FORCE_INLINE_ATTR void mwdt_ll_set_flashboot_en(timg_dev_t* hw, bool enable) +FORCE_INLINE_ATTR void mwdt_ll_set_flashboot_en(timg_dev_t *hw, bool enable) { hw->wdtconfig0.wdt_flashboot_mod_en = (enable) ? 1 : 0; } @@ -253,7 +248,7 @@ FORCE_INLINE_ATTR void mwdt_ll_write_protect_disable(timg_dev_t *hw) * * @param hw Start address of the peripheral registers. */ -FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t* hw) +FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t *hw) { hw->int_clr_timers.wdt_int_clr = 1; } @@ -264,7 +259,7 @@ FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t* hw) * @param hw Beginning address of the peripheral registers. * @param enable Whether to enable the MWDT interrupt */ -FORCE_INLINE_ATTR void mwdt_ll_set_intr_enable(timg_dev_t* hw, bool enable) +FORCE_INLINE_ATTR void mwdt_ll_set_intr_enable(timg_dev_t *hw, bool enable) { hw->int_ena_timers.wdt_int_ena = (enable) ? 1 : 0; } diff --git a/components/hal/esp32s2/include/hal/timer_ll.h b/components/hal/esp32s2/include/hal/timer_ll.h index 59921e2364..798ff147f4 100644 --- a/components/hal/esp32s2/include/hal/timer_ll.h +++ b/components/hal/esp32s2/include/hal/timer_ll.h @@ -1,426 +1,266 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ -// The LL layer for Timer Group register operations. // Note that most of the register operations in this layer are non-atomic operations. #pragma once +#include +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/timer_types.h" +#include "soc/timer_group_struct.h" + #ifdef __cplusplus extern "C" { #endif -#include -#include "hal/misc.h" -#include "soc/timer_periph.h" -#include "soc/timer_group_struct.h" -#include "hal/timer_types.h" -#include "hal/assert.h" - -_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); -_Static_assert(TIMER_INTR_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); -_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); - -// Get timer group instance with giving group number -#define TIMER_LL_GET_HW(num) ((num == 0) ? (&TIMERG0) : (&TIMERG1)) +// Get timer group register base address with giving group number +#define TIMER_LL_GET_HW(group_id) ((group_id == 0) ? (&TIMERG0) : (&TIMERG1)) +#define TIMER_LL_EVENT_ALARM(timer_id) (1 << (timer_id)) /** - * @brief Set timer clock prescale value + * @brief Set clock source for timer * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param divider Prescale value (0 is not valid) - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param clk_src Clock source */ -static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t divider) +static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num, gptimer_clock_source_t clk_src) +{ + switch (clk_src) { + case GPTIMER_CLK_SRC_APB: + hw->hw_timer[timer_num].config.tx_use_xtal = 0; + break; + case GPTIMER_CLK_SRC_XTAL: + hw->hw_timer[timer_num].config.tx_use_xtal = 1; + break; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + +/** + * @brief Enable alarm event + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable alarm + * False: disable alarm + */ +__attribute__((always_inline)) +static inline void timer_ll_enable_alarm(timg_dev_t *hw, uint32_t timer_num, bool en) +{ + hw->hw_timer[timer_num].config.tx_alarm_en = en; + // use level type interrupt + hw->hw_timer[timer_num].config.tx_level_int_en = en; +} + +/** + * @brief Set clock prescale for timer + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param divider Prescale value (0 and 1 are not valid) + */ +static inline void timer_ll_set_clock_prescale(timg_dev_t *hw, uint32_t timer_num, uint32_t divider) { HAL_ASSERT(divider >= 2 && divider <= 65536); if (divider >= 65536) { divider = 0; } - int timer_en = hw->hw_timer[timer_num].config.tx_en; - hw->hw_timer[timer_num].config.tx_en = 0; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hw_timer[timer_num].config, tx_divider, divider); - hw->hw_timer[timer_num].config.tx_en = timer_en; } /** - * @brief Get timer clock prescale value + * @brief Enable auto-reload mode * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param divider Pointer to accept the prescale value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable auto reload mode + * False: disable auto reload mode */ -static inline void timer_ll_get_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t *divider) +static inline void timer_ll_enable_auto_reload(timg_dev_t *hw, uint32_t timer_num, bool en) { - uint32_t d = HAL_FORCE_READ_U32_REG_FIELD(hw->hw_timer[timer_num].config, tx_divider); - if (d == 0) { - d = 65536; - } else if (d == 1) { - d = 2; - } - *divider = d; + hw->hw_timer[timer_num].config.tx_autoreload = en; } /** - * @brief Load counter value into time-base counter + * @brief Set count direction * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param load_val Counter value - * - * @return None + * @param hw Timer peripheral register base address + * @param timer_num Timer number in the group + * @param direction Count direction */ -static inline void timer_ll_set_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t load_val) +static inline void timer_ll_set_count_direction(timg_dev_t *hw, uint32_t timer_num, gptimer_count_direction_t direction) { - hw->hw_timer[timer_num].loadhi.tx_load_hi = (uint32_t) (load_val >> 32); - hw->hw_timer[timer_num].loadlo.tx_load_lo = (uint32_t) load_val; - hw->hw_timer[timer_num].load.tx_load = 1; + hw->hw_timer[timer_num].config.tx_increase = direction == GPTIMER_COUNT_UP; } /** - * @brief Get counter value from time-base counter + * @brief Enable timer, start couting * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param timer_val Pointer to accept the counter value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable the counter + * False: disable the counter */ -FORCE_INLINE_ATTR void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val) +__attribute__((always_inline)) +static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, bool en) +{ + hw->hw_timer[timer_num].config.tx_en = en; +} + +/** + * @brief Get counter value + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * + * @return counter value + */ +__attribute__((always_inline)) +static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) { hw->hw_timer[timer_num].update.tx_update = 1; - while (hw->hw_timer[timer_num].update.tx_update) {} - *timer_val = ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); + // Timer register is in a different clock domain from Timer hardware logic + // We need to wait for the update to take effect before fetching the count value + while (hw->hw_timer[timer_num].update.tx_update) { + } + return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); } /** - * @brief Set counter mode, include increment mode and decrement mode. + * @brief Set alarm value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param increase_en True to increment mode, fasle to decrement mode - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param alarm_value When counter reaches alarm value, alarm event will be triggered */ -static inline void timer_ll_set_counter_increase(timg_dev_t *hw, timer_idx_t timer_num, bool increase_en) -{ - hw->hw_timer[timer_num].config.tx_increase = increase_en; -} - -/** - * @brief Get counter mode, include increment mode and decrement mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Increment mode - * - false Decrement mode - */ -static inline bool timer_ll_get_counter_increase(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_increase; -} - -/** - * @brief Set counter status, enable or disable counter. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param counter_en True to enable counter, false to disable counter - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, bool counter_en) -{ - hw->hw_timer[timer_num].config.tx_en = counter_en; -} - -/** - * @brief Get counter status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable counter - * - false Disable conuter - */ -static inline bool timer_ll_get_counter_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_en; -} - -/** - * @brief Set auto reload mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode - * - * @return None - */ -static inline void timer_ll_set_auto_reload(timg_dev_t *hw, timer_idx_t timer_num, bool auto_reload_en) -{ - hw->hw_timer[timer_num].config.tx_autoreload = auto_reload_en; -} - -/** - * @brief Get auto reload mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable auto reload mode - * - false Disable auto reload mode - */ -FORCE_INLINE_ATTR bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_autoreload; -} - -/** - * @brief Set the counter value to trigger the alarm. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_value Counter value to trigger the alarm - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value) +__attribute__((always_inline)) +static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, uint64_t alarm_value) { hw->hw_timer[timer_num].alarmhi.tx_alarm_hi = (uint32_t) (alarm_value >> 32); hw->hw_timer[timer_num].alarmlo.tx_alarm_lo = (uint32_t) alarm_value; } /** - * @brief Get the counter value to trigger the alarm. + * @brief Get alarm value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_value Pointer to accept the counter value to trigger the alarm - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @return Counter value to trigger the alarm event */ -static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value) +static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) { - *alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); + return ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); } /** - * @brief Set the alarm status, enable or disable the alarm. + * @brief Set reload value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_en True to enable alarm, false to disable alarm - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param reload_val Reload counter value */ -FORCE_INLINE_ATTR void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en) +static inline void timer_ll_set_reload_value(timg_dev_t *hw, uint32_t timer_num, uint64_t load_val) { - hw->hw_timer[timer_num].config.tx_alarm_en = alarm_en; + hw->hw_timer[timer_num].loadhi.tx_load_hi = (uint32_t) (load_val >> 32); + hw->hw_timer[timer_num].loadlo.tx_load_lo = (uint32_t) load_val; } /** - * @brief Get the alarm status. + * @brief Get reload value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable alarm - * - false Disable alarm + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @return reload count value */ -static inline bool timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num) +static inline uint64_t timer_ll_get_reload_value(timg_dev_t *hw, uint32_t timer_num) { - return hw->hw_timer[timer_num].config.tx_alarm_en; + return ((uint64_t)hw->hw_timer[timer_num].loadhi.tx_load_hi << 32) | (hw->hw_timer[timer_num].loadlo.tx_load_lo); } /** - * @brief Enable timer interrupt. + * @brief Trigger software reload, value set by `timer_ll_set_reload_value()` will be reflected into counter immediately * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group */ -FORCE_INLINE_ATTR void timer_ll_intr_enable(timg_dev_t *hw, timer_idx_t timer_num) +static inline void timer_ll_trigger_soft_reload(timg_dev_t *hw, uint32_t timer_num) { - hw->int_ena_timers.val |= BIT(timer_num); - hw->hw_timer[timer_num].config.tx_level_int_en = 1; + hw->hw_timer[timer_num].load.tx_load = 1; } /** - * @brief Disable timer interrupt. + * @brief Enable timer interrupt by mask * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None + * @param hw Timer Group register base address + * @param mask Mask of interrupt events + * @param en True: enable interrupt + * False: disable interrupt */ -FORCE_INLINE_ATTR void timer_ll_intr_disable(timg_dev_t *hw, timer_idx_t timer_num) +__attribute__((always_inline)) +static inline void timer_ll_enable_intr(timg_dev_t *hw, uint32_t mask, bool en) { - hw->int_ena_timers.val &= (~BIT(timer_num)); - hw->hw_timer[timer_num].config.tx_level_int_en = 0; + if (en) { + hw->int_ena_timers.val |= mask; + } else { + hw->int_ena_timers.val &= ~mask; + } } /** - * @brief Disable timer interrupt. + * @brief Get interrupt status * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number + * @param hw Timer Group register base address * - * @return None + * @return Interrupt status */ -FORCE_INLINE_ATTR void timer_ll_clear_intr_status(timg_dev_t *hw, timer_idx_t timer_num) +__attribute__((always_inline)) +static inline uint32_t timer_ll_get_intr_status(timg_dev_t *hw) { - hw->int_clr_timers.val |= BIT(timer_num); + return hw->int_st_timers.val & 0x03; } /** - * @brief Get interrupt status. + * @brief Clear interrupt status by mask * - * @param hw Beginning address of the peripheral registers. - * @param intr_status Interrupt status - * - * @return None + * @param hw Timer Group register base address + * @param mask Interrupt events mask */ -FORCE_INLINE_ATTR void timer_ll_get_intr_status(timg_dev_t *hw, uint32_t *intr_status) +__attribute__((always_inline)) +static inline void timer_ll_clear_intr_status(timg_dev_t *hw, uint32_t mask) { - *intr_status = hw->int_st_timers.val & 0x03; + hw->int_clr_timers.val = mask; } /** - * @brief Get interrupt raw status. + * @brief Enable the register clock forever * - * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param intr_raw_status Interrupt raw status - * - * @return None + * @param hw Timer Group register base address + * @param en True: Enable the register clock forever + * False: Register clock is enabled only when register operation happens */ -FORCE_INLINE_ATTR void timer_ll_get_intr_raw_status(timer_group_t group_num, uint32_t *intr_raw_status) +static inline void timer_ll_enable_register_clock_always_on(timg_dev_t *hw, bool en) { - timg_dev_t *hw = TIMER_LL_GET_HW(group_num); - *intr_raw_status = hw->int_raw_timers.val & 0x03; + hw->regclk.clk_en = en; } /** - * @brief Set the level interrupt status, enable or disable the level interrupt. + * @brief Get interrupt status register address * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param level_int_en True to enable level interrupt, false to disable level interrupt + * @param hw Timer Group register base address * - * @return None + * @return Interrupt status register address */ -static inline void timer_ll_set_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool level_int_en) +static inline volatile void *timer_ll_get_intr_status_reg(timg_dev_t *hw) { - hw->hw_timer[timer_num].config.tx_level_int_en = level_int_en; -} - -/** - * @brief Get the level interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable level interrupt - * - false Disable level interrupt - */ -static inline bool timer_ll_get_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_level_int_en; -} - -/** - * @brief Set the edge interrupt status, enable or disable the edge interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param edge_int_en True to enable edge interrupt, false to disable edge interrupt - * - * @return None - */ -static inline void timer_ll_set_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool edge_int_en) -{ - hw->hw_timer[timer_num].config.tx_edge_int_en = edge_int_en; -} - -/** - * @brief Get the edge interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable edge interrupt - * - false Disable edge interrupt - */ -static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_edge_int_en; -} - -/** - * @brief Get interrupt status register address. - * - * @param hw Beginning address of the peripheral registers. - * - * @return uint32_t Interrupt status register address - */ -static inline uint32_t timer_ll_get_intr_status_reg(timg_dev_t *hw) -{ - return (uint32_t) & (hw->int_st_timers.val); -} - -static inline uint32_t timer_ll_get_intr_mask_bit(timg_dev_t *hw, timer_idx_t timer_num) -{ - return (1U << timer_num); -} - -/** - * @brief Set clock source. - * - * @param hal Context of the HAL layer - * @param use_xtal_en True to use XTAL clock, flase to use APB clock - * - * @return None - */ -static inline void timer_ll_set_use_xtal(timg_dev_t *hw, timer_idx_t timer_num, bool use_xtal_en) -{ - hw->hw_timer[timer_num].config.tx_use_xtal = use_xtal_en; -} - -/** - * @brief Get clock source. - * - * @param hal Context of the HAL layer - * - * @return - * - true Use XTAL clock - * - false Use APB clock - */ -static inline bool timer_ll_get_use_xtal(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tx_use_xtal; + return &hw->int_st_timers.val; } #ifdef __cplusplus diff --git a/components/hal/esp32s3/include/hal/mwdt_ll.h b/components/hal/esp32s3/include/hal/mwdt_ll.h index c15d7b8cd5..ac25adfc50 100644 --- a/components/hal/esp32s3/include/hal/mwdt_ll.h +++ b/components/hal/esp32s3/include/hal/mwdt_ll.h @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ // The LL layer for Timer Group register operations. // Note that most of the register operations in this layer are non-atomic operations. @@ -27,6 +19,7 @@ extern "C" { #include "soc/timer_periph.h" #include "soc/timer_group_struct.h" #include "hal/wdt_types.h" +#include "hal/assert.h" #include "esp_attr.h" /* The value that needs to be written to MWDT_LL_WKEY to write-enable the wdt registers */ @@ -125,6 +118,7 @@ FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, u hw->wdtconfig5.wdt_stg3_hold = timeout; break; default: + HAL_ASSERT(false && "unsupported WDT stage"); break; } } @@ -151,6 +145,7 @@ FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage) hw->wdtconfig0.wdt_stg3 = WDT_STAGE_ACTION_OFF; break; default: + HAL_ASSERT(false && "unsupported WDT stage"); break; } } diff --git a/components/hal/esp32s3/include/hal/timer_ll.h b/components/hal/esp32s3/include/hal/timer_ll.h index 36288f7887..2f5481c0fa 100644 --- a/components/hal/esp32s3/include/hal/timer_ll.h +++ b/components/hal/esp32s3/include/hal/timer_ll.h @@ -1,428 +1,265 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ -// The LL layer for Timer Group register operations. // Note that most of the register operations in this layer are non-atomic operations. #pragma once +#include +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/timer_types.h" +#include "soc/timer_group_struct.h" + #ifdef __cplusplus extern "C" { #endif -#include -#include "hal/misc.h" -#include "soc/timer_periph.h" -#include "soc/timer_group_struct.h" -#include "hal/timer_types.h" -#include "hal/assert.h" - -_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); -_Static_assert(TIMER_INTR_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); -_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); - -typedef struct { - timg_dev_t *dev; - timer_idx_t idx; -} timer_ll_context_t; - -// Get timer group instance with giving group number -#define TIMER_LL_GET_HW(num) ((num == 0) ? (&TIMERG0) : (&TIMERG1)) +// Get timer group register base address with giving group number +#define TIMER_LL_GET_HW(group_id) ((group_id == 0) ? (&TIMERG0) : (&TIMERG1)) +#define TIMER_LL_EVENT_ALARM(timer_id) (1 << (timer_id)) /** - * @brief Set timer clock prescale value + * @brief Set clock source for timer * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param divider Prescale value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param clk_src Clock source */ -static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t divider) +static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num, gptimer_clock_source_t clk_src) +{ + switch (clk_src) { + case GPTIMER_CLK_SRC_APB: + hw->hw_timer[timer_num].config.tn_use_xtal = 0; + break; + case GPTIMER_CLK_SRC_XTAL: + hw->hw_timer[timer_num].config.tn_use_xtal = 1; + break; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + +/** + * @brief Enable alarm event + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable alarm + * False: disable alarm + */ +__attribute__((always_inline)) +static inline void timer_ll_enable_alarm(timg_dev_t *hw, uint32_t timer_num, bool en) +{ + hw->hw_timer[timer_num].config.tn_alarm_en = en; +} + +/** + * @brief Set clock prescale for timer + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param divider Prescale value (0 and 1 are not valid) + */ +static inline void timer_ll_set_clock_prescale(timg_dev_t *hw, uint32_t timer_num, uint32_t divider) { HAL_ASSERT(divider >= 2 && divider <= 65536); if (divider >= 65536) { divider = 0; } - int timer_en = hw->hw_timer[timer_num].config.tn_en; - hw->hw_timer[timer_num].config.tn_en = 0; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hw_timer[timer_num].config, tn_divider, divider); - hw->hw_timer[timer_num].config.tn_en = timer_en; + hw->hw_timer[timer_num].config.tn_divcnt_rst = 1; } /** - * @brief Get timer clock prescale value + * @brief Enable auto-reload mode * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param divider Pointer to accept the prescale value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable auto reload mode + * False: disable auto reload mode */ -static inline void timer_ll_get_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t *divider) +static inline void timer_ll_enable_auto_reload(timg_dev_t *hw, uint32_t timer_num, bool en) { - uint32_t d = HAL_FORCE_READ_U32_REG_FIELD(hw->hw_timer[timer_num].config, tn_divider); - if (d == 0) { - d = 65536; - } else if (d == 1) { - d = 2; + hw->hw_timer[timer_num].config.tn_autoreload = en; +} + +/** + * @brief Set count direction + * + * @param hw Timer peripheral register base address + * @param timer_num Timer number in the group + * @param direction Count direction + */ +static inline void timer_ll_set_count_direction(timg_dev_t *hw, uint32_t timer_num, gptimer_count_direction_t direction) +{ + hw->hw_timer[timer_num].config.tn_increase = (direction == GPTIMER_COUNT_UP); +} + +/** + * @brief Enable timer, start couting + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param en True: enable the counter + * False: disable the counter + */ +__attribute__((always_inline)) +static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, bool en) +{ + hw->hw_timer[timer_num].config.tn_en = en; +} + +/** + * @brief Get counter value + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * + * @return counter value + */ +__attribute__((always_inline)) +static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) +{ + hw->hw_timer[timer_num].update.tn_update = 1; + // Timer register is in a different clock domain from Timer hardware logic + // We need to wait for the update to take effect before fetching the count value + while (hw->hw_timer[timer_num].update.tn_update) { } - *divider = d; + return ((uint64_t)hw->hw_timer[timer_num].hi.tn_hi << 32) | (hw->hw_timer[timer_num].lo.tn_lo); } /** - * @brief Load counter value into time-base counter + * @brief Set alarm value * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param load_val Counter value - * - * @return None + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param alarm_value When counter reaches alarm value, alarm event will be triggered */ -static inline void timer_ll_set_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t load_val) +__attribute__((always_inline)) +static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, uint64_t alarm_value) +{ + hw->hw_timer[timer_num].alarmhi.tn_alarm_hi = (uint32_t)(alarm_value >> 32); + hw->hw_timer[timer_num].alarmlo.tn_alarm_lo = (uint32_t)alarm_value; +} + +/** + * @brief Get alarm value + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @return Counter value to trigger the alarm event + */ +static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) +{ + return ((uint64_t)hw->hw_timer[timer_num].alarmhi.tn_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tn_alarm_lo); +} + +/** + * @brief Set reload value + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @param reload_val Reload counter value + */ +static inline void timer_ll_set_reload_value(timg_dev_t *hw, uint32_t timer_num, uint64_t reload_val) +{ + hw->hw_timer[timer_num].loadhi.tn_load_hi = (uint32_t)(reload_val >> 32); + hw->hw_timer[timer_num].loadlo.tn_load_lo = (uint32_t)reload_val; +} + +/** + * @brief Get reload value + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + * @return reload count value + */ +static inline uint64_t timer_ll_get_reload_value(timg_dev_t *hw, uint32_t timer_num) +{ + return ((uint64_t)hw->hw_timer[timer_num].loadhi.tn_load_hi << 32) | (hw->hw_timer[timer_num].loadlo.tn_load_lo); +} + +/** + * @brief Trigger software reload, value set by `timer_ll_set_reload_value()` will be reflected into counter immediately + * + * @param hw Timer Group register base address + * @param timer_num Timer number in the group + */ +static inline void timer_ll_trigger_soft_reload(timg_dev_t *hw, uint32_t timer_num) { - hw->hw_timer[timer_num].loadhi.tn_load_hi = (uint32_t) (load_val >> 32); - hw->hw_timer[timer_num].loadlo.tn_load_lo = (uint32_t) load_val; hw->hw_timer[timer_num].load.tn_load = 1; } /** - * @brief Get counter value from time-base counter + * @brief Enable timer interrupt by mask * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param timer_val Pointer to accept the counter value - * - * @return None + * @param hw Timer Group register base address + * @param mask Mask of interrupt events + * @param en True: enable interrupt + * False: disable interrupt */ -FORCE_INLINE_ATTR void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val) +__attribute__((always_inline)) +static inline void timer_ll_enable_intr(timg_dev_t *hw, uint32_t mask, bool en) { - hw->hw_timer[timer_num].update.tn_update = 1; - while (hw->hw_timer[timer_num].update.tn_update) {} - *timer_val = ((uint64_t) hw->hw_timer[timer_num].hi.tn_hi << 32) | (hw->hw_timer[timer_num].lo.tn_lo); + if (en) { + hw->int_ena_timers.val |= mask; + } else { + hw->int_ena_timers.val &= ~mask; + } } /** - * @brief Set counter mode, include increment mode and decrement mode. + * @brief Get interrupt status * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param increase_en True to increment mode, fasle to decrement mode + * @param hw Timer Group register base address * - * @return None + * @return Interrupt status */ -static inline void timer_ll_set_counter_increase(timg_dev_t *hw, timer_idx_t timer_num, bool increase_en) +__attribute__((always_inline)) +static inline uint32_t timer_ll_get_intr_status(timg_dev_t *hw) { - hw->hw_timer[timer_num].config.tn_increase = increase_en; + return hw->int_st_timers.val & 0x03; } /** - * @brief Get counter mode, include increment mode and decrement mode. + * @brief Clear interrupt status by mask * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Increment mode - * - false Decrement mode + * @param hw Timer Group register base address + * @param mask Interrupt events mask */ -static inline bool timer_ll_get_counter_increase(timg_dev_t *hw, timer_idx_t timer_num) +__attribute__((always_inline)) +static inline void timer_ll_clear_intr_status(timg_dev_t *hw, uint32_t mask) { - return hw->hw_timer[timer_num].config.tn_increase; + hw->int_clr_timers.val = mask; } /** - * @brief Set counter status, enable or disable counter. + * @brief Enable the register clock forever * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param counter_en True to enable counter, false to disable counter - * - * @return None + * @param hw Timer Group register base address + * @param en True: Enable the register clock forever + * False: Register clock is enabled only when register operation happens */ -FORCE_INLINE_ATTR void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, bool counter_en) +static inline void timer_ll_enable_register_clock_always_on(timg_dev_t *hw, bool en) { - hw->hw_timer[timer_num].config.tn_en = counter_en; + hw->regclk.clk_en = en; } /** - * @brief Get counter status. + * @brief Get interrupt status register address * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number + * @param hw Timer Group register base address * - * @return - * - true Enable counter - * - false Disable conuter + * @return Interrupt status register address */ -static inline bool timer_ll_get_counter_enable(timg_dev_t *hw, timer_idx_t timer_num) +static inline volatile void *timer_ll_get_intr_status_reg(timg_dev_t *hw) { - return hw->hw_timer[timer_num].config.tn_en; -} - -/** - * @brief Set auto reload mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode - * - * @return None - */ -static inline void timer_ll_set_auto_reload(timg_dev_t *hw, timer_idx_t timer_num, bool auto_reload_en) -{ - hw->hw_timer[timer_num].config.tn_autoreload = auto_reload_en; -} - -/** - * @brief Get auto reload mode. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable auto reload mode - * - false Disable auto reload mode - */ -FORCE_INLINE_ATTR bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tn_autoreload; -} - -/** - * @brief Set the counter value to trigger the alarm. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_value Counter value to trigger the alarm - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value) -{ - hw->hw_timer[timer_num].alarmhi.tn_alarm_hi = (uint32_t) (alarm_value >> 32); - hw->hw_timer[timer_num].alarmlo.tn_alarm_lo = (uint32_t) alarm_value; -} - -/** - * @brief Get the counter value to trigger the alarm. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_value Pointer to accept the counter value to trigger the alarm - * - * @return None - */ -static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value) -{ - *alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarmhi.tn_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tn_alarm_lo); -} - -/** - * @brief Set the alarm status, enable or disable the alarm. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param alarm_en True to enable alarm, false to disable alarm - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en) -{ - hw->hw_timer[timer_num].config.tn_alarm_en = alarm_en; -} - -/** - * @brief Get the alarm status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable alarm - * - false Disable alarm - */ -static inline bool timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tn_alarm_en; -} - -/** - * @brief Enable timer interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_intr_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - hw->int_ena_timers.val |= BIT(timer_num); -} - -/** - * @brief Disable timer interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_intr_disable(timg_dev_t *hw, timer_idx_t timer_num) -{ - hw->int_ena_timers.val &= (~BIT(timer_num)); -} - -/** - * @brief Disable timer interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_clear_intr_status(timg_dev_t *hw, timer_idx_t timer_num) -{ - hw->int_clr_timers.val |= BIT(timer_num); -} - -/** - * @brief Get interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param intr_status Interrupt status - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_get_intr_status(timg_dev_t *hw, uint32_t *intr_status) -{ - *intr_status = hw->int_st_timers.val & 0x03; -} - -/** - * @brief Get interrupt raw status. - * - * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param intr_raw_status Interrupt raw status - * - * @return None - */ -FORCE_INLINE_ATTR void timer_ll_get_intr_raw_status(timer_group_t group_num, uint32_t *intr_raw_status) -{ - timg_dev_t *hw = TIMER_LL_GET_HW(group_num); - *intr_raw_status = hw->int_raw_timers.val & 0x03; -} - -/** - * @brief Set the level interrupt status, enable or disable the level interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param level_int_en True to enable level interrupt, false to disable level interrupt - * - * @return None - */ -static inline void timer_ll_set_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool level_int_en) -{ - // Only "level" interrupts are supported on this target -} - -/** - * @brief Get the level interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable level interrupt - * - false Disable level interrupt - */ -static inline bool timer_ll_get_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return true; -} - -/** - * @brief Set the edge interrupt status, enable or disable the edge interrupt. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * @param edge_int_en True to enable edge interrupt, false to disable edge interrupt - * - * @return None - */ -static inline void timer_ll_set_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool edge_int_en) -{ -} - -/** - * @brief Get the edge interrupt status. - * - * @param hw Beginning address of the peripheral registers. - * @param timer_num The timer number - * - * @return - * - true Enable edge interrupt - * - false Disable edge interrupt - */ -static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num) -{ - return false; -} - -/** - * @brief Get interrupt status register address. - * - * @param hw Beginning address of the peripheral registers. - * - * @return uint32_t Interrupt status register address - */ -static inline uint32_t timer_ll_get_intr_status_reg(timg_dev_t *hw) -{ - return (uint32_t) & (hw->int_st_timers.val); -} - -static inline uint32_t timer_ll_get_intr_mask_bit(timg_dev_t *hw, timer_idx_t timer_num) -{ - return (1U << timer_num); -} - -/** - * @brief Set clock source. - * - * @param hal Context of the HAL layer - * @param use_xtal_en True to use XTAL clock, flase to use APB clock - * - * @return None - */ -static inline void timer_ll_set_use_xtal(timg_dev_t *hw, timer_idx_t timer_num, bool use_xtal_en) -{ - hw->hw_timer[timer_num].config.tn_use_xtal = use_xtal_en; -} - -/** - * @brief Get clock source. - * - * @param hal Context of the HAL layer - * - * @return - * - true Use XTAL clock - * - false Use APB clock - */ -static inline bool timer_ll_get_use_xtal(timg_dev_t *hw, timer_idx_t timer_num) -{ - return hw->hw_timer[timer_num].config.tn_use_xtal; + return &hw->int_st_timers; } #ifdef __cplusplus diff --git a/components/hal/include/hal/timer_hal.h b/components/hal/include/hal/timer_hal.h index cb3d5e0671..126c24def6 100644 --- a/components/hal/include/hal/timer_hal.h +++ b/components/hal/include/hal/timer_hal.h @@ -1,16 +1,8 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ /******************************************************************************* * NOTICE @@ -18,25 +10,22 @@ * See readme.md in hal/include/hal/readme.md ******************************************************************************/ -// The HAL layer for Timer Group. -// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters. - #pragma once +#include + #ifdef __cplusplus extern "C" { #endif -#include "soc/soc_caps.h" -#include "hal/timer_ll.h" -#include "hal/timer_types.h" +typedef struct timg_dev_t *gptimer_soc_handle_t; // GPTimer SOC layer handle /** * Context that should be maintained by both the driver and the HAL */ typedef struct { - timg_dev_t *dev; - timer_idx_t idx; + gptimer_soc_handle_t dev; // Timer SOC layer handle (i.e. register base address) + uint32_t timer_id; // Timer ID (i.e. index of the timer in the group) } timer_hal_context_t; /** @@ -45,294 +34,16 @@ typedef struct { * @param hal Context of the HAL layer * @param group_num The timer group number * @param timer_num The timer number - * - * @return None */ -void timer_hal_init(timer_hal_context_t *hal, timer_group_t group_num, timer_idx_t timer_num); - -/** - * @brief Get interrupt status register address and corresponding control bits mask - * - * @param hal Context of the HAL layer - * @param status_reg[out] interrupt status register address - * @param mask_bit[out] control bits mask - */ -void timer_hal_get_status_reg_mask_bit(timer_hal_context_t *hal, uint32_t *status_reg, uint32_t *mask_bit); - -/** - * @brief Reset timer peripheral - * - * @param hal Context of the HAL layer - * - * @return None - */ -void timer_hal_reset_periph(timer_hal_context_t *hal); - -/** - * @brief Set timer clock prescale value - * - * @param hal Context of the HAL layer - * @param divider Prescale value - * - * @return None - */ -#define timer_hal_set_divider(hal, divider) timer_ll_set_divider((hal)->dev, (hal)->idx, divider) - -/** - * @brief Get timer clock prescale value - * - * @param hal Context of the HAL layer - * @param divider Pointer to accept the prescale value - * - * @return None - */ -#define timer_hal_get_divider(hal, divider) timer_ll_get_divider((hal)->dev, (hal)->idx, divider) +void timer_hal_init(timer_hal_context_t *hal, uint32_t group_num, uint32_t timer_num); /** * @brief Load counter value into time-base counter * * @param hal Context of the HAL layer * @param load_val Counter value - * - * @return None */ -#define timer_hal_set_counter_value(hal, load_val) timer_ll_set_counter_value((hal)->dev, (hal)->idx, load_val) - -/** - * @brief Get counter value from time-base counter - * - * @param hal Context of the HAL layer - * @param timer_val Pointer to accept the counter value - * - * @return None - */ -#define timer_hal_get_counter_value(hal, timer_val) timer_ll_get_counter_value((hal)->dev, (hal)->idx, timer_val) - -/** - * @brief Set counter mode, include increment mode and decrement mode. - * - * @param hal Context of the HAL layer - * @param increase_en True to increment mode, fasle to decrement mode - * - * @return None - */ -#define timer_hal_set_counter_increase(hal, increase_en) timer_ll_set_counter_increase((hal)->dev, (hal)->idx, increase_en) - -/** - * @brief Get counter mode, include increment mode and decrement mode. - * - * @param hal Context of the HAL layer - * @param counter_dir Pointer to accept the counter mode - * - * @return - * - true Increment mode - * - false Decrement mode - */ -#define timer_hal_get_counter_increase(hal) timer_ll_get_counter_increase((hal)->dev, (hal)->idx) - -/** - * @brief Set counter status, enable or disable counter. - * - * @param hal Context of the HAL layer - * @param counter_en True to enable counter, false to disable counter - * - * @return None - */ -#define timer_hal_set_counter_enable(hal, counter_en) timer_ll_set_counter_enable((hal)->dev, (hal)->idx, counter_en) - -/** - * @brief Get counter status. - * - * @param hal Context of the HAL layer - * - * @return - * - true Enable counter - * - false Disable conuter - */ -#define timer_hal_get_counter_enable(hal) timer_ll_get_counter_enable((hal)->dev, (hal)->idx) - -/** - * @brief Set auto reload mode. - * - * @param hal Context of the HAL layer - * @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode - * - * @return None - */ -#define timer_hal_set_auto_reload(hal, auto_reload_en) timer_ll_set_auto_reload((hal)->dev, (hal)->idx, auto_reload_en) - -/** - * @brief Get auto reload mode. - * - * @param hal Context of the HAL layer - * - * @return - * - true Enable auto reload mode - * - false Disable auto reload mode - */ -#define timer_hal_get_auto_reload(hal) timer_ll_get_auto_reload((hal)->dev, (hal)->idx) - -/** - * @brief Set the counter value to trigger the alarm. - * - * @param hal Context of the HAL layer - * @param alarm_value Counter value to trigger the alarm - * - * @return None - */ -#define timer_hal_set_alarm_value(hal, alarm_value) timer_ll_set_alarm_value((hal)->dev, (hal)->idx, alarm_value) - -/** - * @brief Get the counter value to trigger the alarm. - * - * @param hal Context of the HAL layer - * @param alarm_value Pointer to accept the counter value to trigger the alarm - * - * @return None - */ -#define timer_hal_get_alarm_value(hal, alarm_value) timer_ll_get_alarm_value((hal)->dev, (hal)->idx, alarm_value) - -/** - * @brief Set the alarm status, enable or disable the alarm. - * - * @param hal Context of the HAL layer - * @param alarm_en True to enable alarm, false to disable alarm - * - * @return None - */ -#define timer_hal_set_alarm_enable(hal, alarm_en) timer_ll_set_alarm_enable((hal)->dev, (hal)->idx, alarm_en) - -/** - * @brief Get the alarm status. - * - * @param hal Context of the HAL layer - * - * @return - * - true Enable alarm - * - false Disable alarm - */ -#define timer_hal_get_alarm_enable(hal) timer_ll_get_alarm_enable((hal)->dev, (hal)->idx) - -/** - * @brief Set the level interrupt status, enable or disable the level interrupt. - * - * @param hal Context of the HAL layer - * @param level_int_en True to enable level interrupt, false to disable level interrupt - * - * @return None - */ -#define timer_hal_set_level_int_enable(hal, level_int_en) timer_ll_set_level_int_enable((hal)->dev, (hal)->idx, level_int_en) - -/** - * @brief Get the level interrupt status. - * - * @param hal Context of the HAL layer - * - * @return - * - true Enable level interrupt - * - false Disable level interrupt - */ -#define timer_hal_get_level_int_enable(hal) timer_ll_get_level_int_enable((hal)->dev, (hal)->idx) - -/** - * @brief Set the edge interrupt status, enable or disable the edge interrupt. - * - * @param hal Context of the HAL layer - * @param edge_int_en True to enable edge interrupt, false to disable edge interrupt - * - * @return None - */ -#define timer_hal_set_edge_int_enable(hal, edge_int_en) timer_ll_set_edge_int_enable((hal)->dev, (hal)->idx, edge_int_en) - -/** - * @brief Get the edge interrupt status. - * - * @param hal Context of the HAL layer - * - * @return - * - true Enable edge interrupt - * - false Disable edge interrupt - */ -#define timer_hal_get_edge_int_enable(hal) timer_ll_get_edge_int_enable((hal)->dev, (hal)->idx) - -/** - * @brief Enable timer interrupt. - * - * @param hal Context of the HAL layer - * - * @return None - */ -#define timer_hal_intr_enable(hal) timer_ll_intr_enable((hal)->dev, (hal)->idx) - -/** - * @brief Disable timer interrupt. - * - * @param hal Context of the HAL layer - * - * @return None - */ -#define timer_hal_intr_disable(hal) timer_ll_intr_disable((hal)->dev, (hal)->idx) - -/** - * @brief Clear interrupt status. - * - * @param hal Context of the HAL layer - * - * @return None - */ -#define timer_hal_clear_intr_status(hal) timer_ll_clear_intr_status((hal)->dev, (hal)->idx) - -/** - * @brief Get interrupt status. - * - * @param hal Context of the HAL layer - * @param intr_status Interrupt status - * - * @return None - */ -#define timer_hal_get_intr_status(hal, intr_status) timer_ll_get_intr_status((hal)->dev, intr_status) - -/** - * @brief Get interrupt raw status. - * - * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param intr_raw_status Interrupt raw status - * - * @return None - */ -#define timer_hal_get_intr_raw_status(group_num, intr_raw_status) timer_ll_get_intr_raw_status(group_num, intr_raw_status) - -/** - * @brief Get interrupt status register address. - * - * @param hal Context of the HAL layer - * - * @return Interrupt status register address - */ -#define timer_hal_get_intr_status_reg(hal) timer_ll_get_intr_status_reg((hal)->dev) - -#if SOC_TIMER_GROUP_SUPPORT_XTAL -/** - * @brief Set clock source. - * - * @param hal Context of the HAL layer - * @param use_xtal_en True to use XTAL clock, flase to use APB clock - * - * @return None - */ -#define timer_hal_set_use_xtal(hal, use_xtal_en) timer_ll_set_use_xtal((hal)->dev, (hal)->idx, use_xtal_en) - -/** - * @brief Get clock source. - * - * @param hal Context of the HAL layer - * - * @return - * - true Use XTAL clock - * - false Use APB clock - */ -#define timer_hal_get_use_xtal(hal) timer_ll_get_use_xtal((hal)->dev, (hal)->idx) -#endif +void timer_hal_set_counter_value(timer_hal_context_t *hal, uint64_t load_val); #ifdef __cplusplus } diff --git a/components/hal/include/hal/timer_types.h b/components/hal/include/hal/timer_types.h index 962fae043b..19e72418bd 100644 --- a/components/hal/include/hal/timer_types.h +++ b/components/hal/include/hal/timer_types.h @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once @@ -18,117 +10,39 @@ extern "C" { #endif -#include -#include -#include -#include "esp_attr.h" -#include "soc/soc_caps.h" - /** - * @brief Selects a Timer-Group out of 2 available groups + * @brief GPTimer clock source + * @note The clock source listed here is not supported on all targets + * @note User should select the clock source based on real requirements: + * ╔══════════════════════╦══════════════════════════════════╦══════════════════════════╗ + * ║ GPTimer clock source ║ Features ║ Power Management ║ + * ╠══════════════════════╬══════════════════════════════════╬══════════════════════════╣ + * ║ GPTIMER_CLK_SRC_APB ║ High resolution ║ ESP_PM_APB_FREQ_MAX lock ║ + * ╠══════════════════════╬══════════════════════════════════╬══════════════════════════╣ + * ║ GPTIMER_CLK_SRC_XTAL ║ Medium resolution, high accuracy ║ No PM lock ║ + * ╚══════════════════════╩══════════════════════════════════╩══════════════════════════╝ */ typedef enum { - TIMER_GROUP_0 = 0, /*! 1 - TIMER_GROUP_1 = 1, /*! 1 - TIMER_1 = 1, /*!