Thanks Rick. That saves me some work!
I ended up doing some additional testing around the non-volatile RAM, which I'm guessing you're referring to the SRAM, as an extension to my original test code since in my experience, I've never had the SRAM clear (which makes sense), even when flashing new code.
FYI the SRAM doesn't clear. Also, the part in the docs that says
On the M-SoM, when waking from HIBERNATE
the RTC will be reset and clock time and date will not be valid until the next cloud connection.
is incorrect from my testing.
Here's my .cpp and serial printout, run on an M404 using device OS 6.2.1.
When running it, I woke it up via a pin twice, then let it wake using the RTC. SRAM remains intact, and the RTC doesn't clear and isValid() returns true if the time has been syned pre-sleep.
/******************************************************
* sleep_example.cpp
* Demonstrates Particle device hibernation for ~1 min,
* using a retained variable to count wake cycles,
* and waking from GPIO pins (D2 or D3).
******************************************************/
#include "Particle.h"
SystemSleepWakeupReason wakeupReason();
// Retained variable to count how many times we've booted after hibernate
retained int NumSleepsEntered = 0;
// How long (in minutes) to sleep
static const int SLEEP_MINUTES = 1;
void setup()
{
System.enableFeature(FEATURE_RESET_INFO);
pinMode(D2, INPUT_PULLDOWN);
pinMode(D3, INPUT_PULLDOWN);
// Start serial for debug output
Serial.begin(115200);
// Optional: wait up to 5 seconds for a USB serial connection (for debugging)
waitFor(Serial.isConnected, 5000);
Serial.println();
// Retrieve the system reset reason
int reason = System.resetReason();
// Convert to a textual description
Serial.printlnf("Reset reason code: %d, data: %d", reason, System.resetReasonData());
// ---------------------------------------------------
// 1. Check the reason we woke up from the *previous* sleep
// (only valid if we truly woke from sleep in HIBERNATE mode).
// ---------------------------------------------------
SystemSleepResult wakeResult = System.sleepResult();
// If there's no error, it likely means we just woke from hibernate
if (wakeResult.error() == SYSTEM_ERROR_NONE)
{
Serial.printlnf("D2: %d, D3: %d", digitalRead(D2), digitalRead(D3));
// Determine which reason caused the wake
switch (wakeResult.wakeupReason())
{
case SystemSleepWakeupReason::BY_GPIO:
{
pin_t pin = wakeResult.wakeupPin();
if (pin == D2)
{
Serial.println("Wake reason: GPIO (D2).");
}
else if (pin == D3)
{
Serial.println("Wake reason: GPIO (D3).");
}
else
{
Serial.printlnf("Wake reason: GPIO (unknown pin %u).", pin);
}
break;
}
case SystemSleepWakeupReason::BY_RTC:
Serial.println("Wake reason: Timer/RTC.");
break;
default:
Serial.printlnf("Wake reason: Other (%d).", wakeResult.wakeupReason());
break;
}
}
else
{
// If we get here, it might be a fresh boot or some other condition
Serial.println("Fresh boot (not waking from hibernate) or system error.");
}
// ---------------------------------------------------
// 2. Print how many times we've woken from hibernate so far
// ---------------------------------------------------
Serial.printlnf("Woken up from hibernation %d times", NumSleepsEntered);
// ---------------------------------------------------
// 3. Print the current time (if valid)
// ---------------------------------------------------
time_t currentTime = Time.now();
Serial.printlnf("Current Unix time: %ld", (long)currentTime);
Time.zone(11.0f); // Sydney Time
Serial.printlnf(Time.format(TIME_FORMAT_DEFAULT));
Serial.printlnf("Time is valid: %s", Time.isValid() ? "true" : "false");
// ---------------------------------------------------
// 4. Optionally wait for cloud connection if time is invalid
// (so we can sync and get correct time from Particle Cloud)
// ---------------------------------------------------
Serial.println("Checking if time is valid after waking");
if (!Time.isValid())
{
Serial.println("Time is invalid - waiting 30sec for a cloud connecton to get a valid time");
waitFor(Particle.connected, 30000); // up to 30s
if (Particle.connected())
{
Serial.println("Connected to the cloud, time should sync shortly.");
}
else
{
Serial.println("Failed to connect to the cloud within 30 seconds.");
}
// Print updated time info after the wait
currentTime = Time.now();
Serial.printlnf("Current Unix time: %ld", (long)currentTime);
Time.zone(11.0f);
Serial.printlnf(Time.format(TIME_FORMAT_DEFAULT));
Serial.printlnf("Time is valid: %s", Time.isValid() ? "true" : "false");
}
else
{
Serial.println("Time is already valid, no need for a cloud connection");
}
// ---------------------------------------------------
// 5. Increment wake counter before sleeping again
// ---------------------------------------------------
NumSleepsEntered++; // in theory, this should get reset when the device wakes from HIBERNATE
// ---------------------------------------------------
// 6. Configure hibernation to wake on D2, D3, or RTC
// ---------------------------------------------------
SystemSleepConfiguration config;
config.mode(SystemSleepMode::HIBERNATE)
.gpio(D2, RISING)
.gpio(D3, RISING)
.duration(SLEEP_MINUTES * 1min);
Serial.printlnf("Entering hibernation for %d minute(s) or until pin wake...", SLEEP_MINUTES);
Serial.flush();
delay(100);
System.sleep(config);
// We do NOT expect to get here in HIBERNATE mode because the device resets on wake
Serial.println("You should not see this line in HIBERNATE mode!");
}
void loop()
{
// In HIBERNATE mode, loop() is never reached after sleep;
// the device resets and runs setup() again.
}
Serial connection closed. Attempting to reconnect...
Serial monitor opened successfully:
Reset reason code: 40, data: 0
D2: 0, D3: 0
Wake reason: Other (0).
Woken up from hibernation 49 times
Current Unix time: 946684801
Sat Jan 1 11:00:01 2000
Time is valid: false
Checking if time is valid after waking
Time is invalid - waiting 30sec for a cloud connecton to get a valid time
Failed to connect to the cloud within 30 seconds.
Current Unix time: 946684832
Sat Jan 1 11:00:32 2000
Time is valid: false
Entering hibernation for 1 minute(s) or until pin wake...
Serial connection closed. Attempting to reconnect...
Serial monitor opened successfully:
Reset reason code: 30, data: 0
D2: 0, D3: 0
Wake reason: Other (0).
Woken up from hibernation 50 times
Current Unix time: 946684886
Sat Jan 1 11:01:26 2000
Time is valid: false
Checking if time is valid after waking
Time is invalid - waiting 30sec for a cloud connecton to get a valid time
Connected to the cloud, time should sync shortly.
Current Unix time: 1737071489
Fri Jan 17 10:51:29 2025
Time is valid: true
Entering hibernation for 1 minute(s) or until pin wake...
Serial connection closed. Attempting to reconnect...
Serial monitor opened successfully:
Reset reason code: 30, data: 0
D2: 0, D3: 0
Wake reason: Other (0).
Woken up from hibernation 51 times
Current Unix time: 1737071523
Fri Jan 17 10:52:03 2025
Time is valid: true
Checking if time is valid after waking
Time is already valid, no need for a cloud connection
Entering hibernation for 1 minute(s) or until pin wake...
Serial connection closed. Attempting to reconnect...
Serial monitor opened successfully:
Reset reason code: 30, data: 0
D2: 0, D3: 0
Wake reason: Other (0).
Woken up from hibernation 52 times
Current Unix time: 1737071593
Fri Jan 17 10:53:13 2025
Time is valid: true
Checking if time is valid after waking
Time is already valid, no need for a cloud connection
Entering hibernation for 1 minute(s) or until pin wake...
Serial connection closed. Attempting to reconnect...