diff --git a/components/esp32/clk.c b/components/esp32/clk.c index ce7b580eb..ab589fcdc 100644 --- a/components/esp32/clk.c +++ b/components/esp32/clk.c @@ -13,11 +13,15 @@ // limitations under the License. #include +#include +#include #include "sdkconfig.h" #include "esp_attr.h" #include "esp_log.h" +#include "esp_clk.h" #include "rom/ets_sys.h" #include "rom/uart.h" +#include "rom/rtc.h" #include "soc/soc.h" #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" @@ -82,12 +86,6 @@ void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) g_ticks_per_us_app = ticks_per_us; } -/* This is a cached value of RTC slow clock period; it is updated by - * the select_rtc_slow_clk function at start up. This cached value is used in - * other places, like time syscalls and deep sleep. - */ -static uint32_t s_rtc_slow_clk_cal = 0; - static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) { if (slow_clk == RTC_SLOW_FREQ_32K_XTAL) { @@ -114,19 +112,16 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) ESP_EARLY_LOGD(TAG, "32k oscillator ready, wait=%d", wait); } rtc_clk_slow_freq_set(slow_clk); + uint32_t cal_val; if (SLOW_CLK_CAL_CYCLES > 0) { /* TODO: 32k XTAL oscillator has some frequency drift at startup. * Improve calibration routine to wait until the frequency is stable. */ - s_rtc_slow_clk_cal = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); + cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); } else { const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; - s_rtc_slow_clk_cal = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); + cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); } - ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", s_rtc_slow_clk_cal); -} - -uint32_t esp_clk_slowclk_cal_get() -{ - return s_rtc_slow_clk_cal; + ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); + esp_clk_slowclk_cal_set(cal_val); } diff --git a/components/esp32/include/esp_clk.h b/components/esp32/include/esp_clk.h index 0cedf0373..7b9c64c69 100644 --- a/components/esp32/include/esp_clk.h +++ b/components/esp32/include/esp_clk.h @@ -33,7 +33,7 @@ void esp_clk_init(void); /** - * @brief Get the cached calibration value of RTC slow clock + * @brief Get the calibration value of RTC slow clock * * The value is in the same format as returned by rtc_clk_cal (microseconds, * in Q13.19 fixed-point format). @@ -42,3 +42,15 @@ void esp_clk_init(void); */ uint32_t esp_clk_slowclk_cal_get(); + +/** + * @brief Update the calibration value of RTC slow clock + * + * The value has to be in the same format as returned by rtc_clk_cal (microseconds, + * in Q13.19 fixed-point format). + * This value is used by timekeeping functions (such as gettimeofday) to + * calculate current time based on RTC counter value. + * @param value calibration value obtained using rtc_clk_cal + */ +void esp_clk_slowclk_cal_set(uint32_t value); + diff --git a/components/esp32/include/rom/rtc.h b/components/esp32/include/rom/rtc.h index 9ea3126a9..3161fb274 100644 --- a/components/esp32/include/rom/rtc.h +++ b/components/esp32/include/rom/rtc.h @@ -50,9 +50,9 @@ extern "C" { * 0x3ff80000(0x400c0000) Fast 8192 deep sleep entry code * ************************************************************************************* - * Rtc store registers usage - * RTC_CNTL_STORE0_REG - * RTC_CNTL_STORE1_REG + * RTC store registers usage + * RTC_CNTL_STORE0_REG Reserved + * RTC_CNTL_STORE1_REG RTC_SLOW_CLK calibration value * RTC_CNTL_STORE2_REG Boot time, low word * RTC_CNTL_STORE3_REG Boot time, high word * RTC_CNTL_STORE4_REG External XTAL frequency @@ -62,6 +62,7 @@ extern "C" { ************************************************************************************* */ +#define RTC_SLOW_CLK_CAL_REG RTC_CNTL_STORE1_REG #define RTC_BOOT_TIME_LOW_REG RTC_CNTL_STORE2_REG #define RTC_BOOT_TIME_HIGH_REG RTC_CNTL_STORE3_REG #define RTC_XTAL_FREQ_REG RTC_CNTL_STORE4_REG diff --git a/components/newlib/time.c b/components/newlib/time.c index 51d0894da..8764c4076 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -130,6 +130,32 @@ static uint64_t get_boot_time() } #endif //defined(WITH_RTC) || defined(WITH_FRC1) + +void esp_clk_slowclk_cal_set(uint32_t new_cal) +{ +#if defined(WITH_RTC) + /* To force monotonic time values even when clock calibration value changes, + * we adjust boot time, given current time and the new calibration value: + * T = boot_time_old + cur_cal * ticks / 2^19 + * T = boot_time_adj + new_cal * ticks / 2^19 + * which results in: + * boot_time_adj = boot_time_old + ticks * (cur_cal - new_cal) / 2^19 + */ + const int64_t ticks = (int64_t) rtc_time_get(); + const uint32_t cur_cal = REG_READ(RTC_SLOW_CLK_CAL_REG); + int32_t cal_diff = (int32_t) (cur_cal - new_cal); + int64_t boot_time_diff = ticks * cal_diff / (1LL << RTC_CLK_CAL_FRACT); + uint64_t boot_time_adj = get_boot_time() + boot_time_diff; + set_boot_time(boot_time_adj); +#endif // WITH_RTC + REG_WRITE(RTC_SLOW_CLK_CAL_REG, new_cal); +} + +uint32_t esp_clk_slowclk_cal_get() +{ + return REG_READ(RTC_SLOW_CLK_CAL_REG); +} + void esp_setup_time_syscalls() { #if defined( WITH_FRC1 )