ESP32 risparmio energetico pratico: preservare lo stato dei gpio, risveglio esterno e ULP – 5

Spread the love

Con l’esp32, quando si utilizza un sonno leggero, un sonno profondo o uno stato di ibernazione, è necessario selezionare la sorgente di risveglio per far tornare attivo il dispositivo.

ESP32 practical power saving preserve gpio status on deep sleep ULP and external wake-up
ESP32 practical power saving preserve gpio status on deep sleep ULP and external wake-up

Ci sono molte soluzioni, alcune sono standard RTC o esterne, altre sono new entry come touch o ULP.

Se hai già letto il capitolo precedente, sai che ci sono alcune grandi differenze nel consumo di energia se selezioni una fonte di sveglia esterna o timer, quindi fai attenzione alla tua scelta.

Ora andremo a testare una fonte di risveglio esterna.

Function Block diagram Espressif esp32 Wi-Fi Bluetooth Microcontroller
Function Block diagram Espressif esp32 Wi-Fi Bluetooth Microcontroller

Wake up esterno (ext0), gestione di un gpio singolo

Il modulo RTC IO contiene la logica per riattivare il dispositivo quando uno dei GPIO RTC è impostato su un livello logico predefinito. RTC IO fa parte del dominio di alimentazione delle periferiche RTC, quindi le periferiche RTC verranno mantenute accese durante la sospensione profonda se viene richiesta questa sorgente di attivazione.

Poiché il modulo RTC IO è abilitato in questa modalità, è possibile utilizzare resistenze interne di pullup o pulldown. Devono essere configurati dall’applicazione utilizzando  rtc_gpio_pullup_en e  rtc_gpio_pulldown_en functions, prima di chiamare l’esp_deep_sleep_start.

Nelle revisioni 0 e 1 di ESP32, questa sorgente di riattivazione non è compatibile con ULP e sorgenti di riattivazione tattile.

Avvertenza: dopo il risveglio dalla sospensione profonda, l’IO pin utilizzato per il risveglio verrà configurato come RTC IO. Prima di utilizzare questo pin come GPIO digitale, riconfigurarlo utilizzando la funzione rtc_gpio_deinit(gpio_num).

Il comando per attivare il risveglio da un GPIO è

esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level)

Questa funzione utilizza la features di riattivazione esterna della periferica RTC_IO. Funzionerà solo se le periferiche RTC vengono tenute accese durante il sonno profondo.

Questa funzione può monitorare qualsiasi pin che sia un RTC IO. Una volta che il pin passa allo stato fornito dall’argomento level, il chip verrà riattivato.

Ritorno

  • ESP_OK in caso di successo
  • ESP_ERR_INVALID_ARG se il GPIO selezionato non è un GPIO RTC o la modalità non è valida
  • ESP_ERR_INVALID_STATE se il risveglio innesca un conflitto

Per ulteriori informazioni sul dispositivo fare riferimento a “DOIT ESP32 DEV KIT v1 immagine di piedinatura ad alta risoluzione e specifiche“.

Parametri

  • gpio_num: numero del GPIO utilizzato come origine del risveglio. È possibile utilizzare solo GPIO con funzionalità RTC: 0,2,4,12-15,25-27,32-39.
  • level: livello di ingresso che attiverà il risveglio (0 = basso, 1 = alto)

Ecco uno sketch basico di esempio:

/*
 *  ESP32
 *  DEEP Sleep and external wake up (ext0) on GPIO4
 *  by Mischianti Renzo <https://mischianti.org>
 *
 *  https://mischianti.org/it/esp32-risparmio-energetico-pratico-preservare-lo-stato-dei-gpio-risveglio-esterno-e-ulp-5/
 *
 */

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial2.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial2.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial2.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial2.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial2.println("Wakeup caused by ULP program"); break;
    default : Serial2.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

void setup(){
  Serial2.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial2.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up for an external trigger.

  Note that using internal pullups/pulldowns also requires
  RTC peripherals to be turned on.
  */
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_4,HIGH);

  //Go to sleep now
  Serial2.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial2.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}

Conservare lo stato dei GPIOs

