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;
}