ESP8266, Deep sleep and RTC
Posted: Fri Oct 11, 2024 10:01 am
TLDR; When going into deep sleep, I need to "recompute" the actual time, but I cannot seem to find a way to do so semi-precisely.
Context: I am managing an old (remote) clock through electrical signals, so need to send an impulse every minute. I first obtain my time with wifi/NTP, then, to reduce power consumption, disable my wifi and rely on the internal clock for ~1 week before re-syncing with NTP (I have about 1.8 sec drift per week). To further improve consumption, I'd like to go in deep sleep for ~55 seconds or more, then send my electric signal to the clock, then back to deep sleep, etc. for a week, until I eventually sync back to NTP.
I did some prototyping with deep sleep, so, I created a program that gets time through NTP, then do a series of 100 deep-sleep/wake-up, then after 100x, I sync back to NTP and check the drift.
Here is what I use to store my last known time and deep sleep duration in RTC, stored just before going to deep sleep:
struct RTCData
I've tried multiple ways to restore the clock as I wake up from deep sleep. First option with system_get_rtc_time and system_rtc_clock_cali_proc:
I had big hopes but this is pretty bad, about 18 seconds drift over 100x (random duration of 3-8 sec sleeps)
Then went straight to "millis()" and it was better, about 9sec drift:
Lastly, I correct with a static value and it is "perfect" time-wise
But obviously, it is super ugly and non-deterministic.
What am I missing? How can I get the true time that elapses, beyond the actual sleep time? I need this "time" that elapses.
Would a ESP32-C6 have a better way to solve this?
(I don't want to use an external RTC)
Happy to send the code if useful!
Thanks!
Context: I am managing an old (remote) clock through electrical signals, so need to send an impulse every minute. I first obtain my time with wifi/NTP, then, to reduce power consumption, disable my wifi and rely on the internal clock for ~1 week before re-syncing with NTP (I have about 1.8 sec drift per week). To further improve consumption, I'd like to go in deep sleep for ~55 seconds or more, then send my electric signal to the clock, then back to deep sleep, etc. for a week, until I eventually sync back to NTP.
I did some prototyping with deep sleep, so, I created a program that gets time through NTP, then do a series of 100 deep-sleep/wake-up, then after 100x, I sync back to NTP and check the drift.
Here is what I use to store my last known time and deep sleep duration in RTC, stored just before going to deep sleep:
struct RTCData
Code: Select all
{
uint32_t magic;
timeval storedTime; // stores sec and micro-sec
int deepSleepTime; // how long am I going to sleep
int iteration; // counting to 100 before syncing to NTP to compute the drift
};
Code: Select all
uint32_t RTC_Time;
uint32_t SYS_Time = system_get_rtc_time();
uint32_t cal_factor = system_rtc_clock_cali_proc();
RTC_Time = SYS_Time / (((cal_factor * 1000) >> 12) / 1000);
// Set the system time to the adjusted current time
timeval tv = {rtcData.storedTime.tv_sec + rtcData.deepSleepTime, static_cast<suseconds_t>(rtcData.storedTime.tv_usec + RTC_TIME)};
Then went straight to "millis()" and it was better, about 9sec drift:
Code: Select all
timeval tv = {rtcData.storedTime.tv_sec + rtcData.deepSleepTime, static_cast<suseconds_t>(rtcData.storedTime.tv_usec + millis() * 1000)};
Code: Select all
timeval tv = {rtcData.storedTime.tv_sec + rtcData.deepSleepTime, static_cast<suseconds_t>(rtcData.storedTime.tv_usec + millis() * 1000 + 120 * 1000)};
What am I missing? How can I get the true time that elapses, beyond the actual sleep time? I need this "time" that elapses.
Would a ESP32-C6 have a better way to solve this?
(I don't want to use an external RTC)
Happy to send the code if useful!
Thanks!