È anche possibile preservare lo stato del GPIOs, questo è molto utile per mantenere aperto un mosfet o impostare uno stato su dispositivo esterno.

    if (ESP_SLEEP_WAKEUP_EXT0 == wakeup_reason) {
    	Serial.println("Waked up from external GPIO!");

    	gpio_hold_dis(GPIO_NUM_21);
    	gpio_hold_dis(GPIO_NUM_19);

    	gpio_deep_sleep_hold_dis();
    }else{
		delay(1000);
		Serial.println();
		Serial.println("Start sleep!");
		delay(100);

		if (ESP_OK == gpio_hold_en(GPIO_NUM_21)){
			Serial.println("HOLD 21");
		}else{
			Serial.println("NO HOLD 21");
		}
		if (ESP_OK == gpio_hold_en(GPIO_NUM_19)){
				Serial.println("HOLD 19");
			}else{
				Serial.println("NO HOLD 19");
			}

		esp_sleep_enable_ext0_wakeup(GPIO_NUM_15,LOW);

		gpio_deep_sleep_hold_en();
		//Go to sleep now
		Serial.println("Going to sleep now");
		esp_deep_sleep_start();

		delay(1);
    }

Come puoi vedere puoi forzare il valore di GPIO con gpio_hold_en e devi chiamare gpio_hold_dis per consentirne nuovamente la modifica.

Per abilitare la preservazione del valore dopo il risveglio dal sonno profondo è necessario aggiungere una funzione gpio_deep_sleep_hold_en() al codice.

Wake up esterno (ext1), gestione di GPIOs multipli

esp32 DOIT DEV KIT v1 Serial2 FTDI multiple external wake-up on breadboard
esp32 DOIT DEV KIT v1 Serial2 FTDI multiple external wake-up on breadboard

Il controller RTC contiene la logica per la riattivazione utilizzando più RTC GPIOs. Uno dei due stati logici può essere utilizzato per attivare il risveglio:

  • svegliati se uno dei pin selezionati è alto (ESP_EXT1_WAKEUP_ANY_HIGH)
  • svegliati se tutti i pin selezionati sono bassi (ESP_EXT1_WAKEUP_ALL_LOW)

Questa sorgente di attivazione è implementata dal controller RTC. Pertanto, le periferiche RTC e le memorie RTC possono essere disattivate in questa modalità. Tuttavia, se le periferiche RTC sono spente, le resistenze interne di pullup e pulldown saranno disabilitate.

La funzione esp_sleep_enable_ext1_wakeup() può essere utilizzata per abilitare questa sorgente di risveglio.

Per impostare la maschera di bit puoi usare questo comando:

esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode);

Questa funzione può monitorare qualsiasi numero di pin che si trovino negli RTC IO. Una volta che uno qualsiasi dei pin selezionati entra nello stato fornito dall’argomento mode, il chip verrà riattivato.

Ritorno

  • ESP_OK in caso di successo
  • ESP_ERR_INVALID_ARG se uno dei GPIO selezionati non è un GPIO RTC o la modalità non è valida

Parametri

  • mask: maschera di bit dei GPIOs che causerà il risveglio. Solo i GPIOs con funzionalità RTC possono essere utilizzati in questa bit map: 0,2,4,12-15,25-27,32-39. Creo un generatore di maschere di bit in modo da semplificare la gestione.
    C’è un problema con i GPIO da 32 a 39, che non sono identificati dallo stato e non possono essere recuperati.
  • mode: seleziona la funzione logica utilizzata per determinare la condizione di riattivazione:
    • ESP_EXT1_WAKEUP_ALL_LOW: svegliati quando tutti i GPIO selezionati sono bassi
    • ESP_EXT1_WAKEUP_ANY_HIGH: svegliati quando uno qualsiasi dei GPIO selezionati è alto
Title
GPIO Bitmask
BitMask:

Puoi recuperare quale pin è stato movimentato con esp_sleep_get_ext1_wakeup_status() il quale restituisce la maschera di bit che aveva generato la sveglia, return 0 identifica se la fonte non è ext1. Molte persone hanno un problema con i pins da 32 a 39 che restituisce 0, quindi fai attenzione.

/*
Method to print the GPIO by which ESP32
has been awaken from sleep
*/
void print_wakeup_GPIO(){
  GPIObitmask = esp_sleep_get_ext1_wakeup_status();

  Serial2.print(GPIObitmask);
  Serial2.print(" Wake UP GPIO: GPIO ");
  Serial2.println((log(GPIObitmask))/log(2), 0);
}

Qui lo sketch completo:

