Skip to main content

Deep Sleep Support

The Memfault SDK stores Heartbeats, Event data, and the Logging circular buffer in RAM by default. Systems that periodically enter low-power modes, and power off RAM, will lose this data.

To persist Memfault data through these low-power modes, the Memfault SDK has support for saving and restoring the state of these subsystems.

Here's a flowchart showing the sequence of operations for preserving and restoring the Memfault SDK state during deep sleep:

note

The Memfault SDK includes a built-in implementation for saving and restoring on ESP-IDF (ESP32) devices, and for memfault_platform_get_time_since_boot_ms(). If you are using ESP-IDF, you can use the CONFIG_MEMFAULT_DEEP_SLEEP_SUPPORT=Y option to enable this feature.

Prior to deep sleep, you must call memfault_platform_deep_sleep_save_state().

On exiting deep sleep, you must call memfault_platform_deep_sleep_restore_state().

Time Since Boot

The implementation of memfault_platform_get_time_since_boot_ms() must include the time spent in deep sleep. You can use an RTC, or compensate the active tick timer by the accumulated time spent in deep sleep.

Saving Memfault State

The general strategy for saving the Memfault state is to call the memfault_x_get_state() function for each subsystem you want to save. You can then write the returned state to a storage medium that persists through deep sleep power down (e.g., low-power RAM, flash, etc.).

Call the following APIs to save the Memfault state before entering deep sleep:

#include "memfault/components.h"

int deep_sleep_prepare(void) {
// Save the Memfault Metrics state
// First trigger a metrics collection to update any metrics accumulated over
// this interval
memfault_metrics_heartbeat_collect();
const void *metrics_ctx = memfault_metrics_get_state();
// The data can now be written to storage of size
// MEMFAULT_METRICS_CONTEXT_SIZE_BYTES

// Save the Memfault Log state
sMfltLogSaveState log_state = memfault_log_get_state();
// The sMfltLogSaveState data structure contains 2 separate blocks of memory
// that should be saved.
log_state.context; // this is of size MEMFAULT_LOG_STATE_SIZE_BYTES
log_state.storage; // this matches the size of the buffer passed into
// memfault_log_boot()

// Save the Memfault Event state
sMfltEventStorageSaveState event_state = memfault_event_storage_get_state();
// The sMfltEventStorageSaveState data structure contains 2 separate blocks of
// memory that should be saved.
event_state.context; // this is of size MEMFAULT_EVENT_STORAGE_STATE_SIZE_BYTES
event_state.storage; // this is the size of the buffer passed into
// memfault_event_storage_boot()

Restoring Memfault State

To restore the Memfault state after waking up from deep sleep, you need to implement a set of callbacks that are invoked during the Memfault subcomponent boot steps.

#include "memfault/components.h"

#include <stdint.h>

// Imaginary structure to hold the saved state
struct sMfltBackupData {
uint8_t event_storage_context[MEMFAULT_EVENT_STORAGE_STATE_SIZE_BYTES];
uint8_t event_storage_data[MEMFAULT_EVENT_STORAGE_SIZE_BYTES];
uint8_t metrics_data[MEMFAULT_METRICS_CONTEXT_SIZE_BYTES];
uint8_t log_context[MEMFAULT_LOG_STATE_SIZE_BYTES];
uint8_t log_storage[MEMFAULT_LOG_STORAGE_SIZE_BYTES];
} s_mflt_backup_data;

bool memfault_event_storage_restore_state(sMfltEventStorageSaveState *state) {
// Copy data from storage back to the state
memcpy(state->context, &s_mflt_backup_data.event_storage_context[0],
MEMFAULT_EVENT_STORAGE_STATE_SIZE_BYTES);
state->context_len = MEMFAULT_EVENT_STORAGE_STATE_SIZE_BYTES;
memcpy(state->storage, &s_mflt_backup_data.event_storage_data[0],
MEMFAULT_EVENT_STORAGE_SIZE_BYTES);
state->storage_len = MEMFAULT_EVENT_STORAGE_SIZE_BYTES;

return true;
}

bool memfault_metrics_restore_state(void *state) {
// Copy the data back to the state
memcpy(state, &s_mflt_backup_data.metrics_data[0], MEMFAULT_METRICS_CONTEXT_SIZE_BYTES);

return true;
}

extern bool memfault_log_restore_state(sMfltLogSaveState *state) {
// Copy data from storage back to the state
memcpy(state->context, &s_mflt_backup_data.log_context[0],
MEMFAULT_LOG_STATE_SIZE_BYTES);
state->context_len = MEMFAULT_LOG_STATE_SIZE_BYTES;
memcpy(state->storage, &s_mflt_backup_data.log_storage[0],
MEMFAULT_LOG_STORAGE_SIZE_BYTES);
state->storage_len = MEMFAULT_LOG_STORAGE_SIZE_BYTES;

return true;
}