Browse Source

Add tracking and control of the rate error in the clock crystal. (#1697)

* Improve RTC timekeeping -- includes clock rate tracking
* Improved division by 1M
* Fix crash in sntp
* Disable RTC debug
* Get the offset correct
* Add comments on where the mysterious numbers came from
* Fix a crash with auto repeat mode and errors on repeat
Philip Gladstone 6 years ago
parent
commit
d93465cd86

+ 1 - 0
app/include/rtc/rtctime.h

@@ -62,6 +62,7 @@ struct rtc_tm{
 
 void TEXT_SECTION_ATTR rtctime_early_startup (void);
 void rtctime_late_startup (void);
+void rtctime_adjust_rate (int rate);
 void rtctime_gettimeofday (struct rtc_timeval *tv);
 void rtctime_settimeofday (const struct rtc_timeval *tv);
 bool rtctime_have_time (void);

+ 222 - 72
app/include/rtc/rtctime_internal.h

@@ -32,6 +32,11 @@
  * @author Johny Mattsson <jmattsson@dius.com.au>
  */
 
+/*
+ * It is vital that this file is only included once in the entire
+ * system. 
+ */
+
 #ifndef _RTCTIME_INTERNAL_H_
 #define _RTCTIME_INTERNAL_H_
 
@@ -181,6 +186,17 @@
 #define CPU_DEFAULT_MHZ   80
 #define CPU_BOOTUP_MHZ    52
 
+#ifdef RTC_DEBUG_ENABLED
+#define RTC_DBG(...)         do { if (rtc_dbg_enabled == 'R') { dbg_printf(__VA_ARGS__); } } while (0)
+static bool rtc_dbg_enabled;
+#define RTC_DBG_ENABLED()   rtc_dbg_enabled = 'R'
+#define RTC_DBG_NOT_ENABLED()   rtc_dbg_enabled = 0
+#else
+#define RTC_DBG(...)
+#define RTC_DBG_ENABLED()
+#define RTC_DBG_NOT_ENABLED()
+#endif
+
 // RTCTIME storage
 #define RTC_TIME_MAGIC_POS       (RTC_TIME_BASE+0)
 #define RTC_CYCLEOFFSETL_POS     (RTC_TIME_BASE+1)
@@ -190,8 +206,22 @@
 #define RTC_CALIBRATION_POS      (RTC_TIME_BASE+5)
 #define RTC_SLEEPTOTALUS_POS     (RTC_TIME_BASE+6)
 #define RTC_SLEEPTOTALCYCLES_POS (RTC_TIME_BASE+7)
-#define RTC_TODOFFSETUS_POS      (RTC_TIME_BASE+8)
-#define RTC_LASTTODUS_POS        (RTC_TIME_BASE+9)
+//#define RTC_TODOFFSETUS_POS      (RTC_TIME_BASE+8)
+//#define RTC_LASTTODUS_POS        (RTC_TIME_BASE+9)
+#define RTC_USRATE_POS		 (RTC_TIME_BASE+8)
+
+static uint32_t rtc_time_magic;
+static uint64_t rtc_cycleoffset;
+static uint32_t rtc_lastsourceval;
+static uint32_t rtc_sourcecycleunits;
+static uint32_t rtc_calibration;
+static uint32_t rtc_sleeptotalus;
+static uint32_t rtc_sleeptotalcycles;
+static uint64_t rtc_usatlastrate;
+static uint64_t rtc_rateadjustedus;
+static uint32_t rtc_todoffsetus;
+static uint32_t rtc_lasttodus;
+static uint32_t rtc_usrate;
 
 
 struct rtc_timeval
@@ -200,13 +230,79 @@ struct rtc_timeval
   uint32_t tv_usec;
 };
 
-static inline uint64_t rtc_time_get_now_us_adjusted();
+static void bbram_load() {
+  rtc_time_magic = rtc_mem_read(RTC_TIME_MAGIC_POS);
+  rtc_cycleoffset = rtc_mem_read64(RTC_CYCLEOFFSETL_POS);
+  rtc_lastsourceval = rtc_mem_read(RTC_LASTSOURCEVAL_POS);
+  rtc_sourcecycleunits = rtc_mem_read(RTC_SOURCECYCLEUNITS_POS);
+  rtc_calibration = rtc_mem_read(RTC_CALIBRATION_POS);
+  rtc_sleeptotalus = rtc_mem_read(RTC_SLEEPTOTALUS_POS);
+  rtc_sleeptotalcycles = rtc_mem_read(RTC_SLEEPTOTALCYCLES_POS);
+  rtc_usrate = rtc_mem_read(RTC_USRATE_POS);
+}
 
-static inline uint32_t rtc_time_get_magic(void)
-{
-  return rtc_mem_read(RTC_TIME_MAGIC_POS);
+static void bbram_save() {
+  RTC_DBG("bbram_save\n");
+  rtc_mem_write(RTC_TIME_MAGIC_POS       , rtc_time_magic);
+  rtc_mem_write64(RTC_CYCLEOFFSETL_POS   , rtc_cycleoffset);
+  rtc_mem_write(RTC_LASTSOURCEVAL_POS    , rtc_lastsourceval);
+  rtc_mem_write(RTC_SOURCECYCLEUNITS_POS , rtc_sourcecycleunits);
+  rtc_mem_write(RTC_CALIBRATION_POS      , rtc_calibration);
+  rtc_mem_write(RTC_SLEEPTOTALUS_POS     , rtc_sleeptotalus);
+  rtc_mem_write(RTC_SLEEPTOTALCYCLES_POS , rtc_sleeptotalcycles);
+  rtc_mem_write(RTC_USRATE_POS		 , rtc_usrate);
 }
 
+static inline uint64_t div2080(uint64_t n) {
+  n = n >> 5;
+  uint64_t t = n >> 7;
+
+  uint64_t q = t + (t >> 1) + (t >> 2);
+
+  q += q >> 3;
+  q += q >> 12;
+  q += q >> 24;
+  q += q >> 48;
+
+  uint32_t r = (uint32_t) n - (uint32_t) q * 65;
+
+  uint32_t off = (r - (r >> 6)) >> 6;
+
+  q = q + off;
+
+  return q;
+}
+
+static uint32_t div1m(uint32_t *rem, unsigned long long n) {
+  // 0   -> 0002000000000000 sub
+  // 0 >> 5 - 0 >> 19 + [-1]  -> 00020fffc0000000 add
+  // 0 >> 9 - 0 >> 6 + [-1]  -> 000208ffc0000000 add
+  // 2 >> 12 - 2 >> 23   -> 000000208bea0080 sub
+
+  uint64_t q1 = (n >> 5) - (n >> 19) + n;
+  uint64_t q2 = q1 + (n >> 9) - (n >> 6);
+  uint64_t q3 = (q2 >> 12) - (q2 >> 23);
+
+  uint64_t q = q1 - n + q2 - q3;
+
+  q = q >> 20;
+
+  uint32_t r = (uint32_t) n - (uint32_t) q * 1000000;
+
+  if (r >= 1000000) {
+    r -= 1000000;
+    q++;
+  }
+
+  *rem = r;
+
+  return q;
+}
+
+static inline uint64_t rtc_time_get_now_us_adjusted();
+
+#define rtc_time_get_magic()    rtc_time_magic
+
 static inline bool rtc_time_check_sleep_magic(void)
 {
   uint32_t magic=rtc_time_get_magic();
@@ -225,9 +321,11 @@ static inline bool rtc_time_check_magic(void)
   return (magic==RTC_TIME_MAGIC_FRC2 || magic==RTC_TIME_MAGIC_CCOUNT || magic==RTC_TIME_MAGIC_SLEEP);
 }
 
-static inline void rtc_time_set_magic(uint32_t new_magic)
+static void rtc_time_set_magic(uint32_t new_magic)
 {
-  rtc_mem_write(RTC_TIME_MAGIC_POS,new_magic);
+  RTC_DBG("Set magic to %08x\n", new_magic);
+  rtc_time_magic = new_magic;
+  bbram_save();
 }
 
 static inline void rtc_time_set_sleep_magic(void)
@@ -249,7 +347,7 @@ static inline void rtc_time_set_frc2_magic(void)
 
 static inline void rtc_time_unset_magic(void)
 {
-  rtc_mem_write(RTC_TIME_MAGIC_POS,0);
+  rtc_time_set_magic(0);
 }
 
 static inline uint32_t rtc_time_read_raw(void)
@@ -281,16 +379,16 @@ static inline uint64_t rtc_time_source_offset(void)
   case RTC_TIME_MAGIC_FRC2:   raw=rtc_time_read_raw_frc2();   break;
   default: return 0; // We are not in a position to offer time
   }
-  uint32_t multiplier=rtc_mem_read(RTC_SOURCECYCLEUNITS_POS);
-  uint32_t previous=rtc_mem_read(RTC_LASTSOURCEVAL_POS);
+  uint32_t multiplier = rtc_sourcecycleunits;
+  uint32_t previous = rtc_lastsourceval;
   if (raw<previous)
   { // We had a rollover.
     uint64_t to_add=(1ULL<<32)*multiplier;
-    uint64_t base=rtc_mem_read64(RTC_CYCLEOFFSETL_POS);
+    uint64_t base = rtc_cycleoffset;
     if (base)
-      rtc_mem_write64(RTC_CYCLEOFFSETL_POS,base+to_add);
+      rtc_cycleoffset = base + to_add;
   }
-  rtc_mem_write(RTC_LASTSOURCEVAL_POS,raw);
+  rtc_lastsourceval = raw;
   return ((uint64_t)raw)*multiplier;
 }
 
