From 768cd5ee595bb7744e1489e7b2301228037b841e Mon Sep 17 00:00:00 2001 From: Zhenyu Wu Date: Mon, 26 Dec 2016 15:43:19 -0500 Subject: [PATCH 1/4] Renovate ESP8266 rtc implementation; provide access to non-RTC system time --- esp8266/fatfs_port.c | 2 +- esp8266/machine_rtc.c | 126 +++++++++++++++++++++++++++--------------- esp8266/modmachine.h | 3 + esp8266/modutime.c | 4 +- 4 files changed, 86 insertions(+), 49 deletions(-) diff --git a/esp8266/fatfs_port.c b/esp8266/fatfs_port.c index 9c84f04e45ce0..87ac77d27b15d 100644 --- a/esp8266/fatfs_port.c +++ b/esp8266/fatfs_port.c @@ -33,7 +33,7 @@ DWORD get_fattime(void) { // TODO: Optimize division (there's no HW division support on ESP8266, // so it's expensive). - uint32_t secs = (uint32_t)(pyb_rtc_get_us_since_2000() / 1000000); + uint32_t secs = (uint32_t)(esp_clk_get_us_since_2000() / 1000000); timeutils_struct_time_t tm; timeutils_seconds_since_2000_to_struct_time(secs, &tm); diff --git a/esp8266/machine_rtc.c b/esp8266/machine_rtc.c index 54eeea6f6e1ba..14e29df406f8d 100644 --- a/esp8266/machine_rtc.c +++ b/esp8266/machine_rtc.c @@ -39,12 +39,15 @@ typedef struct _pyb_rtc_obj_t { } pyb_rtc_obj_t; #define MEM_MAGIC 0x75507921 -#define MEM_DELTA_ADDR 64 -#define MEM_CAL_ADDR (MEM_DELTA_ADDR + 2) -#define MEM_USER_MAGIC_ADDR (MEM_CAL_ADDR + 1) +#define MEM_RTC_BASE 64 +#define MEM_RTCOFS_ADDR (MEM_RTC_BASE + 0) +#define MEM_CLKOFS_ADDR (MEM_RTCOFS_ADDR + 2) +#define MEM_RTCREF_ADDR (MEM_CLKOFS_ADDR + 2) +#define MEM_CLKREF_ADDR (MEM_RTCREF_ADDR + 1) +#define MEM_USER_MAGIC_ADDR (MEM_CLKREF_ADDR + 1) #define MEM_USER_LEN_ADDR (MEM_USER_MAGIC_ADDR + 1) #define MEM_USER_DATA_ADDR (MEM_USER_LEN_ADDR + 1) -#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_DELTA_ADDR) * 4) +#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_RTC_BASE) * 4) // singleton RTC object STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}}; @@ -55,23 +58,86 @@ uint64_t pyb_rtc_alarm0_expiry; // in microseconds // RTC overflow checking STATIC uint32_t rtc_last_ticks; +STATIC uint32_t rtc_last_unit; +// Clock overflow checking +STATIC uint32_t clk_last_ticks; + +void esp_clk_set_us_since_2000(uint64_t nowus) { + // Get the current clock tick + clk_last_ticks = system_get_time(); + // Set current time as base for future calculations + system_rtc_mem_write(MEM_CLKOFS_ADDR, &nowus, sizeof(nowus)); + system_rtc_mem_write(MEM_CLKREF_ADDR, &clk_last_ticks, sizeof(clk_last_ticks)); +}; + +uint64_t esp_clk_get_us_since_2000() { + uint64_t offset; + uint32_t clk_ticks; + + system_rtc_mem_read(MEM_CLKOFS_ADDR, &offset, sizeof(offset)); + clk_ticks = system_get_time(); + + int64_t newoffset = offset; + if (clk_ticks >= clk_last_ticks) { + newoffset+= clk_ticks-clk_last_ticks; + } else { + // If overflow happened, assume 1 wrap-around and persist info for the new cycle + newoffset+= clk_ticks+~clk_last_ticks+1; + clk_last_ticks = clk_ticks; + system_rtc_mem_write(MEM_CLKOFS_ADDR, &newoffset, sizeof(newoffset)); + system_rtc_mem_write(MEM_CLKREF_ADDR, &clk_last_ticks, sizeof(clk_last_ticks)); + } + return newoffset; +}; + +void pyb_rtc_set_us_since_2000(uint64_t nowus) { + // Get the current clock tick + rtc_last_ticks = system_get_rtc_time(); + // Set current time as base for future calculations + system_rtc_mem_write(MEM_RTCOFS_ADDR, &nowus, sizeof(nowus)); + system_rtc_mem_write(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks)); +}; + +uint64_t pyb_rtc_get_us_since_2000() { + uint64_t offset; + uint32_t rtc_ticks; + + system_rtc_mem_read(MEM_RTCOFS_ADDR, &offset, sizeof(offset)); + rtc_ticks = system_get_rtc_time(); + rtc_last_unit = (system_rtc_clock_cali_proc()*100)>>12; + + int64_t newoffset = offset; + int64_t newdelta = rtc_ticks; + if (rtc_ticks >= rtc_last_ticks) { + newdelta-= rtc_last_ticks; + } else { + // If overflow happened, assume 1 wrap-around and persist info for the new cycle + newdelta+= ~rtc_last_ticks+1; + system_rtc_mem_write(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks)); + } + // Since RTC unit is volatile, we have to rebase every time + newoffset+= newdelta*rtc_last_unit; + rtc_last_ticks = rtc_ticks; + system_rtc_mem_write(MEM_RTCOFS_ADDR, &newoffset, sizeof(newoffset)); + return newoffset; +}; void mp_hal_rtc_init(void) { uint32_t magic; system_rtc_mem_read(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); if (magic != MEM_MAGIC) { + // Reset clock to 2000-01-01 00:00:00 AM + esp_clk_set_us_since_2000(0); + pyb_rtc_set_us_since_2000(0); magic = MEM_MAGIC; system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); - uint32_t cal = system_rtc_clock_cali_proc(); - int64_t delta = 0; - system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal)); - system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); uint32_t len = 0; system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len)); + } else { + // Use rtc clock's data to reinitialize system clock + esp_clk_set_us_since_2000(pyb_rtc_get_us_since_2000()); } - // system_get_rtc_time() is always 0 after reset/deepsleep - rtc_last_ticks = system_get_rtc_time(); // reset ALARM0 state pyb_rtc_alarm0_wake = 0; @@ -86,44 +152,12 @@ STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp return (mp_obj_t)&pyb_rtc_obj; } -void pyb_rtc_set_us_since_2000(uint64_t nowus) { - uint32_t cal = system_rtc_clock_cali_proc(); - // Save RTC ticks for overflow detection. - rtc_last_ticks = system_get_rtc_time(); - int64_t delta = nowus - (((uint64_t)rtc_last_ticks * cal) >> 12); - - // As the calibration value jitters quite a bit, to make the - // clock at least somewhat practially usable, we need to store it - system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal)); - system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); -}; - -uint64_t pyb_rtc_get_us_since_2000() { - uint32_t cal; - int64_t delta; - uint32_t rtc_ticks; - - system_rtc_mem_read(MEM_CAL_ADDR, &cal, sizeof(cal)); - system_rtc_mem_read(MEM_DELTA_ADDR, &delta, sizeof(delta)); - - // ESP-SDK system_get_rtc_time() only returns uint32 and therefore - // overflow about every 7:45h. Thus, we have to check for - // overflow and handle it. - rtc_ticks = system_get_rtc_time(); - if (rtc_ticks < rtc_last_ticks) { - // Adjust delta because of RTC overflow. - delta += (uint64_t)cal << 20; - system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); - } - rtc_last_ticks = rtc_ticks; - - return (((uint64_t)rtc_ticks * cal) >> 12) + delta; -}; - void rtc_prepare_deepsleep(uint64_t sleep_us) { // RTC time will reset at wake up. Let's be preared for this. - int64_t delta = pyb_rtc_get_us_since_2000() + sleep_us; - system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); + int64_t newoffset = pyb_rtc_get_us_since_2000() + sleep_us; + rtc_last_ticks+= sleep_us / rtc_last_unit; + system_rtc_mem_write(MEM_RTCOFS_ADDR, &newoffset, sizeof(newoffset)); + system_rtc_mem_write(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks)); } STATIC mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { diff --git a/esp8266/modmachine.h b/esp8266/modmachine.h index 414aaa85b0a14..0396ebdaa5af7 100644 --- a/esp8266/modmachine.h +++ b/esp8266/modmachine.h @@ -34,6 +34,9 @@ void pin_set(uint pin, int value); extern uint32_t pyb_rtc_alarm0_wake; extern uint64_t pyb_rtc_alarm0_expiry; +void esp_clk_set_us_since_2000(uint64_t nowus); +uint64_t esp_clk_get_us_since_2000(); + void pyb_rtc_set_us_since_2000(uint64_t nowus); uint64_t pyb_rtc_get_us_since_2000(); void rtc_prepare_deepsleep(uint64_t sleep_us); diff --git a/esp8266/modutime.c b/esp8266/modutime.c index 2adb6c563b378..e457e574f18ce 100644 --- a/esp8266/modutime.c +++ b/esp8266/modutime.c @@ -60,7 +60,7 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) { timeutils_struct_time_t tm; mp_int_t seconds; if (n_args == 0 || args[0] == mp_const_none) { - seconds = pyb_rtc_get_us_since_2000() / 1000 / 1000; + seconds = esp_clk_get_us_since_2000() / 1000 / 1000; } else { seconds = mp_obj_get_int(args[0]); } @@ -103,7 +103,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); /// Returns the number of seconds, as an integer, since 1/1/2000. STATIC mp_obj_t time_time(void) { // get date and time - return mp_obj_new_int(pyb_rtc_get_us_since_2000() / 1000 / 1000); + return mp_obj_new_int(esp_clk_get_us_since_2000() / 1000 / 1000); } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); From fc5b37feff6b03c10cbb4e6e8461a9f5ec78585a Mon Sep 17 00:00:00 2001 From: Zhenyu Wu Date: Mon, 26 Dec 2016 16:28:31 -0500 Subject: [PATCH 2/4] Implement access to (more stable) ESP8266 system clock, and use this clock for general purpose time functions --- esp8266/fatfs_port.c | 2 +- esp8266/machine_rtc.c | 113 +++++++++++++++++++++++++++--------------- esp8266/modmachine.h | 3 ++ esp8266/modutime.c | 4 +- 4 files changed, 80 insertions(+), 42 deletions(-) diff --git a/esp8266/fatfs_port.c b/esp8266/fatfs_port.c index 9c84f04e45ce0..87ac77d27b15d 100644 --- a/esp8266/fatfs_port.c +++ b/esp8266/fatfs_port.c @@ -33,7 +33,7 @@ DWORD get_fattime(void) { // TODO: Optimize division (there's no HW division support on ESP8266, // so it's expensive). - uint32_t secs = (uint32_t)(pyb_rtc_get_us_since_2000() / 1000000); + uint32_t secs = (uint32_t)(esp_clk_get_us_since_2000() / 1000000); timeutils_struct_time_t tm; timeutils_seconds_since_2000_to_struct_time(secs, &tm); diff --git a/esp8266/machine_rtc.c b/esp8266/machine_rtc.c index 54eeea6f6e1ba..5df25f074f9db 100644 --- a/esp8266/machine_rtc.c +++ b/esp8266/machine_rtc.c @@ -39,12 +39,15 @@ typedef struct _pyb_rtc_obj_t { } pyb_rtc_obj_t; #define MEM_MAGIC 0x75507921 -#define MEM_DELTA_ADDR 64 -#define MEM_CAL_ADDR (MEM_DELTA_ADDR + 2) -#define MEM_USER_MAGIC_ADDR (MEM_CAL_ADDR + 1) +#define MEM_RTC_BASE 64 +#define MEM_DELTA_ADDR (MEM_RTC_BASE + 0) +#define MEM_CLKOFS_ADDR (MEM_DELTA_ADDR + 2) +#define MEM_CAL_ADDR (MEM_CLKOFS_ADDR + 2) +#define MEM_CLKREF_ADDR (MEM_CAL_ADDR + 1) +#define MEM_USER_MAGIC_ADDR (MEM_CLKREF_ADDR + 1) #define MEM_USER_LEN_ADDR (MEM_USER_MAGIC_ADDR + 1) #define MEM_USER_DATA_ADDR (MEM_USER_LEN_ADDR + 1) -#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_DELTA_ADDR) * 4) +#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_RTC_BASE) * 4) // singleton RTC object STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}}; @@ -55,36 +58,36 @@ uint64_t pyb_rtc_alarm0_expiry; // in microseconds // RTC overflow checking STATIC uint32_t rtc_last_ticks; +// Clock overflow checking +STATIC uint32_t clk_last_ticks; + +void esp_clk_set_us_since_2000(uint64_t nowus) { + // Get the current clock tick + clk_last_ticks = system_get_time(); + // Set current time as base for future calculations + system_rtc_mem_write(MEM_CLKOFS_ADDR, &nowus, sizeof(nowus)); + system_rtc_mem_write(MEM_CLKREF_ADDR, &clk_last_ticks, sizeof(clk_last_ticks)); +}; -void mp_hal_rtc_init(void) { - uint32_t magic; +uint64_t esp_clk_get_us_since_2000() { + uint64_t offset; + uint32_t clk_ticks; - system_rtc_mem_read(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); - if (magic != MEM_MAGIC) { - magic = MEM_MAGIC; - system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); - uint32_t cal = system_rtc_clock_cali_proc(); - int64_t delta = 0; - system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal)); - system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); - uint32_t len = 0; - system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len)); - } - // system_get_rtc_time() is always 0 after reset/deepsleep - rtc_last_ticks = system_get_rtc_time(); + system_rtc_mem_read(MEM_CLKOFS_ADDR, &offset, sizeof(offset)); + clk_ticks = system_get_time(); - // reset ALARM0 state - pyb_rtc_alarm0_wake = 0; - pyb_rtc_alarm0_expiry = 0; -} - -STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { - // check arguments - mp_arg_check_num(n_args, n_kw, 0, 0, false); - - // return constant object - return (mp_obj_t)&pyb_rtc_obj; -} + int64_t newoffset = offset; + if (clk_ticks >= clk_last_ticks) { + newoffset+= clk_ticks-clk_last_ticks; + } else { + // If overflow happened, assume 1 wrap-around and persist info for the new cycle + newoffset+= clk_ticks+~clk_last_ticks+1; + clk_last_ticks = clk_ticks; + system_rtc_mem_write(MEM_CLKOFS_ADDR, &newoffset, sizeof(newoffset)); + system_rtc_mem_write(MEM_CLKREF_ADDR, &clk_last_ticks, sizeof(clk_last_ticks)); + } + return newoffset; +}; void pyb_rtc_set_us_since_2000(uint64_t nowus) { uint32_t cal = system_rtc_clock_cali_proc(); @@ -120,7 +123,38 @@ uint64_t pyb_rtc_get_us_since_2000() { return (((uint64_t)rtc_ticks * cal) >> 12) + delta; }; +void mp_hal_rtc_init(void) { + uint32_t magic; + + system_rtc_mem_read(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); + if (magic != MEM_MAGIC) { + // Reset clock to 2000-01-01 00:00:00 AM + esp_clk_set_us_since_2000(0); + pyb_rtc_set_us_since_2000(0); + magic = MEM_MAGIC; + system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); + uint32_t len = 0; + system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len)); + } else { + // Use rtc clock's data to reinitialize system clock + esp_clk_set_us_since_2000(pyb_rtc_get_us_since_2000()); + } + + // reset ALARM0 state + pyb_rtc_alarm0_wake = 0; + pyb_rtc_alarm0_expiry = 0; +} + +STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return (mp_obj_t)&pyb_rtc_obj; +} + void rtc_prepare_deepsleep(uint64_t sleep_us) { + // RTC time will reset at wake up. Let's be preared for this. // RTC time will reset at wake up. Let's be preared for this. int64_t delta = pyb_rtc_get_us_since_2000() + sleep_us; system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); @@ -151,14 +185,15 @@ STATIC mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { mp_obj_t *items; mp_obj_get_array_fixed_n(args[1], 8, &items); - pyb_rtc_set_us_since_2000( - ((uint64_t)timeutils_seconds_since_2000( - mp_obj_get_int(items[0]), - mp_obj_get_int(items[1]), - mp_obj_get_int(items[2]), - mp_obj_get_int(items[4]), - mp_obj_get_int(items[5]), - mp_obj_get_int(items[6])) * 1000 + mp_obj_get_int(items[7])) * 1000); + uint64_t arg_us = ((uint64_t)timeutils_seconds_since_2000( + mp_obj_get_int(items[0]), + mp_obj_get_int(items[1]), + mp_obj_get_int(items[2]), + mp_obj_get_int(items[4]), + mp_obj_get_int(items[5]), + mp_obj_get_int(items[6])) * 1000 + mp_obj_get_int(items[7])) * 1000; + pyb_rtc_set_us_since_2000(arg_us); + esp_clk_set_us_since_2000(arg_us); return mp_const_none; } diff --git a/esp8266/modmachine.h b/esp8266/modmachine.h index 414aaa85b0a14..0396ebdaa5af7 100644 --- a/esp8266/modmachine.h +++ b/esp8266/modmachine.h @@ -34,6 +34,9 @@ void pin_set(uint pin, int value); extern uint32_t pyb_rtc_alarm0_wake; extern uint64_t pyb_rtc_alarm0_expiry; +void esp_clk_set_us_since_2000(uint64_t nowus); +uint64_t esp_clk_get_us_since_2000(); + void pyb_rtc_set_us_since_2000(uint64_t nowus); uint64_t pyb_rtc_get_us_since_2000(); void rtc_prepare_deepsleep(uint64_t sleep_us); diff --git a/esp8266/modutime.c b/esp8266/modutime.c index 2adb6c563b378..e457e574f18ce 100644 --- a/esp8266/modutime.c +++ b/esp8266/modutime.c @@ -60,7 +60,7 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) { timeutils_struct_time_t tm; mp_int_t seconds; if (n_args == 0 || args[0] == mp_const_none) { - seconds = pyb_rtc_get_us_since_2000() / 1000 / 1000; + seconds = esp_clk_get_us_since_2000() / 1000 / 1000; } else { seconds = mp_obj_get_int(args[0]); } @@ -103,7 +103,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); /// Returns the number of seconds, as an integer, since 1/1/2000. STATIC mp_obj_t time_time(void) { // get date and time - return mp_obj_new_int(pyb_rtc_get_us_since_2000() / 1000 / 1000); + return mp_obj_new_int(esp_clk_get_us_since_2000() / 1000 / 1000); } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); From 70374423f759c0a97ce156d0558bc3624a378e0f Mon Sep 17 00:00:00 2001 From: Zhenyu Wu Date: Mon, 26 Dec 2016 22:38:43 -0500 Subject: [PATCH 3/4] Removed system clock's RTC memory slot (not necessary); Persist and restore RTC ticks from RTC memory at initialization, keeps time across machine.reset --- esp8266/machine_rtc.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/esp8266/machine_rtc.c b/esp8266/machine_rtc.c index 0631c6f392353..9a4d34c39c83f 100644 --- a/esp8266/machine_rtc.c +++ b/esp8266/machine_rtc.c @@ -41,10 +41,8 @@ typedef struct _pyb_rtc_obj_t { #define MEM_MAGIC 0x75507921 #define MEM_RTC_BASE 64 #define MEM_RTCOFS_ADDR (MEM_RTC_BASE + 0) -#define MEM_CLKOFS_ADDR (MEM_RTCOFS_ADDR + 2) -#define MEM_RTCREF_ADDR (MEM_CLKOFS_ADDR + 2) -#define MEM_CLKREF_ADDR (MEM_RTCREF_ADDR + 1) -#define MEM_USER_MAGIC_ADDR (MEM_CLKREF_ADDR + 1) +#define MEM_RTCREF_ADDR (MEM_RTCOFS_ADDR + 2) +#define MEM_USER_MAGIC_ADDR (MEM_RTCREF_ADDR + 1) #define MEM_USER_LEN_ADDR (MEM_USER_MAGIC_ADDR + 1) #define MEM_USER_DATA_ADDR (MEM_USER_LEN_ADDR + 1) #define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_RTC_BASE) * 4) @@ -61,33 +59,31 @@ STATIC uint32_t rtc_last_ticks; STATIC uint32_t rtc_last_cal; // Clock overflow checking STATIC uint32_t clk_last_ticks; +STATIC uint64_t clk_offset; void esp_clk_set_us_since_2000(uint64_t nowus) { // Get the current clock tick clk_last_ticks = system_get_time(); // Set current time as base for future calculations - system_rtc_mem_write(MEM_CLKOFS_ADDR, &nowus, sizeof(nowus)); - system_rtc_mem_write(MEM_CLKREF_ADDR, &clk_last_ticks, sizeof(clk_last_ticks)); + clk_offset = nowus; }; uint64_t esp_clk_get_us_since_2000() { uint64_t offset; uint32_t clk_ticks; - system_rtc_mem_read(MEM_CLKOFS_ADDR, &offset, sizeof(offset)); + offset = clk_offset; clk_ticks = system_get_time(); - int64_t newoffset = offset; if (clk_ticks >= clk_last_ticks) { - newoffset+= clk_ticks-clk_last_ticks; + offset+= clk_ticks-clk_last_ticks; } else { // If overflow happened, assume 1 wrap-around and persist info for the new cycle - newoffset+= clk_ticks+~clk_last_ticks+1; + offset+= clk_ticks+~clk_last_ticks+1; clk_last_ticks = clk_ticks; - system_rtc_mem_write(MEM_CLKOFS_ADDR, &newoffset, sizeof(newoffset)); - system_rtc_mem_write(MEM_CLKREF_ADDR, &clk_last_ticks, sizeof(clk_last_ticks)); + clk_offset = offset; } - return newoffset; + return offset; }; void pyb_rtc_set_us_since_2000(uint64_t nowus) { @@ -106,20 +102,20 @@ uint64_t pyb_rtc_get_us_since_2000() { rtc_ticks = system_get_rtc_time(); rtc_last_cal = system_rtc_clock_cali_proc(); - int64_t newoffset = offset; - int64_t newdelta = rtc_ticks; + int64_t delta = rtc_ticks; if (rtc_ticks >= rtc_last_ticks) { - newdelta-= rtc_last_ticks; + delta-= rtc_last_ticks; } else { // If overflow happened, assume 1 wrap-around and persist info for the new cycle - newdelta+= ~rtc_last_ticks+1; - system_rtc_mem_write(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks)); + delta+= ~rtc_last_ticks+1; } - // Since RTC unit is volatile, we have to rebase every time - newoffset+= (newdelta*rtc_last_cal)>>12; + offset+= (delta*rtc_last_cal)>>12; + // Since RTC cal is volatile, we have to rebase every time rtc_last_ticks = rtc_ticks; - system_rtc_mem_write(MEM_RTCOFS_ADDR, &newoffset, sizeof(newoffset)); - return newoffset; + // Since RTC enjoys persistence across (some) reboots, we persist the rebase to enjoy the benefit + system_rtc_mem_write(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks)); + system_rtc_mem_write(MEM_RTCOFS_ADDR, &offset, sizeof(offset)); + return offset; }; void mp_hal_rtc_init(void) { @@ -135,6 +131,8 @@ void mp_hal_rtc_init(void) { uint32_t len = 0; system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len)); } else { + // Load back the RTC cycle base + system_rtc_mem_read(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks)); // Use rtc clock's data to reinitialize system clock esp_clk_set_us_since_2000(pyb_rtc_get_us_since_2000()); } From 8bcc8ebc39b1e23b8d2c3a35bf9e7229780a70d5 Mon Sep 17 00:00:00 2001 From: Zhenyu Wu Date: Mon, 26 Dec 2016 23:00:04 -0500 Subject: [PATCH 4/4] Handle hard reset differently from other reset when reinitializing RTC ticks. --- esp8266/machine_rtc.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/esp8266/machine_rtc.c b/esp8266/machine_rtc.c index 9a4d34c39c83f..f64bdd90c8037 100644 --- a/esp8266/machine_rtc.c +++ b/esp8266/machine_rtc.c @@ -131,8 +131,18 @@ void mp_hal_rtc_init(void) { uint32_t len = 0; system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len)); } else { - // Load back the RTC cycle base - system_rtc_mem_read(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks)); + // Check reset cause to determine what to do with stored RTC ticks + struct rst_info *rtc_info = system_get_rst_info(); + if (rtc_info->reason == REASON_EXT_SYS_RST) { + // External reset, RTC ticks reset to zero + // Note: PowerOn and ChipEn also cause ticks to reset but since they also randomize entire RTC memory, + // it is assumed the control flow never reach here for those two cases + rtc_last_ticks = 0; + system_rtc_mem_write(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks)); + } else { + // Load back the RTC cycle base + system_rtc_mem_read(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks)); + } // Use rtc clock's data to reinitialize system clock esp_clk_set_us_since_2000(pyb_rtc_get_us_since_2000()); }