Просмотр исходного кода

esp_system: introduce system time functions

- Introduce system time function and concept of system time provider.
esp_timer is system time provider when present.
- Set the reference point for system time, g_startup_time.
- Use the system time functions in newlib instead of calling esp_timer
functions directly
Renz Bagaporo 5 лет назад
Родитель
Сommit
346cf4430d

+ 10 - 0
components/esp_common/include/esp_private/system_internal.h

@@ -61,6 +61,16 @@ void esp_reset_reason_set_hint(esp_reset_reason_t hint);
  */
 esp_reset_reason_t esp_reset_reason_get_hint(void);
 
+/** 
+ * @brief Set function which provides `esp_system_get_time`.
+ *
+ * @param time_fn function which provides system time
+ * @param resolution resolution in microseconds of the time provider function specified
+ */
+void esp_system_set_time_provider(esp_system_time_fn_t time_fn, uint32_t resolution);
+
+
+
 #ifdef __cplusplus
 }
 #endif

+ 2 - 2
components/esp_system/CMakeLists.txt

@@ -1,4 +1,4 @@
-idf_component_register(SRCS "panic.c" "system_api.c" "startup.c"
+idf_component_register(SRCS "panic.c" "system_api.c" "startup.c" "system_time.c"
                     INCLUDE_DIRS include
                     PRIV_REQUIRES spi_flash app_update
                                   # requirements due to startup code
@@ -21,4 +21,4 @@ endif()
 set_source_files_properties(
     startup.c
     PROPERTIES COMPILE_FLAGS
-    -fno-stack-protector)
+    -fno-stack-protector)

+ 4 - 0
components/esp_system/include/esp_private/startup_internal.h

@@ -64,6 +64,10 @@ static __attribute__((used)) esp_system_init_fn_t _SECTION_ATTR_IMPL(".esp_syste
 static __attribute__((used)) __VA_ARGS__ void __esp_system_init_fn_##f(void) // [refactor-todo] this can be made public API if we allow components to declare init functions, 
                                                                              // instead of calling them explicitly
 
+extern uint64_t g_startup_time;   // Startup time that serves as the point of origin for system time. Should be set by the entry 
+                                  // function in the port layer. May be 0 as well if this is not backed by a persistent counter, in which case
+                                  // startup time = system time = 0 at the point the entry function sets this variable.
+
 #ifdef __cplusplus
 }
 #endif

+ 16 - 0
components/esp_system/include/esp_system.h

@@ -28,6 +28,8 @@
 extern "C" {
 #endif
 
+typedef int64_t (*esp_system_time_fn_t)(void);
+
 typedef enum {
     ESP_MAC_WIFI_STA,
     ESP_MAC_WIFI_SOFTAP,
@@ -286,6 +288,20 @@ typedef struct {
  */
 void esp_chip_info(esp_chip_info_t* out_info);
 
+/** 
+ * @brief Get the time in microseconds since startup
+ * 
+ * @returns time since startup in microseconds
+ */
+int64_t esp_system_get_time(void);
+
+/** 
+ * @brief Get the resolution of the time returned by `esp_system_get_time`.
+ * 
+ * @returns the resolution in microseconds
+ */
+uint32_t esp_system_get_time_resolution(void);
+
 #if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
 /**
  * @brief Cache lock bug exists or not

+ 21 - 1
components/esp_system/port/cpu_start.c

@@ -55,6 +55,8 @@
 #include "soc/dport_reg.h"
 #include "soc/efuse_reg.h"
 #include "soc/cpu.h"
+#include "soc/rtc.h"
+#include "soc/spinlock.h"
 
 #include "trax.h"
 
@@ -67,6 +69,7 @@
 #endif
 
 #include "esp_private/startup_internal.h"
+#include "esp_private/system_internal.h"
 
 extern int _bss_start;
 extern int _bss_end;
@@ -95,16 +98,27 @@ static volatile bool s_cpu_inited[SOC_CPU_CORES_NUM] = { false };
 static volatile bool s_resume_cores;
 #endif
 
+uint64_t g_startup_time = 0;
+
 // If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false.
 bool g_spiram_ok = true;
 
+static int64_t default_system_time_fn(void)
+{
+    int64_t t = 0;
+    static spinlock_t s_time_lock = SPINLOCK_INITIALIZER;
+    spinlock_acquire(&s_time_lock, SPINLOCK_WAIT_FOREVER);
+    t = (esp_rtc_get_time_us() - g_startup_time); 
+    spinlock_release(&s_time_lock);
+    return t;
+}
+
 #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
 void startup_resume_other_cores(void)
 {
     s_resume_cores = true;
 }
 
-
 void IRAM_ATTR call_start_cpu1(void)
 {
     cpu_hal_set_vecbase(&_init_start);
@@ -352,6 +366,12 @@ void IRAM_ATTR call_start_cpu0(void)
 
     esp_clk_init();
     esp_perip_clk_init();
+
+    // Now that the clocks have been set-up, set the startup time from RTC
+    // and default RTC-backed system time provider.
+    g_startup_time = esp_rtc_get_time_us();
+    esp_system_set_time_provider(default_system_time_fn, 1000000L / rtc_clk_slow_freq_get_hz());
+
     intr_matrix_clear();
 
 #ifdef CONFIG_ESP_CONSOLE_UART

+ 4 - 3
components/esp_system/startup.c

@@ -183,6 +183,7 @@ static void IRAM_ATTR do_core_init(void)
        fail initializing it properly. */
     heap_caps_init();
     esp_setup_syscall_table();
+    esp_newlib_time_init();
 
     if (g_spiram_ok) {
 #if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
@@ -244,9 +245,6 @@ static void IRAM_ATTR do_core_init(void)
     esp_efuse_disable_basic_rom_console();
 #endif
 
-    esp_timer_init();
-    esp_set_time_from_rtc();
-
     // [refactor-todo] move this to secondary init
 #if CONFIG_APPTRACE_ENABLE
     err = esp_apptrace_init();
@@ -301,6 +299,7 @@ static void IRAM_ATTR do_secondary_init(void)
 
 void IRAM_ATTR start_cpu0_default(void)
 {
+
     ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
 
     // Display information about the current running image.
@@ -353,6 +352,8 @@ void IRAM_ATTR start_cpu0_default(void)
 
 IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0))
 {
+    esp_timer_init();
+
 #if defined(CONFIG_PM_ENABLE) && defined(CONFIG_ESP_CONSOLE_UART)
     /* When DFS is enabled, use REFTICK as UART clock source */
     uart_ll_set_baudrate(UART_LL_GET_HW(CONFIG_ESP_CONSOLE_UART_NUM), UART_SCLK_REF_TICK, CONFIG_ESP_CONSOLE_UART_BAUDRATE);

+ 41 - 0
components/esp_system/system_time.c

@@ -0,0 +1,41 @@
+// 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.
+
+#include "esp_system.h"
+#include "esp_attr.h"
+
+typedef struct {
+    esp_system_time_fn_t fn;        // time provider function
+    uint32_t resolution;            // resolution in microseconds of the time provider
+} system_time_provider_t;
+
+// This is expected to be modified only on startup, so
+// it should be safe to not put locks on it.
+static system_time_provider_t s_system_time_provider;
+
+int64_t IRAM_ATTR esp_system_get_time(void)
+{
+    return (*s_system_time_provider.fn)();
+}
+
+uint32_t IRAM_ATTR esp_system_get_time_resolution(void)
+{
+    return s_system_time_provider.resolution;
+}
+
+void esp_system_set_time_provider(esp_system_time_fn_t time_fn, uint32_t resolution)
+{
+    s_system_time_provider.fn = time_fn;
+    s_system_time_provider.resolution = resolution;
+}

+ 2 - 1
components/esp_timer/CMakeLists.txt

@@ -1,7 +1,8 @@
 idf_build_get_property(target IDF_TARGET)
 
 set(srcs    "src/esp_timer.c"
-            "src/ets_timer_legacy.c")
+            "src/ets_timer_legacy.c"
+            "src/timekeeping.c")
 
 if(CONFIG_ESP_TIMER_IMPL_FRC2)
     list(APPEND srcs "src/esp_timer_impl_frc_legacy.c")

+ 5 - 0
components/esp_timer/private_include/esp_timer_impl.h

@@ -117,3 +117,8 @@ uint64_t esp_timer_impl_get_counter_reg(void);
  * @return the value of the alarm register
  */
 uint64_t esp_timer_impl_get_alarm_reg(void);
+
+/**
+ * @brief Initialize and provide system timekeeping functions.
+ */
+esp_err_t esp_timer_timekeeping_impl_init(void);

+ 6 - 3
components/esp_timer/src/esp_timer.c

@@ -97,7 +97,6 @@ static StaticQueue_t s_timer_semaphore_memory;
 static portMUX_TYPE s_timer_lock = portMUX_INITIALIZER_UNLOCKED;
 
 
-
 esp_err_t esp_timer_create(const esp_timer_create_args_t* args,
                            esp_timer_handle_t* out_handle)
 {
@@ -349,7 +348,6 @@ static IRAM_ATTR bool is_initialized(void)
     return s_timer_task != NULL;
 }
 
-
 esp_err_t esp_timer_init(void)
 {
     esp_err_t err;
@@ -380,6 +378,11 @@ esp_err_t esp_timer_init(void)
         goto out;
     }
 
+    err = esp_timer_timekeeping_impl_init();
+    if (err != ESP_OK) {
+        goto out;
+    }
+
     return ESP_OK;
 
 out:
@@ -505,4 +508,4 @@ int64_t IRAM_ATTR esp_timer_get_next_alarm(void)
     }
     timer_list_unlock();
     return next_alarm;
-}
+}

+ 45 - 0
components/esp_timer/src/timekeeping.c

@@ -0,0 +1,45 @@
+// 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.
+
+#include "esp_timer.h"
+
+#include "esp_private/esp_timer_private.h"
+#include "esp_private/system_internal.h"
+
+#include "sdkconfig.h"
+
+#if defined( CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 ) || \
+    defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 ) || \
+    defined( CONFIG_ESP32S2_TIME_SYSCALL_USE_FRC1 ) || \
+    defined( CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC_FRC1 )
+#define WITH_FRC 1
+#endif
+
+#if WITH_FRC
+void esp_timer_timekeeping_impl_init(void)
+{
+    // esp_system_get_time here calls the previous system time provider.
+    // This should add the time elapsed from g_startup_time up to esp_timer_init,
+    // therefore keeping it as the point of reference (g_startup_time, that is).
+    esp_timer_private_advance(esp_system_get_time());
+
+    // esp_timer provides microsecond-resolution timers to the system
+    esp_system_set_time_provider(esp_timer_get_time, 1);
+}
+#else
+void esp_timer_timekeeping_impl_init(void)
+{
+    // Do not override default system time provider
+}
+#endif