@@ -298,7 +396,7 @@ static inline uint64_t rtc_time_unix_unitcycles(void)
 {
   // Note: The order of these two must be maintained, as the first call might change the outcome of the second
   uint64_t offset=rtc_time_source_offset();
-  uint64_t base=rtc_mem_read64(RTC_CYCLEOFFSETL_POS);
+  uint64_t base = rtc_cycleoffset;
 
   if (!base)
     return 0; // No known time
@@ -308,17 +406,22 @@ static inline uint64_t rtc_time_unix_unitcycles(void)
 
 static inline uint64_t rtc_time_unix_us(void)
 {
+#if UNITCYCLE_MHZ == 2080
+  return div2080(rtc_time_unix_unitcycles());
+#else
+#error UNITCYCLE_MHZ has an odd value
   return rtc_time_unix_unitcycles()/UNITCYCLE_MHZ;
+#endif
 }
 
 static inline void rtc_time_register_time_reached(uint32_t s, uint32_t us)
 {
-  rtc_mem_write(RTC_LASTTODUS_POS,us);
+  rtc_lasttodus = us;
 }
 
 static inline uint32_t rtc_time_us_since_time_reached(uint32_t s, uint32_t us)
 {
-  uint32_t lastus=rtc_mem_read(RTC_LASTTODUS_POS);
+  uint32_t lastus=rtc_lasttodus;
   if (us<lastus)
     us+=1000000;
   return us-lastus;
@@ -334,14 +437,14 @@ static inline bool rtc_time_calibration_is_sane(uint32_t cali)
 
 static inline uint32_t rtc_time_get_calibration(void)
 {
-  uint32_t cal=rtc_time_check_magic()?rtc_mem_read(RTC_CALIBRATION_POS):0;
+  uint32_t cal=rtc_time_check_magic()?rtc_calibration:0;
   if (!cal)
   {
     // Make a first guess, most likely to be rather bad, but better then nothing.
 #ifndef BOOTLOADER_CODE // This will pull in way too much of the system for the bootloader to handle.
     ets_delay_us(200);
     cal=system_rtc_clock_cali_proc();
-    rtc_mem_write(RTC_CALIBRATION_POS,cal);
+    rtc_calibration = cal;
 #else
     cal=6<<12;
 #endif
@@ -351,7 +454,7 @@ static inline uint32_t rtc_time_get_calibration(void)
 
 static inline void rtc_time_invalidate_calibration(void)
 {
-  rtc_mem_write(RTC_CALIBRATION_POS,0);
+  rtc_calibration = 0;
 }
 
 static inline uint64_t rtc_time_us_to_ticks(uint64_t us)
@@ -374,7 +477,7 @@ static inline uint64_t rtc_time_get_now_us_adjusted(void)
   uint64_t raw=rtc_time_get_now_us_raw();
   if (!raw)
     return 0;
-  return raw+rtc_mem_read(RTC_TODOFFSETUS_POS);
+  return raw+rtc_todoffsetus;
 }
 
 
@@ -383,16 +486,16 @@ static inline void rtc_time_add_sleep_tracking(uint32_t us, uint32_t cycles)
   if (rtc_time_check_magic())
   {
     // us is the one that will grow faster...
-    uint32_t us_before=rtc_mem_read(RTC_SLEEPTOTALUS_POS);
+    uint32_t us_before=rtc_sleeptotalus;
     uint32_t us_after=us_before+us;
-    uint32_t cycles_after=rtc_mem_read(RTC_SLEEPTOTALCYCLES_POS)+cycles;
+    uint32_t cycles_after=rtc_sleeptotalcycles+cycles;
 
     if (us_after<us_before) // Give up if it would cause an overflow
     {
       us_after=cycles_after=0xffffffff;
     }
-    rtc_mem_write(RTC_SLEEPTOTALUS_POS,    us_after);
-    rtc_mem_write(RTC_SLEEPTOTALCYCLES_POS,cycles_after);
+    rtc_sleeptotalus = us_after;
+    rtc_sleeptotalcycles = cycles_after;
   }
 }
 
@@ -402,6 +505,8 @@ static void rtc_time_enter_deep_sleep_us(uint32_t us)
 {
   if (rtc_time_check_wake_magic())
     rtc_time_set_sleep_magic();
+  else 
+    bbram_save();
 
   rtc_reg_write(0,0);
   rtc_reg_write(0,rtc_reg_read(0)&0xffffbfff);
@@ -442,22 +547,23 @@ static void rtc_time_enter_deep_sleep_us(uint32_t us)
   rtc_time_enter_deep_sleep_final();
 }
 
-static inline void rtc_time_deep_sleep_us(uint32_t us)
+static void rtc_time_deep_sleep_us(uint32_t us)
 {
   if (rtc_time_check_magic())
   {
-    uint32_t to_adjust=rtc_mem_read(RTC_TODOFFSETUS_POS);
+    uint32_t to_adjust=rtc_todoffsetus;
     if (to_adjust)
     {
       us+=to_adjust;
-      rtc_mem_write(RTC_TODOFFSETUS_POS,0);
+      rtc_todoffsetus = 0;
     }
     uint64_t now=rtc_time_get_now_us_raw(); // Now the same as _adjusted()
     if (now)
     { // Need to maintain the clock first. When we wake up, counter will be 0
       uint64_t wakeup=now+us;
       uint64_t wakeup_cycles=wakeup*UNITCYCLE_MHZ;
-      rtc_mem_write64(RTC_CYCLEOFFSETL_POS,wakeup_cycles);
+      // Probly should factor in the rate here TODO
+      rtc_cycleoffset = wakeup_cycles;
     }
   }
   rtc_time_enter_deep_sleep_us(us);
@@ -476,27 +582,32 @@ static inline void rtc_time_deep_sleep_until_aligned(uint32_t align, uint32_t mi
   rtc_time_deep_sleep_us(then-now);
 }
 
-static inline void rtc_time_reset(bool clear_cali)
+static void rtc_time_reset(bool clear_cali)
 {
-  rtc_mem_write64(RTC_CYCLEOFFSETL_POS,0);
-  rtc_mem_write(RTC_SLEEPTOTALUS_POS,0);
-  rtc_mem_write(RTC_SLEEPTOTALCYCLES_POS,0);
-  rtc_mem_write(RTC_TODOFFSETUS_POS,0);
-  rtc_mem_write(RTC_LASTTODUS_POS,0);
-  rtc_mem_write(RTC_SOURCECYCLEUNITS_POS,0);
-  rtc_mem_write(RTC_LASTSOURCEVAL_POS,0);
+  rtc_cycleoffset = 0;
+  rtc_sleeptotalus = 0;
+  rtc_sleeptotalcycles = 0;
+  rtc_todoffsetus = 0;
+  rtc_lasttodus = 0;
+  rtc_sourcecycleunits = 0;
+  rtc_lastsourceval = 0;
+  rtc_usatlastrate = 0;
+  rtc_rateadjustedus = 0;
+  rtc_usrate = 0;
 
   if (clear_cali)
-    rtc_mem_write(RTC_CALIBRATION_POS,0);
+    rtc_calibration = 0;
+
+  bbram_save();
 }
 
 static inline bool rtc_time_have_time(void)
 {
-  return (rtc_time_check_magic() && rtc_mem_read64(RTC_CYCLEOFFSETL_POS)!=0);
+  return (rtc_time_check_magic() && rtc_cycleoffset!=0);
 }
 
 
-static inline void rtc_time_select_frc2_source()
+static void rtc_time_select_frc2_source()
 {
   // FRC2 always runs at 1/256th of the default 80MHz clock, even if the actual clock is different
   uint32_t new_multiplier=(256*UNITCYCLE_MHZ+CPU_DEFAULT_MHZ/2)/CPU_DEFAULT_MHZ;
@@ -515,14 +626,14 @@ static inline void rtc_time_select_frc2_source()
   if (rtc_time_have_time())
   {
     uint64_t offset=(uint64_t)after*new_multiplier;
-    rtc_mem_write64(RTC_CYCLEOFFSETL_POS,now-offset);
-    rtc_mem_write(RTC_LASTSOURCEVAL_POS,after);
+    rtc_cycleoffset = now-offset;
+    rtc_lastsourceval = after;
   }
-  rtc_mem_write(RTC_SOURCECYCLEUNITS_POS,new_multiplier);
-  rtc_mem_write(RTC_TIME_MAGIC_POS,RTC_TIME_MAGIC_FRC2);
+  rtc_sourcecycleunits = new_multiplier;
+  rtc_time_set_magic(RTC_TIME_MAGIC_FRC2);
 }
 
-static inline void rtc_time_select_ccount_source(uint32_t mhz, bool first)
+static void rtc_time_select_ccount_source(uint32_t mhz, bool first)
 {
   uint32_t new_multiplier=(UNITCYCLE_MHZ+mhz/2)/mhz;
 
@@ -532,9 +643,9 @@ static inline void rtc_time_select_ccount_source(uint32_t mhz, bool first)
 
   if (first)
   { // The ccounter has been running at this rate since startup, and the offset is set accordingly
-    rtc_mem_write(RTC_LASTSOURCEVAL_POS,0);
-    rtc_mem_write(RTC_SOURCECYCLEUNITS_POS,new_multiplier);
-    rtc_mem_write(RTC_TIME_MAGIC_POS,RTC_TIME_MAGIC_CCOUNT);
+    rtc_lastsourceval = 0;
+    rtc_sourcecycleunits = new_multiplier;
+    rtc_time_set_magic(RTC_TIME_MAGIC_CCOUNT);
     return;
   }
 
@@ -552,11 +663,11 @@ static inline void rtc_time_select_ccount_source(uint32_t mhz, bool first)
   if (rtc_time_have_time())
   {
     uint64_t offset=(uint64_t)after*new_multiplier;
-    rtc_mem_write64(RTC_CYCLEOFFSETL_POS,now-offset);
-    rtc_mem_write(RTC_LASTSOURCEVAL_POS,after);
+    rtc_cycleoffset = now-offset;
+    rtc_lastsourceval = after;
   }
-  rtc_mem_write(RTC_SOURCECYCLEUNITS_POS,new_multiplier);
-  rtc_mem_write(RTC_TIME_MAGIC_POS,RTC_TIME_MAGIC_CCOUNT);
+  rtc_sourcecycleunits = new_multiplier;
+  rtc_time_set_magic(RTC_TIME_MAGIC_CCOUNT);
 }
 
 
@@ -573,12 +684,9 @@ static inline void rtc_time_switch_to_system_clock(void)
     rtc_time_select_frc2_source();
 }
 
-static inline void rtc_time_tmrfn(void* arg)
-{
-  rtc_time_source_offset();
-}
+static inline void rtc_time_tmrfn(void* arg);
 
-static inline void rtc_time_install_timer(void)
+static void rtc_time_install_timer(void)
 {
   static ETSTimer tmr;
 
@@ -618,8 +726,10 @@ static inline void rtc_time_install_wrap_handler(void)
 
 // This switches from MAGIC_SLEEP to MAGIC_CCOUNT, with ccount running at bootup frequency (i.e. 52MHz).
 // To be called as early as possible, potententially as the first thing in an overridden entry point.
-static inline void rtc_time_register_bootup(void)
+static void rtc_time_register_bootup(void)
 {
+  RTC_DBG_NOT_ENABLED();
+  bbram_load();
   uint32_t reset_reason=rtc_get_reset_reason();
 #ifndef BOOTLOADER_CODE
   static const bool erase_calibration=true;
@@ -634,6 +744,9 @@ static inline void rtc_time_register_bootup(void)
     if (reset_reason!=2)  // This was *not* a proper wakeup from a deep sleep. All our time keeping is f*cked!
       rtc_time_reset(erase_calibration); // Possibly keep the calibration, it should still be good
     rtc_time_select_ccount_source(CPU_BOOTUP_MHZ,true);
+    rtc_rateadjustedus = rtc_usatlastrate = rtc_time_get_now_us_adjusted();
+    rtc_todoffsetus = 0;
+    RTC_DBG_ENABLED();
     return;
   }
 
@@ -642,6 +755,7 @@ static inline void rtc_time_register_bootup(void)
     // We did not go to sleep properly. All our time keeping is f*cked!
     rtc_time_reset(erase_calibration); // Possibly keep the calibration, it should still be good
   }
+  RTC_DBG_ENABLED();
 }
 
 // Call this from the nodemcu entry point, i.e. just before we switch from 52MHz to 80MHz
@@ -664,12 +778,44 @@ static inline void rtc_time_prepare(void)
   rtc_time_select_frc2_source();
 }
 