/*
 *  ESP32
 *  DEEP Sleep and external wake up (ext1) with bitmask
 *  set on GPIO2 GPIO4 GPIO12
 *  by Mischianti Renzo <https://mischianti.org>
 *
 *  https://mischianti.org/it/esp32-risparmio-energetico-pratico-preservare-lo-stato-dei-gpio-risveglio-esterno-e-ulp-5/
 *
 */

// Refer to my GPIO bitmask generator on relativa rticle
#define BUTTON_PIN_BITMASK 0x1014 // 2^2 + 2^4 + 2^12  in hex

RTC_DATA_ATTR int bootCount = 0;
int GPIObitmask;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial2.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial2.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial2.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial2.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial2.println("Wakeup caused by ULP program"); break;
    default : Serial2.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

/*
Method to print the GPIO by which ESP32
has been awaken from sleep
*/
void print_wakeup_GPIO(){
  GPIObitmask = esp_sleep_get_ext1_wakeup_status();

  Serial2.print(GPIObitmask);
  Serial2.print(" Wake UP GPIO: GPIO ");
  Serial2.println((log(GPIObitmask))/log(2), 0);
}

void setup(){
  Serial2.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial2.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  //Print the wakeup GPIO for ESP32
  print_wakeup_GPIO();

  //If you were to use ext1, you would use it like
  esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

  //Go to sleep now
  Serial2.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial2.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}

ULP Wake UP

Il coprocessore ULP può essere eseguito mentre il chip è in modalità di sospensione e può essere utilizzato per eseguire il polling dei sensori, monitorare i valori dell’ADC o del sensore tattile e riattivare il chip quando viene rilevato un evento specifico. Il coprocessore ULP fa parte del dominio di alimentazione delle periferiche RTC ed esegue il programma archiviato nella memoria lenta RTC. La memoria lenta RTC verrà attivata durante la sospensione se viene richiesta questa modalità di riattivazione. Le periferiche RTC verranno automaticamente accese prima che il coprocessore ULP inizi a eseguire il programma; una volta che il programma smette di funzionare, le periferiche RTC vengono automaticamente spente di nuovo.

La funzione esp_sleep_enable_ulp_wakeup() è utilizzata per abilitare questa sorgente di risveglio.

Puoi caricare il programma ULP con questi comandi:

void init_ulp_program() {
    const ulp_insn_t program[] = {
            // initiate wakeup of the SoC
            I_WAKE(),
			// stop the ULP program
            I_HALT()
    };

    size_t load_addr = 0;
    size_t size = sizeof(program)/sizeof(ulp_insn_t);
    ulp_process_macros_and_load(load_addr, program, &size);

    ulp_run(0);
}

Il comando per impostare il periodo di attivazione dell’ULP è:

esp_err_t ulp_set_wakeup_period(size_t period_index, uint32_t period_us);

Parametri:
period_index indice dell’impostazione del periodo di sveglia (0-4)
period_us periodo di sveglia in µs.

Ritorno
ESP_OK in caso di successo
ESP_ERR_INVALID_ARG se period_index è fuori intervallo

I comandi ULP per riattivare l’esp32 sono:

        // initiate wakeup of the SoC
        I_WAKE(),
	// stop the ULP program
        I_HALT()

Qui lo sketch completo:

/*
 *  ESP32
 *  DEEP Sleep and ULP wake up
 *  by Mischianti Renzo <https://mischianti.org>
 *
 *  https://mischianti.org/it/esp32-risparmio-energetico-pratico-preservare-lo-stato-dei-gpio-risveglio-esterno-e-ulp-5/
 *
 */

#include "esp32/ulp.h"
#include "soc/rtc_cntl_reg.h"
#include "driver/rtc_io.h"

void init_ulp_program();

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial2.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial2.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial2.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial2.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial2.println("Wakeup caused by ULP program"); break;
    default : Serial2.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

void setup() {
    Serial2.begin(115200);
    while( !Serial ){}

    Serial2.println("Init");

    //Increment boot number and print it every reboot
    ++bootCount;
    Serial2.println("Boot number: " + String(bootCount));

    //Print the wakeup reason for ESP32
    print_wakeup_reason();

    esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
    if (cause != ESP_SLEEP_WAKEUP_ULP) {
    	Serial2.println("Initializing ULP");
        init_ulp_program();
        /* Set ULP wake up period to 5s */
        ulp_set_wakeup_period(0, 5 * 1000 * 1000);
    }

    Serial2.println("Entering deep sleep\n");
    ESP_ERROR_CHECK( esp_sleep_enable_ulp_wakeup() );

    esp_deep_sleep_start();
}

