diff --git a/components/esp_hw_support/test/test_rtc_clk.c b/components/esp_hw_support/test/test_rtc_clk.c index 9d3d3d4895..b2032f7156 100644 --- a/components/esp_hw_support/test/test_rtc_clk.c +++ b/components/esp_hw_support/test/test_rtc_clk.c @@ -1,6 +1,7 @@ #include #include "unity.h" +#include "esp_attr.h" #include "soc/soc_caps.h" #include "soc/rtc.h" #include "soc/rtc_periph.h" @@ -18,12 +19,31 @@ #include "esp_rom_sys.h" #include "esp_rom_uart.h" +#include "esp_sleep.h" +#include "esp_system.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rtc.h" +#include "esp32/clk.h" +#include "esp32/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rtc.h" +#include "esp32s2/clk.h" +#include "esp32s2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rtc.h" +#include "esp32s3/clk.h" +#include "esp32s3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rtc.h" +#include "esp32c3/clk.h" +#include "esp32c3/rom/rtc.h" +#endif + extern void rtc_clk_select_rtc_slow_clk(void); #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3, ESP32C3) -#include "esp32/clk.h" - #define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk) static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char* name) @@ -290,3 +310,81 @@ TEST_CASE("Test starting 'External 32kHz XTAL' on the board without it.", "[rtc_ } #endif + +static RTC_NOINIT_ATTR int64_t start = 0; + +TEST_CASE("Test rtc clk calibration compensation", "[rtc_clk]") +{ + int64_t t1 = esp_rtc_get_time_us(); + + // Modify calibration value + esp_clk_slowclk_cal_set(esp_clk_slowclk_cal_get() / 2); + + // Delay for error accumulation. + vTaskDelay(pdMS_TO_TICKS(1000)); + + // Internally, the origin point of rtc clk has been adjusted + // so that t2 > t1 remains true + int64_t t2 = esp_rtc_get_time_us(); + + TEST_ASSERT(t2 > t1); + + // Restore calibration value + esp_clk_slowclk_cal_set(esp_clk_slowclk_cal_get() * 2); + + // Delay for error accumulation. + vTaskDelay(pdMS_TO_TICKS(1000)); + + t2 = esp_rtc_get_time_us(); + + TEST_ASSERT(t2 > t1); +} + +static void trigger_deepsleep(void) +{ + printf("Trigger deep sleep. Waiting for 10 sec ...\n"); + + // Simulate the dispersion of the calibration coefficients at start-up. + // Corrupt the calibration factor. + esp_clk_slowclk_cal_set(esp_clk_slowclk_cal_get() / 2); + + // Delay for error accumulation. + vTaskDelay(pdMS_TO_TICKS(1000)); + + // Save start time. Deep sleep. + start = esp_rtc_get_time_us(); + esp_sleep_enable_timer_wakeup(1000); + // In function esp_deep_sleep_start() uses function esp_sync_counters_rtc_and_frc() + // to prevent a negative time after wake up. + esp_deep_sleep_start(); +} + +static void check_time_deepsleep_1(void) +{ + RESET_REASON reason = rtc_get_reset_reason(0); + TEST_ASSERT(reason == DEEPSLEEP_RESET); + int64_t end = esp_rtc_get_time_us(); + TEST_ASSERT(end > start); + + esp_clk_slowclk_cal_set(esp_clk_slowclk_cal_get() * 2); + + // Delay for error accumulation. + vTaskDelay(pdMS_TO_TICKS(1000)); + + start = esp_rtc_get_time_us(); + + esp_sleep_enable_timer_wakeup(1000); + // In function esp_deep_sleep_start() uses function esp_sync_counters_rtc_and_frc() + // to prevent a negative time after wake up. + esp_deep_sleep_start(); +} + +static void check_time_deepsleep_2(void) +{ + RESET_REASON reason = rtc_get_reset_reason(0); + TEST_ASSERT(reason == DEEPSLEEP_RESET); + int64_t end = esp_rtc_get_time_us(); + TEST_ASSERT(end > start); +} + +TEST_CASE_MULTIPLE_STAGES("Test rtc clk calibration compensation across deep sleep", "[rtc_clk][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET]", trigger_deepsleep, check_time_deepsleep_1, check_time_deepsleep_2); diff --git a/components/newlib/port/esp_time_impl.c b/components/newlib/port/esp_time_impl.c index d13d3db402..bb3bc77bb3 100644 --- a/components/newlib/port/esp_time_impl.c +++ b/components/newlib/port/esp_time_impl.c @@ -16,6 +16,7 @@ #include #include +#include "esp_attr.h" #include "esp_system.h" #include "soc/rtc.h" @@ -60,7 +61,7 @@ static uint64_t s_boot_time; // when RTC is used to persist time, two RTC_STORE static _lock_t s_boot_time_lock; static _lock_t s_esp_rtc_time_lock; -static uint64_t s_esp_rtc_time_us, s_rtc_last_ticks; +static RTC_DATA_ATTR uint64_t s_esp_rtc_time_us = 0, s_rtc_last_ticks = 0; #if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) || defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER ) uint64_t esp_time_impl_get_time_since_boot(void)