ESP32 risparmio energetico pratico: preservare lo stato dei gpio, risveglio esterno e ULP – 5
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.
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.
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 successoESP_ERR_INVALID_ARG
se il GPIO selezionato non è un GPIO RTC o la modalità non è validaESP_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
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 successoESP_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 bassiESP_EXT1_WAKEUP_ANY_HIGH
: svegliati quando uno qualsiasi dei GPIO selezionati è alto
GPIO 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
è utilizzata per abilitare questa sorgente di risveglio.esp_sleep_enable_ulp_wakeup()
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.
RitornoESP_OK
in caso di successoESP_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
- ESP32: piedinatura, specifiche e configurazione dell’Arduino IDE
- ESP32: fileSystem integrato SPIFFS
- ESP32: gestire più seriali e logging per il debug
- ESP32 risparmio energetico pratico
- ESP32 risparmio energetico pratico: gestire WiFi e CPU
- ESP32 risparmio energetico pratico: modem e light sleep
- ESP32 risparmio energetico pratico: deep sleep e ibernazione
- ESP32 risparmio energetico pratico: preservare dati al riavvio, sveglia a tempo e tramite tocco
- ESP32 risparmio energetico pratico: sveglia esterna e da ULP
- ESP32 risparmio energetico pratico: sveglia da UART e GPIO
- ESP32: filesystem integrato LittleFS
- ESP32: filesystem integrato FFat (Fat/exFAT)
- ESP32-wroom-32
- ESP32-CAM
- ESP32: ethernet w5500 con chiamate standard (HTTP) e SSL (HTTPS)
- ESP32: ethernet enc28j60 con chiamate standard (HTTP) e SSL (HTTPS)
- Come usare la scheda SD con l’esp32
- esp32 e esp8266: file system FAT su memoria SPI flash esterna
- Gestione aggiornamenti firmware e OTA
- Gestione del firmware
- Aggiornamento OTA con Arduino IDE
- Aggiornamento OTA con browser web
- Aggiornamenti automatici OTA da un server HTTP
- Aggiornamento del firmware non standard
- Integrare LAN8720 con ESP32 per la connettività Ethernet con plain (HTTP) e SSL (HTTPS)
- Collegare l’EByte E70 (CC1310) ai dispositivi ESP32 c3/s3 ed un semplice sketch di esempio
- ESP32-C3: piedinatura, specifiche e configurazione dell’IDE Arduino
- Integrazione del modulo W5500 su ESP32 con Core 3: supporto nativo ai protocolli Ethernet con SSL e altre funzionalità
- Integrazione del modulo LAN8720 su ESP32 con Core 3: supporto nativo del protocollo Ethernet con SSL e altre funzionalità.