void loop(){
}

void init_ulp_program() {
    const ulp_insn_t program[] = {
            // initiate wakeup of the SoC
            I_WAKE(),
			// stop the ULP program
            I_HALT()
    };

    size_t load_addr = 0;
    size_t size = sizeof(program)/sizeof(ulp_insn_t);
    ulp_process_macros_and_load(load_addr, program, &size);

    ulp_run(0);
}

Ecco l’output della Serial2

Init
Boot number: 1
Wakeup was not caused by deep sleep: 0
Entering deep sleep

Init
Boot number: 2
Wakeup caused by ULP program
ULP wakeup
Entering deep sleep

Init
Boot number: 3
Wakeup caused by ULP program
ULP wakeup
Entering deep sleep

Grazie

  1. ESP32: piedinatura, specifiche e configurazione dell’Arduino IDE
  2. ESP32: fileSystem integrato SPIFFS
  3. ESP32: gestire più seriali e logging per il debug
  4. ESP32 risparmio energetico pratico
    1. ESP32 risparmio energetico pratico: gestire WiFi e CPU
    2. ESP32 risparmio energetico pratico: modem e light sleep
    3. ESP32 risparmio energetico pratico: deep sleep e ibernazione
    4. ESP32 risparmio energetico pratico: preservare dati al riavvio, sveglia a tempo e tramite tocco
    5. ESP32 risparmio energetico pratico: sveglia esterna e da ULP
    6. ESP32 risparmio energetico pratico: sveglia da UART e GPIO
  5. ESP32: filesystem integrato LittleFS
  6. ESP32: filesystem integrato FFat (Fat/exFAT)
  7. ESP32-wroom-32
    1. ESP32-wroom-32: flash, piedinatura, specifiche e configurazione dell’Arduino IDE
  8. ESP32-CAM
    1. ESP32-CAM: piedinatura, specifiche e configurazione dell’Arduino IDE
    2. ESP32-CAM: upgrade CamerWebServer con gestione della luce flash
  9. ESP32: ethernet w5500 con chiamate standard (HTTP) e SSL (HTTPS)
  10. ESP32: ethernet enc28j60 con chiamate standard (HTTP) e SSL (HTTPS)
  11. Come usare la scheda SD con l’esp32
  12. esp32 e esp8266: file system FAT su memoria SPI flash esterna
  13. Gestione aggiornamenti firmware e OTA
    1. Gestione del firmware
      1. ESP32: flash del firmware binario compilato (.bin)
      2. ESP32: flash del firmware e filesystem (.bin) con strumenti grafici
    2. Aggiornamento OTA con Arduino IDE
      1. Aggiornamenti OTA su ESP32 con Arduino IDE: filesystem, firmware e password
    3. Aggiornamento OTA con browser web
      1. Aggiornamenti OTA su ESP32 tramite browser web: firmware, filesystem e autenticazione
      2. Aggiornamenti OTA su ESP32 tramite browser web: caricamento in HTTPS (SSL/TLS) con certificato autofirmato
      3. Aggiornamenti OTA su ESP32 tramite browser web: interfaccia web personalizzata
    4. Aggiornamenti automatici OTA da un server HTTP
      1. Aggiornamento automatico Firmware OTA dell’ESP32 dal server
      2. Aggiornamento automatico Firmware OTA dell’ESP32 dal server con controllo della versione
      3. Aggiornamento automatico Firmware OTA dell’ESP32 in HTTPS (SSL/TLS) con certificato autofirmato affidabile
    5. Aggiornamento del firmware non standard
      1. Aggiornamento firmware e filesystem ESP32 dalla scheda SD
      2. Aggiornamento firmware e filesystem ESP32 con client FTP
  14. Integrare LAN8720 con ESP32 per la connettività Ethernet con plain (HTTP) e SSL (HTTPS)
  15. Collegare l’EByte E70 (CC1310) ai dispositivi ESP32 c3/s3 ed un semplice sketch di esempio
  16. ESP32-C3: piedinatura, specifiche e configurazione dell’IDE Arduino
  17. Integrazione del modulo W5500 su ESP32 con Core 3: supporto nativo ai protocolli Ethernet con SSL e altre funzionalità
  18. Integrazione del modulo LAN8720 su ESP32 con Core 3: supporto nativo del protocollo Ethernet con SSL e altre funzionalità.

Spread the love

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *