ESP32 (29) – Deep sleep

luca 22/01/2018 6

Una delle tematiche principali per dispositivi embedded è il consumo energetico. Se infatti il dispositivo che si sta realizzando dovrà essere alimentato a batteria, è necessario ridurre al minimo il consumo di corrente in modo da massimizzare l’autonomia (= il tempo di funzionamento prima che sia necessario sostituire o ricaricare la batteria).

Il chip esp32 offre 5 diverse modalità di consumo energetico (power modes). La modalità di funzionamento “nomale” prende il nome di active mode; in tale modalità tutte le funzionalità del chip sono disponibili. Iniziando a ridurre la velocità di funzionamento e disattivando periferiche e cores, si passa a diverse modalità di risparmio energetico, riassunte nel seguente schema:

sleep-001

In questo primo articolo relativo al risparmio energetico del chip esp32, vi parlerò della modalità deep sleep.

Deep sleep

Il framework esp-idf supporta attualmente due modalità di risparmio ergetico: light sleepdeep sleep. Tra le due, la modalità deep sleep è quella che offre un risparmio maggiore di energia. In tale modalità vengono spente:

  • entrambe le CPU
  • la maggior parte della memoria RAM
  • tutte le periferiche

sono invece di default mantenute in esecuzione:

  • il controller RTC
  • le periferiche RTC, incluso il coprocessore ULP
  • Le memorie RTC lenta e veloce (slowfast)

L’attivazione della modalità deep sleep avviene con il comando esp_deep_sleep_start(), mentre è possibile “risvegliarsi” (wakeup) da tale modalità in base a diversi eventi:

sleep-002

Al risveglio dalla modalità deep sleep, avviene un nuovo boot. E’ molto importante comprendere quindi che il programma non riprende dal punto in cui è stato chiamato il metodo esp_deep_sleep_start().

Vediamo nel dettaglio la configurazione e l’utilizzo di due eventi: di touch pad e ULP vi parlerò in un prossimo articolo.

Timer

L’evento di wakeup più semplice è quello che utilizza un timer del controller RTC. Utilizzando il metodo:

esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)

è possibile risvegliare il chip esp32 dopo il numero di microsecondi specificati come parametro. Il metodo deve essere chiamato prima di attivare la modalità deep sleep:

// wakeup after 10 seconds
esp_sleep_enable_timer_wakeup(10000000);
esp_deep_sleep_start();

I/O triggers

In un precedente articolo vi ho parlato della possibilità di avere interrupts al cambio di stato di uno dei pin digitali del chip esp32. Possiamo sfruttare una funzionalità simile per risvegliare il chip esp32 dallo sleep.

Con il metodo

esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level)

è possibile attivare il wakeup se avviene un cambio di stato (level) del pin specificato (gpio_num).

I pin utilizzabili sono soltanto quelli con funzionalità RTC (0, 2, 4, 12-15, 25-27, 32-39) e i livelli sono 0 (= basso) o 1 (alto). Se ad esempio vogliamo configurare il risveglio da deep sleep quando il pin 4 ha uno stato logico basso, scriveremo:

esp_sleep_enable_ext0_wakeup(4, 0);

E’ disponibile anche un metodo per monitorare diversi pins:

esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode)

i pin (anche per tale metodo è possibile specificare solo quelli sopra elencati) vanno indicati come bitmask, mentre le modalità possibili sono:

  • ESP_EXT1_WAKEUP_ALL_LOW = wakeup quanto tutti i pins sono a livello logico basso
  • ESP_EXT1_WAKEUP_ANY_HIGH = wakeup quando almeno un pin è a livello logico alto
Al ritorno dallo sleep, i pin specificati saranno configurati come RTC IO. Per poterli utilizzare come pin digitali, è necessario chiamare il metodo rtc_gpio_deinit(gpio_num). Il metodo ext0_wakeup non è attualmente compatibile con wakeup basati su touch pad o ULP.

Dopo il risveglio…

Se sono stati attivati più eventi di wakeup, è possibile conoscere quale evento ha causato il risveglio con:

esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause()

Le costanti possibili sono:

sleep-003

Per l’evento ext1_wakeup, è possibile conoscere la bitmask dei pin che hanno causato il risveglio con:

uint64_t esp_sleep_get_ext1_wakeup_status()

Memoria

Come spiegato sopra, in deep sleep viene preservato il contenuto delle memorie RTC fastRTC slow. E’ quindi possibile utilizzare tali aree di memoria per memorizzare dati da conservare durante lo sleep.

Per indicare al compilatore che una variabile deve essere memorizzata nella RTC slow memory è sufficiente usare l’attributo RTC_DATA_ATTR, oppure RTC_RODATA_ATTR se tale variabile è in sola lettura (read only):

RTC_DATA_ATTR static time_t last;

Demo

Ho preparato un programma (il codice sorgente è disponibile nel mio repository Github) che mostra il funzionamento della modalità deep sleep e due diversi eventi di wake up (sottitoli in italiano disponibili):

6 Comments »

  1. Stivi 07/03/2018 at 16:59 - Reply

    i have trouble with the deepsleep of the esp32 (huzzah32)

    I hope any one of you could help me.
    i am using this:

    switch (esp_deep_sleep_get_wakeup_cause()) {
    case ESP_DEEP_SLEEP_WAKEUP_EXT1: {
    uint64_t wakeup_pin_mask = esp_deep_sleep_get_ext1_wakeup_status();
    if (wakeup_pin_mask != 0) {
    int pin = __builtin_ffsll(wakeup_pin_mask) – 1;
    printf(“Wake up from GPIO %d\n”, pin);
    } else {
    printf(“Wake up from GPIO\n”);
    }
    break;
    }

    and get the following error:

    “error: esp_deep_sleep_get_ext1_wakeup_status() not declared in this scope”

    I include deepsleep:
    #include

    Did anyone had an hint for me?

    Thanks a lot!!

    Regards,

    Stivi

    • luca 08/03/2018 at 15:15 - Reply

      Hi, it seems they changed the method to esp_sleep_get_ext1_wakeup_status()

  2. Stivi 09/03/2018 at 11:46 - Reply

    Thanks a lot Luca! You made my day!

    I haven´t seen it!

    It´s working now!

  3. Alessandro Dionisi 17/03/2018 at 17:30 - Reply

    Ciao Luca,

    Grazie del tuo video, mi sarà molto di aiuto nel progettino che sto realizzando. Vorrei costruire un tastierino wireless bluetooth usando un comune matrix keypad a membrana e ESP32. Il mio problema è che vorrei sfruttare il deep sleep e risvegliare il dispositivo solo quando l’utente digita qualche tasto. Mi accontenterei anche di perdere la prima cifra digitata eventualmente. Tu che consigli mi daresti per realizzare questa cosa? Grazie mille!

    • luca 18/03/2018 at 16:06 - Reply

      Ciao Alessandro, quei tastierini normalmente sono gestiti come “matrice”, quindi penso si possa usare il wake sui pin di I/O a cui hai collegato il tastierino! buon diverimento!

      • Alessandro Dionisi 18/03/2018 at 21:01 - Reply

        Si certo, però il problema è che dato che sono gestiti a matrice, per poter capire quale tasto è stato premuto, si cicla sulle righe (collegate ai pin di output) e si da livello logico alto, andando poi a leggere le colonne per capire quale tasto è stato premuto. Per questo motivo, diversamente dal pushbutton che è sempre “alimentato”, gli switch della matrice sono alimentati a rotazione ma solo mentre il codice è in esecuzione. Forse ho capito male io, me lo confermi? Grazie ancora!

Leave A Response »

Questo sito usa i cookie per poterti offrire una migliore esperienza di navigazione maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.

Chiudi