+ 1 - 1
components/newlib/CMakeLists.txt

@@ -21,7 +21,7 @@ list(APPEND ldfragments newlib.lf)
 idf_component_register(SRCS "${srcs}"
                     INCLUDE_DIRS "${include_dirs}"
                     PRIV_INCLUDE_DIRS priv_include
-                    PRIV_REQUIRES soc esp_timer
+                    PRIV_REQUIRES soc
                     LDFRAGMENTS "${ldfragments}")  
 
 # Toolchain libraries require code defined in this component

+ 13 - 19
components/newlib/port/esp_time_impl.c

@@ -15,8 +15,6 @@
 #include <time.h>
 #include <sys/time.h>
 
-#include "esp_timer.h"
-
 #include "esp_system.h"
 
 #include "soc/spinlock.h"
@@ -70,24 +68,31 @@ uint64_t esp_time_impl_get_time_since_boot(void)
 
 #ifdef WITH_FRC
 #ifdef WITH_RTC
-    microseconds = s_microseconds_offset + esp_timer_get_time();
+    microseconds = s_microseconds_offset + esp_system_get_time();
 #else
-    microseconds = esp_timer_get_time();
+    microseconds = esp_system_get_time();
 #endif // WITH_RTC
 #elif defined(WITH_RTC)
