To drift forward less than 7s/day (3.5 minutes/month) for ESP32-based repeaters with Power Saving.

This commit is contained in:
Kevin Le committed 2026-05-06 15:07:59 +07:00
1 parent 517d3ed643
commit 3281ea2924
3 files changed
+5 -67

No files matched your search

+1 -1
View File
@@ -155,7 +155,7 @@ void loop() {
board.sleep(1800); // nrf ignores seconds param, sleeps whenever possible
#else
if (the_mesh.millisHasNowPassed(POWERSAVING_FIRSTSLEEP_SECS * 1000)) { // To check if it is time to sleep
board.sleep(1800); // Sleep. Wake up after 30 minutes or when receiving a LoRa packet
board.sleep(30); // Sleep. Wake up after some seconds or when receiving a LoRa packet
}
#endif
}
+1 -1
View File
@@ -246,7 +246,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
} else if (memcmp(command, "clock", 5) == 0) {
uint32_t now = getRTCClock()->getCurrentTime();
DateTime dt = DateTime(now);
sprintf(reply, "%02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
sprintf(reply, "%02d:%02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.second(), dt.day(), dt.month(), dt.year());
} else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds)
uint32_t secs = _atoi(&command[5]);
uint32_t curr = getRTCClock()->getCurrentTime();
+3 -65
View File
@@ -24,7 +24,7 @@ protected:
public:
void begin() {
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
startup_reason = BD_STARTUP_NORMAL;
#ifdef ESP32_CPU_FREQ
setCpuFrequencyMhz(ESP32_CPU_FREQ);
@@ -47,7 +47,7 @@ public:
#endif
#else
Wire.begin();
#endif
#endif
}
// Temperature from ESP32 MCU
@@ -66,50 +66,6 @@ public:
return P_LORA_DIO_1; // default for SX1262
}
// 27 mins drift in 28 days and 40 mins = 669 ppm
const int64_t MICROSECONDS_PER_SECOND_DRIFT = 669;
const int64_t DRIFT_THRESHOLD_US = 60000000LL; // 1 minute in microseconds
void applyTimeTrim() {
static int64_t last_trim_us = 0;
static int64_t accumulated_drift_us = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
int64_t now_us = (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
if (last_trim_us == 0) {
last_trim_us = now_us;
return;
}
// Calculate elapsed time
int64_t elapsed_us = now_us - last_trim_us;
// Add this interval's drift to accumulated drift
accumulated_drift_us += (elapsed_us * MICROSECONDS_PER_SECOND_DRIFT) / 1000000LL;
// Only trim when accumulated drift exceeds threshold
if (accumulated_drift_us >= DRIFT_THRESHOLD_US) {
// Calculate full seconds to trim
uint32_t seconds_to_trim = (uint32_t)(accumulated_drift_us / 1000000LL);
// Set back the trimmed time to RTC
tv.tv_sec -= (time_t)seconds_to_trim;
settimeofday(&tv, NULL);
// Keep the fractional remainder (anything less than a full second)
accumulated_drift_us %= 1000000LL;
// Save for next trim
gettimeofday(&tv, NULL);
last_trim_us = (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
} else {
// Skip trimming
last_trim_us = now_us;
}
}
void sleep(uint32_t secs) override {
// Skip if not allow to sleep
if (inhibit_sleep) {
@@ -117,23 +73,8 @@ public:
return;
}
// Use more accurate clock in sleep
#if SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256
if (rtc_clk_slow_src_get() != SOC_RTC_SLOW_CLK_SRC_RC_FAST) {
// Switch slow clock source to RC_FAST / 256 (~31.25 kHz)
rtc_clk_slow_src_set(SOC_RTC_SLOW_CLK_SRC_RC_FAST);
// Calibrate slow clock
esp_clk_slow_boot_cal(1024);
}
#endif
// Keep RTC 8M during sleep
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC8M, ESP_PD_OPTION_ON);
// Set GPIO wakeup
gpio_num_t wakeupPin = (gpio_num_t)getIRQGpio();
gpio_num_t wakeupPin = (gpio_num_t)getIRQGpio();
// Configure timer wakeup
if (secs > 0) {
@@ -163,9 +104,6 @@ public:
// Enable CPU interrupt servicing
portEXIT_CRITICAL(&sleepMux);
// Apply the software trim to correct for RC drift
applyTimeTrim();
}
uint8_t getStartupReason() const override { return startup_reason; }