+static uint64_t rtc_time_adjust_us_by_rate(uint64_t us, int force) {
+  uint64_t usoff = us - rtc_usatlastrate; 
+  uint64_t usadj = (usoff * ((1ull << 32) + (int) rtc_usrate)) >> 32;
+  usadj = usadj + rtc_rateadjustedus;
+
+  if (usoff > 1000000000 || force) {
+    rtc_usatlastrate = us;
+    rtc_rateadjustedus = usadj;
+  }
+
+  return usadj;
+}
+
+static inline void rtc_time_set_rate(int32_t rate) {
+  uint64_t now=rtc_time_get_now_us_adjusted();
+  rtc_time_adjust_us_by_rate(now, 1);
+  rtc_usrate = rate;
+}
+
+static inline int32_t rtc_time_get_rate() {
+  return rtc_usrate;
+}
+
+static inline void rtc_time_tmrfn(void* arg)
+{
+  uint64_t now=rtc_time_get_now_us_adjusted();
+  rtc_time_adjust_us_by_rate(now, 0);
+  rtc_time_source_offset();
+}
+
+
 static inline void rtc_time_gettimeofday(struct rtc_timeval* tv)
 {
   uint64_t now=rtc_time_get_now_us_adjusted();
-  uint32_t sec=now/1000000;
-  uint32_t usec=now%1000000;
-  uint32_t to_adjust=rtc_mem_read(RTC_TODOFFSETUS_POS);
+  now = rtc_time_adjust_us_by_rate(now, 0);
+  uint32_t usec;
+  uint32_t sec = div1m(&usec, now);
+  uint32_t to_adjust=rtc_todoffsetus;
   if (to_adjust)
   {
     uint32_t us_passed=rtc_time_us_since_time_reached(sec,usec);
@@ -680,9 +826,8 @@ static inline void rtc_time_gettimeofday(struct rtc_timeval* tv)
         adjust=to_adjust;
       to_adjust-=adjust;
       now-=adjust;
-      now/1000000;
-      now%1000000;
-      rtc_mem_write(RTC_TODOFFSETUS_POS,to_adjust);
+      sec = div1m(&usec, now);
+      rtc_todoffsetus = to_adjust;
     }
   }
   tv->tv_sec=sec;
