From 85bc2d7240cd53e15507c5d6239944ff0705e7e6 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 20 Jul 2021 03:31:25 +0200 Subject: [PATCH] esp_timer: allow querying the timer before esp_timer_init is called --- components/esp_system/startup.c | 7 ++++- components/esp_timer/include/esp_timer.h | 17 +++++++++++ .../private_include/esp_timer_impl.h | 11 +++++++ components/esp_timer/src/esp_timer.c | 5 ++++ components/esp_timer/src/esp_timer_impl_lac.c | 23 +++++++------- .../esp_timer/src/esp_timer_impl_systimer.c | 30 +++++++++++-------- 6 files changed, 68 insertions(+), 25 deletions(-) diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index 719afd108f..11fd441dbe 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -241,7 +241,6 @@ static void do_core_init(void) fail initializing it properly. */ heap_caps_init(); esp_newlib_init(); - esp_newlib_time_init(); if (g_spiram_ok) { #if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) @@ -266,6 +265,12 @@ static void do_core_init(void) esp_brownout_init(); #endif + // esp_timer early initialization is required for esp_timer_get_time to work. + // This needs to happen before VFS initialization, since some USB_SERIAL_JTAG VFS driver uses + // esp_timer_get_time to determine timeout conditions. + esp_timer_early_init(); + esp_newlib_time_init(); + #ifdef CONFIG_VFS_SUPPORT_IO #ifdef CONFIG_ESP_CONSOLE_UART esp_vfs_dev_uart_register(); diff --git a/components/esp_timer/include/esp_timer.h b/components/esp_timer/include/esp_timer.h index 8c94298947..02f9379736 100644 --- a/components/esp_timer/include/esp_timer.h +++ b/components/esp_timer/include/esp_timer.h @@ -83,11 +83,28 @@ typedef struct { bool skip_unhandled_events; //!< Skip unhandled events for periodic timers } esp_timer_create_args_t; + +/** + * @brief Minimal initialization of esp_timer + * + * @note This function is called from startup code. Applications do not need + * to call this function before using other esp_timer APIs. + * + * This function can be called very early in startup process, after this call + * only esp_timer_get_time function can be used. + * + * @return + * - ESP_OK on success + */ +esp_err_t esp_timer_early_init(void); + /** * @brief Initialize esp_timer library * * @note This function is called from startup code. Applications do not need * to call this function before using other esp_timer APIs. + * Before calling this function, esp_timer_early_init must be called by the + * startup code. * * @return * - ESP_OK on success diff --git a/components/esp_timer/private_include/esp_timer_impl.h b/components/esp_timer/private_include/esp_timer_impl.h index 63daba0d9e..888461f9fa 100644 --- a/components/esp_timer/private_include/esp_timer_impl.h +++ b/components/esp_timer/private_include/esp_timer_impl.h @@ -28,9 +28,20 @@ #include "esp_err.h" #include "esp_intr_alloc.h" +/** + * @brief Minimal initialization of platform specific layer of esp_timer + * This function can be called very early in startup process, after this call + * only esp_timer_get_time function can be used. + * esp_timer_impl_init has to be called after this function to initialize the + * rest of esp_timer implementation. + * @return ESP_OK + */ +esp_err_t esp_timer_impl_early_init(void); + /** * @brief Initialize platform specific layer of esp_timer * @param alarm_handler function to call on timer interrupt + * Before calling this function, esp_timer_impl_early_init must be called. * @return ESP_OK, ESP_ERR_NO_MEM, or one of the errors from interrupt allocator */ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler); diff --git a/components/esp_timer/src/esp_timer.c b/components/esp_timer/src/esp_timer.c index ad185760f5..375cad6c4d 100644 --- a/components/esp_timer/src/esp_timer.c +++ b/components/esp_timer/src/esp_timer.c @@ -428,6 +428,11 @@ static IRAM_ATTR inline bool is_initialized(void) return s_timer_task != NULL; } +esp_err_t esp_timer_early_init(void) +{ + return esp_timer_impl_early_init(); +} + esp_err_t esp_timer_init(void) { esp_err_t err; diff --git a/components/esp_timer/src/esp_timer_impl_lac.c b/components/esp_timer/src/esp_timer_impl_lac.c index aa414709e7..13338f0874 100644 --- a/components/esp_timer/src/esp_timer_impl_lac.c +++ b/components/esp_timer/src/esp_timer_impl_lac.c @@ -146,9 +146,6 @@ uint64_t IRAM_ATTR esp_timer_impl_get_counter_reg(void) int64_t IRAM_ATTR esp_timer_impl_get_time(void) { - if (s_alarm_handler == NULL) { - return 0; - } return esp_timer_impl_get_counter_reg() / TICKS_PER_US; } @@ -217,13 +214,10 @@ void esp_timer_impl_advance(int64_t time_diff_us) portEXIT_CRITICAL(&s_time_update_lock); } -esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) +esp_err_t esp_timer_impl_early_init(void) { - s_alarm_handler = alarm_handler; - periph_module_enable(PERIPH_LACT); - /* Reset the state */ REG_WRITE(CONFIG_REG, 0); REG_WRITE(LOAD_LO_REG, 0); REG_WRITE(LOAD_HI_REG, 0); @@ -231,6 +225,17 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) REG_WRITE(ALARM_HI_REG, UINT32_MAX); REG_WRITE(LOAD_REG, 1); REG_SET_BIT(INT_CLR_REG, TIMG_LACT_INT_CLR); + REG_SET_FIELD(CONFIG_REG, TIMG_LACT_DIVIDER, APB_CLK_FREQ / 1000000 / TICKS_PER_US); + REG_SET_BIT(CONFIG_REG, TIMG_LACT_INCREASE | + TIMG_LACT_LEVEL_INT_EN | + TIMG_LACT_EN); + + return ESP_OK; +} + +esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) +{ + s_alarm_handler = alarm_handler; const int interrupt_lvl = (1 << CONFIG_ESP_TIMER_INTERRUPT_LEVEL) & ESP_INTR_FLAG_LEVELMASK; esp_err_t err = esp_intr_alloc(INTR_SOURCE_LACT, @@ -250,10 +255,6 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) esp_timer_impl_update_apb_freq(esp_clk_apb_freq() / 1000000); - REG_SET_BIT(CONFIG_REG, TIMG_LACT_INCREASE | - TIMG_LACT_LEVEL_INT_EN | - TIMG_LACT_EN); - // Set the step for the sleep mode when the timer will work // from a slow_clk frequency instead of the APB frequency. uint32_t slowclk_ticks_per_us = esp_clk_slowclk_cal_get() * TICKS_PER_US; diff --git a/components/esp_timer/src/esp_timer_impl_systimer.c b/components/esp_timer/src/esp_timer_impl_systimer.c index 28bdb07212..833e845460 100644 --- a/components/esp_timer/src/esp_timer_impl_systimer.c +++ b/components/esp_timer/src/esp_timer_impl_systimer.c @@ -72,9 +72,6 @@ uint64_t IRAM_ATTR esp_timer_impl_get_counter_reg(void) int64_t IRAM_ATTR esp_timer_impl_get_time(void) { - if (unlikely(s_alarm_handler == NULL)) { - return 0; - } return systimer_hal_get_counter_value(&systimer_hal, SYSTIMER_LL_COUNTER_CLOCK) / SYSTIMER_LL_TICKS_PER_US; } @@ -119,6 +116,23 @@ void esp_timer_impl_advance(int64_t time_us) portEXIT_CRITICAL_SAFE(&s_time_update_lock); } +esp_err_t esp_timer_impl_early_init(void) +{ + systimer_hal_init(&systimer_hal); + +#if !SOC_SYSTIMER_FIXED_TICKS_US + assert(rtc_clk_xtal_freq_get() == 40 && "update the step for xtal to support other XTAL:APB frequency ratios"); + systimer_hal_set_steps_per_tick(&systimer_hal, 0, 2); // for xtal + systimer_hal_set_steps_per_tick(&systimer_hal, 1, 1); // for pll +#endif + + systimer_hal_enable_counter(&systimer_hal, SYSTIMER_LL_COUNTER_CLOCK); + systimer_hal_select_alarm_mode(&systimer_hal, SYSTIMER_LL_ALARM_CLOCK, SYSTIMER_ALARM_MODE_ONESHOT); + systimer_hal_connect_alarm_counter(&systimer_hal, SYSTIMER_LL_ALARM_CLOCK, SYSTIMER_LL_COUNTER_CLOCK); + + return ESP_OK; +} + esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) { s_alarm_handler = alarm_handler; @@ -137,16 +151,6 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) goto err_intr_alloc; } - systimer_hal_init(&systimer_hal); -#if !SOC_SYSTIMER_FIXED_TICKS_US - assert(rtc_clk_xtal_freq_get() == 40 && "update the step for xtal to support other XTAL:APB frequency ratios"); - systimer_hal_set_steps_per_tick(&systimer_hal, 0, 2); // for xtal - systimer_hal_set_steps_per_tick(&systimer_hal, 1, 1); // for pll -#endif - systimer_hal_enable_counter(&systimer_hal, SYSTIMER_LL_COUNTER_CLOCK); - systimer_hal_select_alarm_mode(&systimer_hal, SYSTIMER_LL_ALARM_CLOCK, SYSTIMER_ALARM_MODE_ONESHOT); - systimer_hal_connect_alarm_counter(&systimer_hal, SYSTIMER_LL_ALARM_CLOCK, SYSTIMER_LL_COUNTER_CLOCK); - /* TODO: if SYSTIMER is used for anything else, access to SYSTIMER_INT_ENA_REG has to be * protected by a shared spinlock. Since this code runs as part of early startup, this * is practically not an issue.