Pārlūkot izejas kodu

esp_timer: allow querying the timer before esp_timer_init is called

Ivan Grokhotkov 4 gadi atpakaļ
vecāks
revīzija
85bc2d7240

+ 6 - 1
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();

+ 17 - 0
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

+ 11 - 0
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);

+ 5 - 0
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;

+ 12 - 11
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;

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