@@ -690,23 +835,24 @@ static inline void rtc_time_gettimeofday(struct rtc_timeval* tv)
   rtc_time_register_time_reached(sec,usec);
 }
 
-static inline void rtc_time_settimeofday(const struct rtc_timeval* tv)
+static void rtc_time_settimeofday(const struct rtc_timeval* tv)
 {
   if (!rtc_time_check_magic())
     return;
 
 
-  uint32_t sleep_us=rtc_mem_read(RTC_SLEEPTOTALUS_POS);
-  uint32_t sleep_cycles=rtc_mem_read(RTC_SLEEPTOTALCYCLES_POS);
+  uint32_t sleep_us=rtc_sleeptotalus;
+  uint32_t sleep_cycles=rtc_sleeptotalcycles;
   // At this point, the CPU clock will definitely be at the default rate (nodemcu fully booted)
   uint64_t now_esp_us=rtc_time_get_now_us_adjusted();
+  now_esp_us = rtc_time_adjust_us_by_rate(now_esp_us, 1);
   uint64_t now_ntp_us=((uint64_t)tv->tv_sec)*1000000+tv->tv_usec;
   int64_t  diff_us=now_esp_us-now_ntp_us;
 
   // Store the *actual* time.
   uint64_t target_unitcycles=now_ntp_us*UNITCYCLE_MHZ;
   uint64_t sourcecycles=rtc_time_source_offset();
-  rtc_mem_write64(RTC_CYCLEOFFSETL_POS,target_unitcycles-sourcecycles);
+  rtc_cycleoffset = target_unitcycles-sourcecycles;
 
   // calibrate sleep period based on difference between expected time and actual time
   if (sleep_us>0 && sleep_us<0xffffffff &&
@@ -715,11 +861,15 @@ static inline void rtc_time_settimeofday(const struct rtc_timeval* tv)
     uint64_t actual_sleep_us=sleep_us-diff_us;
     uint32_t cali=(actual_sleep_us<<12)/sleep_cycles;
     if (rtc_time_calibration_is_sane(cali))
-      rtc_mem_write(RTC_CALIBRATION_POS,cali);
+      rtc_calibration = cali;
   }
 
-  rtc_mem_write(RTC_SLEEPTOTALUS_POS,0);
-  rtc_mem_write(RTC_SLEEPTOTALCYCLES_POS,0);
+  rtc_sleeptotalus = 0;
+  rtc_sleeptotalcycles = 0;
+
+  rtc_usatlastrate = now_ntp_us;
+  rtc_rateadjustedus = now_ntp_us;
+  rtc_usrate = 0;
 
   // Deal with time adjustment if necessary
   if (diff_us>0) // Time went backwards. Avoid that....
@@ -730,7 +880,7 @@ static inline void rtc_time_settimeofday(const struct rtc_timeval* tv)
   }
   else
     diff_us=0;
