Merge branch 'bugfix/rtc_time_issues' into 'master'
Fixes for RTC time issues See merge request !849
This commit is contained in:
commit
07ccbb8dbc
|
@ -13,11 +13,15 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_clk.h"
|
||||||
#include "rom/ets_sys.h"
|
#include "rom/ets_sys.h"
|
||||||
#include "rom/uart.h"
|
#include "rom/uart.h"
|
||||||
|
#include "rom/rtc.h"
|
||||||
#include "soc/soc.h"
|
#include "soc/soc.h"
|
||||||
#include "soc/rtc.h"
|
#include "soc/rtc.h"
|
||||||
#include "soc/rtc_cntl_reg.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;
|
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)
|
static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
|
||||||
{
|
{
|
||||||
if (slow_clk == RTC_SLOW_FREQ_32K_XTAL) {
|
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);
|
ESP_EARLY_LOGD(TAG, "32k oscillator ready, wait=%d", wait);
|
||||||
}
|
}
|
||||||
rtc_clk_slow_freq_set(slow_clk);
|
rtc_clk_slow_freq_set(slow_clk);
|
||||||
|
uint32_t cal_val;
|
||||||
if (SLOW_CLK_CAL_CYCLES > 0) {
|
if (SLOW_CLK_CAL_CYCLES > 0) {
|
||||||
/* TODO: 32k XTAL oscillator has some frequency drift at startup.
|
/* TODO: 32k XTAL oscillator has some frequency drift at startup.
|
||||||
* Improve calibration routine to wait until the frequency is stable.
|
* 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 {
|
} else {
|
||||||
const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL;
|
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);
|
ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val);
|
||||||
}
|
esp_clk_slowclk_cal_set(cal_val);
|
||||||
|
|
||||||
uint32_t esp_clk_slowclk_cal_get()
|
|
||||||
{
|
|
||||||
return s_rtc_slow_clk_cal;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
* The value is in the same format as returned by rtc_clk_cal (microseconds,
|
||||||
* in Q13.19 fixed-point format).
|
* in Q13.19 fixed-point format).
|
||||||
|
@ -42,3 +42,15 @@ void esp_clk_init(void);
|
||||||
*/
|
*/
|
||||||
uint32_t esp_clk_slowclk_cal_get();
|
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);
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,9 @@ extern "C" {
|
||||||
* 0x3ff80000(0x400c0000) Fast 8192 deep sleep entry code
|
* 0x3ff80000(0x400c0000) Fast 8192 deep sleep entry code
|
||||||
*
|
*
|
||||||
*************************************************************************************
|
*************************************************************************************
|
||||||
* Rtc store registers usage
|
* RTC store registers usage
|
||||||
* RTC_CNTL_STORE0_REG
|
* RTC_CNTL_STORE0_REG Reserved
|
||||||
* RTC_CNTL_STORE1_REG
|
* RTC_CNTL_STORE1_REG RTC_SLOW_CLK calibration value
|
||||||
* RTC_CNTL_STORE2_REG Boot time, low word
|
* RTC_CNTL_STORE2_REG Boot time, low word
|
||||||
* RTC_CNTL_STORE3_REG Boot time, high word
|
* RTC_CNTL_STORE3_REG Boot time, high word
|
||||||
* RTC_CNTL_STORE4_REG External XTAL frequency
|
* 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_LOW_REG RTC_CNTL_STORE2_REG
|
||||||
#define RTC_BOOT_TIME_HIGH_REG RTC_CNTL_STORE3_REG
|
#define RTC_BOOT_TIME_HIGH_REG RTC_CNTL_STORE3_REG
|
||||||
#define RTC_XTAL_FREQ_REG RTC_CNTL_STORE4_REG
|
#define RTC_XTAL_FREQ_REG RTC_CNTL_STORE4_REG
|
||||||
|
|
|
@ -46,8 +46,23 @@
|
||||||
#ifdef WITH_RTC
|
#ifdef WITH_RTC
|
||||||
static uint64_t get_rtc_time_us()
|
static uint64_t get_rtc_time_us()
|
||||||
{
|
{
|
||||||
uint64_t ticks = rtc_time_get();
|
const uint64_t ticks = rtc_time_get();
|
||||||
return (uint32_t) ((ticks * esp_clk_slowclk_cal_get()) >> RTC_CLK_CAL_FRACT);
|
const uint32_t cal = esp_clk_slowclk_cal_get();
|
||||||
|
/* RTC counter result is up to 2^48, calibration factor is up to 2^24,
|
||||||
|
* for a 32kHz clock. We need to calculate (assuming no overflow):
|
||||||
|
* (ticks * cal) >> RTC_CLK_CAL_FRACT
|
||||||
|
*
|
||||||
|
* An overflow in the (ticks * cal) multiplication would cause time to
|
||||||
|
* wrap around after approximately 13 days, which is probably not enough
|
||||||
|
* for some applications.
|
||||||
|
* Therefore multiplication is split into two terms, for the lower 32-bit
|
||||||
|
* and the upper 16-bit parts of "ticks", i.e.:
|
||||||
|
* ((ticks_low + 2^32 * ticks_high) * cal) >> RTC_CLK_CAL_FRACT
|
||||||
|
*/
|
||||||
|
const uint64_t ticks_low = ticks & UINT32_MAX;
|
||||||
|
const uint64_t ticks_high = ticks >> 32;
|
||||||
|
return ((ticks_low * cal) >> RTC_CLK_CAL_FRACT) +
|
||||||
|
((ticks_high * cal) << (32 - RTC_CLK_CAL_FRACT));
|
||||||
}
|
}
|
||||||
#endif // WITH_RTC
|
#endif // WITH_RTC
|
||||||
|
|
||||||
|
@ -115,6 +130,32 @@ static uint64_t get_boot_time()
|
||||||
}
|
}
|
||||||
#endif //defined(WITH_RTC) || defined(WITH_FRC1)
|
#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()
|
void esp_setup_time_syscalls()
|
||||||
{
|
{
|
||||||
#if defined( WITH_FRC1 )
|
#if defined( WITH_FRC1 )
|
||||||
|
|
Loading…
Reference in a new issue