esp32-sleep-modes

Qué son los modos sleep en el ESP32

Los Sleep Mode son estrategias utilizadas para minimizar el consumo de energía en dispositivos electrónicos cuando no están activamente realizando tareas.

Estos modos permiten reducir significativamente el consumo de energía, lo que es crucial para aplicaciones que funcionan con baterías o que están permanentemente conectados.

Cuando entramos en un modo de Sleep, en algún momento deberemos volver al modo “normal”. Para ello se disponen de varias formas de “despertar” al ESP32. A estos eventos los llamamos Wake-Up Sources.

Hay muchísima información obsoleta al respecto en tutoriales en internet. Ante cualquier duda, consultar la documentación oficial del fabricante

Modos Sleep en el ESP32

El ESP32 tiene dos modos de Sleep. Sumados al modo “normal” (activo) son tres posibles modos de funcionamiento.

⚡ Modo Activo

Es el modo “normal” en el que todo está conectado. La CPU, la RAM, y todos los periféricos están activos.

El ESP32 está haciendo sus cosas, procesando datos, y con el WiFi y BT activado.

🔋 Modo Light Sleep

El modo Light Sleep es similar a el modo “suspensión” de un ordenador. El ESP32 se para y reduce su consumo.

La CPU, la RAM y los periféricos digitales, son desconectados del reloj y su voltaje se reduce para deducir energía.

Al volver al modo normal el ESP32 sigue su ejecución en el mismo punto del programa que estuviera, conservando la memoria.

💤 Modo Deep Sleep

El modo Deep Sleep es mucho más agresivo. Es casi como apagar y encender el ESP32.

Las CPUs, la RAM y los periféricos digitales se apagan. Únicamente el RTC permanece activo.

Al volver al modo normal, el ESP32 vuelve al principio del programa. Todo lo que hubiéramos guardado en la memoria se pierde.

WakeUp Sources

Las WakeUp Sources también son la parte más importante para entrar en modo Sleep. Son las formas disponibles para despertar del modo Sleep.

Por defecto, el ESP32 desactivará todos los periféricos, excepto aquellos que especifiquemos como WakeUp Source. Es decir, el estado final y el consumo del ESP32 dependerá de los WakeUp Source que definamos.

Los WakeUp Source que están disponibles en ambos modos, Deep Sleep y Light Sleep, son los siguientes.

  • Timer
  • Touchpad
  • ULP Coprocessor Wakeup
  • External Wakeup (Ext0 y Ext1)

Y estos que solo funcionan en Light Sleep

  • GPIO Wakeup
  • UART Wakeup
  • WIFI Wakeup

Para configurarlos, emplearemos estas funciones:

// Light Sleep y Deep Sleep
esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us);
esp_err_t esp_sleep_enable_touchpad_wakeup(void);
esp_err_t esp_sleep_enable_ulp_wakeup(void);
esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level);
esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode);

// Solo en light Sleep
esp_err_t esp_sleep_enable_gpio_wakeup(void);
esp_err_t esp_sleep_enable_uart_wakeup(int uart_num);
esp_err_t esp_sleep_enable_wifi_wakeup(void);
void esp_sleep_enable_gpio_switch(bool enable);

Alternativamente podríamos usar la función esp_sleep_pd_config (internamente las anteriores lo hacen):

esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain,
                                   esp_sleep_pd_option_t option);

Donde esp_sleep_pd_domain_t puede tomar estos valores:

/**
 * @brief Power domains which can be powered down in sleep mode
 */
typedef enum {
    ESP_PD_DOMAIN_RTC_PERIPH,      //!< RTC IO, sensors and ULP co-processor
    ESP_PD_DOMAIN_RTC_SLOW_MEM,    //!< RTC slow memory
    ESP_PD_DOMAIN_RTC_FAST_MEM,    //!< RTC fast memory
    ESP_PD_DOMAIN_XTAL,            //!< XTAL oscillator
#if SOC_PM_SUPPORT_CPU_PD
    ESP_PD_DOMAIN_CPU,             //!< CPU core
#endif
    ESP_PD_DOMAIN_RTC8M,           //!< Internal 8M oscillator
    ESP_PD_DOMAIN_VDDSDIO,         //!< VDD_SDIO
    ESP_PD_DOMAIN_MAX              //!< Number of domains
} esp_sleep_pd_domain_t;

Y esp_sleep_pd_option_t puede ser:

/**
 * @brief Power down options
 */
typedef enum {
    ESP_PD_OPTION_OFF,      //!< Power down the power domain in sleep mode
    ESP_PD_OPTION_ON,       //!< Keep power domain enabled during sleep mode
    ESP_PD_OPTION_AUTO      //!< Keep power domain enabled in sleep mode, if it is needed by one of the wakeup options. Otherwise power it down.
} esp_sleep_pd_option_t;

Disable Sleep Wakeup Source

Si es necesario, podemos desactivar una de las WakeUp Source que hayamos definido anteriormente.

/**
 * @brief Disable wakeup source
 *
 * This function is used to deactivate wake up trigger for source
 * defined as parameter of the function.
 * @param source - number of source to disable of type esp_sleep_source_t
 */
esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source);

Obtener WakeUp Cause

La función esp_sleep_get_wakeup_cause() se puede utilizar para verificar qué fuente de activación ha provocado la salida del modo de suspensión.

/**
 * @brief Sleep wakeup cause
 */
typedef enum {
    ESP_SLEEP_WAKEUP_UNDEFINED,    //!< In case of deep sleep, reset was not caused by exit from deep sleep
    ESP_SLEEP_WAKEUP_ALL,          //!< Not a wakeup cause, used to disable all wakeup sources with esp_sleep_disable_wakeup_source
    ESP_SLEEP_WAKEUP_EXT0,         //!< Wakeup caused by external signal using RTC_IO
    ESP_SLEEP_WAKEUP_EXT1,         //!< Wakeup caused by external signal using RTC_CNTL
    ESP_SLEEP_WAKEUP_TIMER,        //!< Wakeup caused by timer
    ESP_SLEEP_WAKEUP_TOUCHPAD,     //!< Wakeup caused by touchpad
    ESP_SLEEP_WAKEUP_ULP,          //!< Wakeup caused by ULP program
    ESP_SLEEP_WAKEUP_GPIO,         //!< Wakeup caused by GPIO (light sleep only)
    ESP_SLEEP_WAKEUP_UART,         //!< Wakeup caused by UART (light sleep only)
    ESP_SLEEP_WAKEUP_WIFI,              //!< Wakeup caused by WIFI (light sleep only)
    ESP_SLEEP_WAKEUP_COCPU,             //!< Wakeup caused by COCPU int
    ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG,   //!< Wakeup caused by COCPU crash
    ESP_SLEEP_WAKEUP_BT,           //!< Wakeup caused by BT (light sleep only)
} esp_sleep_source_t;

Para el panel táctil, es posible identificar qué pin táctil ha causado la activación utilizando las funciones esp_sleep_get_touchpad_wakeup_status().

void print_wakeup_touchpad(){
  touchPin = esp_sleep_get_touchpad_wakeup_status();
  Serial.printf("Touch detectado en d\n",touchPin);
}
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();
  Serial.printf("Touch detectado en d\n",wakeup_reason);
}

Para las fuentes de activación ext1, es posible identificar qué pin táctil ha causado la activación utilizando las funciones esp_sleep_get_ext1_wakeup_status().

void print_wakeup_ext1(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_ext1 = esp_sleep_get_wakeup_cause();
  Serial.printf("Ext1 en d\n", wakeup_ext1);
}

Desactivar radio

Al entrar en un modo Sleep la radio (WiFi y BT) se apagan de forma “no demasiado elegante”. Por tanto, si estamos usando alguna de estas formas de comunicación debemos desactivarla explícitamente haciendo.

esp_bluedroid_disable()
esp_bt_controller_disable()
esp_wifi_stop()

Que, en el caso de usar el entorno de Arduino se hace así.

btStop();
WiFi.mode(WIFI_OFF);