+    spinlock_acquire(&s_time_lock, SPINLOCK_WAIT_FOREVER);
     microseconds = esp_rtc_get_time_us();
+    spinlock_release(&s_time_lock);
 #endif // WITH_FRC
     return microseconds;
 }
 
 uint64_t esp_time_impl_get_time(void)
 {
+    uint64_t microseconds = 0;
 #if defined( WITH_FRC )
-    return esp_timer_get_time();
+    microseconds = esp_system_get_time();
 #elif defined( WITH_RTC )
-    return esp_rtc_get_time_us();
+    spinlock_acquire(&s_time_lock, SPINLOCK_WAIT_FOREVER);
+    microseconds = esp_rtc_get_time_us();
+    spinlock_release(&s_time_lock);
 #endif // WITH_FRC
+    return microseconds;
 }
+
 #endif // defined( WITH_FRC ) || defined( WITH_RTC )
 
 
@@ -175,7 +180,7 @@ void esp_set_time_from_rtc(void)
 {
 #if defined( WITH_FRC ) && defined( WITH_RTC )
     // initialize time from RTC clock
-    s_microseconds_offset = esp_rtc_get_time_us() - esp_timer_get_time();
+    s_microseconds_offset = esp_rtc_get_time_us() - esp_system_get_time();
 #endif // WITH_FRC && WITH_RTC
 }
 
@@ -185,7 +190,7 @@ void esp_sync_counters_rtc_and_frc(void)
     struct timeval tv;
     gettimeofday(&tv, NULL);
     settimeofday(&tv, NULL);
-    int64_t s_microseconds_offset_cur = esp_rtc_get_time_us() - esp_timer_get_time();
+    int64_t s_microseconds_offset_cur = esp_rtc_get_time_us() - esp_system_get_time();
     esp_time_impl_set_boot_time(esp_time_impl_get_boot_time() + ((int64_t)s_microseconds_offset - s_microseconds_offset_cur));
 #endif
 }
@@ -193,15 +198,4 @@ void esp_sync_counters_rtc_and_frc(void)
 void esp_time_impl_init(void)
 {
     esp_set_time_from_rtc();
-}
-
-uint32_t esp_time_impl_get_time_resolution(void)
-{
-#if defined( WITH_FRC )
-    return 1L;
-#elif defined( WITH_RTC )
-    uint32_t rtc_freq = rtc_clk_slow_freq_get_hz();
-    assert(rtc_freq != 0);
-    return 1000000L / rtc_freq;
-#endif // WITH_FRC
 }

+ 2 - 1
components/newlib/time.c

@@ -22,6 +22,7 @@
 #include <sys/time.h>
 #include <sys/times.h>
 
+#include "esp_system.h"
 #include "esp_attr.h"
 
 #include "freertos/FreeRTOS.h"
@@ -285,7 +286,7 @@ int clock_getres (clockid_t clock_id, struct timespec *res)
     }
 
     res->tv_sec = 0;
-    res->tv_nsec = esp_time_impl_get_time_resolution() * 1000;
+    res->tv_nsec = esp_system_get_time_resolution() * 1000;
 
     return 0;
 #else