-  rtc_mem_write(RTC_TODOFFSETUS_POS,diff_us);
+  rtc_todoffsetus = diff_us;
 
   uint32_t now_s=now_ntp_us/1000000;
   uint32_t now_us=now_ntp_us%1000000;

+ 12 - 1
app/modules/rtctime.c

@@ -57,6 +57,11 @@ void rtctime_late_startup (void)
   rtc_time_switch_system ();
 }
 
+void rtctime_adjust_rate (int rate)
+{
+  rtc_time_set_rate (rate);
+}
+
 void rtctime_gettimeofday (struct rtc_timeval *tv)
 {
   rtc_time_gettimeofday (tv);
@@ -66,7 +71,9 @@ void rtctime_settimeofday (const struct rtc_timeval *tv)
 {
   if (!rtc_time_check_magic ())
     rtc_time_prepare ();
+  int32_t rate = rtc_time_get_rate();
   rtc_time_settimeofday (tv);
+  rtc_time_set_rate(rate);
 }
 
 bool rtctime_have_time (void)
@@ -131,6 +138,9 @@ static int rtctime_set (lua_State *L)
 
   struct rtc_timeval tv = { sec, usec };
   rtctime_settimeofday (&tv);
+
+  if (lua_isnumber(L, 3))
+    rtc_time_set_rate(lua_tonumber(L, 3));
   return 0;
 }
 
@@ -142,7 +152,8 @@ static int rtctime_get (lua_State *L)
   rtctime_gettimeofday (&tv);
   lua_pushnumber (L, tv.tv_sec);
   lua_pushnumber (L, tv.tv_usec);
-  return 2;
+  lua_pushnumber (L, rtc_time_get_rate());
+  return 3;
 }
 
 static void do_sleep_opt (lua_State *L, int idx)

+ 1 - 1
app/modules/sntp.c

@@ -254,7 +254,7 @@ static void sntp_handle_result(lua_State *L) {
     int64_t f = ((state->best.delta * PLL_A) >> 32) + pll_increment;
     pll_increment += (state->best.delta * PLL_B) >> 32;
     sntp_dbg("f=%d, increment=%d\n", (int32_t) f, (int32_t) pll_increment);
-    //rtctime_adjust_rate((int32_t) f);
+    rtctime_adjust_rate((int32_t) f);
   } else {
     rtctime_settimeofday (&tv);
   }

File diff suppressed because it is too large
+ 1 - 1
docs/en/modules/rtctime.md


Some files were not shown because too many files changed in this diff