diff --git a/components/esp32/include/esp_sleep.h b/components/esp32/include/esp_sleep.h index 8e50c7e20..57fb4780e 100644 --- a/components/esp32/include/esp_sleep.h +++ b/components/esp32/include/esp_sleep.h @@ -61,6 +61,8 @@ typedef enum { 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_source_t; /* Leave this type define for compatibility */ @@ -189,6 +191,43 @@ 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); +/** + * @brief Enable wakeup from light sleep using GPIOs + * + * Each GPIO supports wakeup function, which can be triggered on either low level + * or high level. Unlike EXT0 and EXT1 wakeup sources, this method can be used + * both for all IOs: RTC IOs and digital IOs. It can only be used to wakeup from + * light sleep though. + * + * To enable wakeup, first call gpio_wakeup_enable, specifying gpio number and + * wakeup level, for each GPIO which is used for wakeup. + * Then call this function to enable wakeup feature. + * + * @note In revisions 0 and 1 of the ESP32, GPIO wakeup source + * can not be used together with touch or ULP wakeup sources. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE if wakeup triggers conflict + */ +esp_err_t esp_sleep_enable_gpio_wakeup(); + +/** + * @brief Enable wakeup from light sleep using UART + * + * Use uart_set_wakeup_threshold function to configure UART wakeup threshold. + * + * Wakeup from light sleep takes some time, so not every character sent + * to the UART can be received by the application. + * + * @note ESP32 does not support wakeup from UART2. + * + * @param uart_num UART port to wake up from + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if wakeup from given UART is not supported + */ +esp_err_t esp_sleep_enable_uart_wakeup(int uart_num); /** * @brief Get the bit mask of GPIOs which caused wakeup (ext1) diff --git a/components/esp32/sleep_modes.c b/components/esp32/sleep_modes.c index ac9ea70dc..13681a52d 100644 --- a/components/esp32/sleep_modes.c +++ b/components/esp32/sleep_modes.c @@ -34,6 +34,7 @@ #include "soc/dport_reg.h" #include "soc/rtc_wdt.h" #include "driver/rtc_io.h" +#include "driver/uart.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "sdkconfig.h" @@ -363,19 +364,20 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source) if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_TIMER, RTC_TIMER_TRIG_EN)) { s_config.wakeup_triggers &= ~RTC_TIMER_TRIG_EN; s_config.sleep_duration = 0; - } - else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_EXT0, RTC_EXT0_TRIG_EN)) { + } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_EXT0, RTC_EXT0_TRIG_EN)) { s_config.ext0_rtc_gpio_num = 0; s_config.ext0_trigger_level = 0; s_config.wakeup_triggers &= ~RTC_EXT0_TRIG_EN; - } - else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_EXT1, RTC_EXT1_TRIG_EN)) { + } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_EXT1, RTC_EXT1_TRIG_EN)) { s_config.ext1_rtc_gpio_mask = 0; s_config.ext1_trigger_mode = 0; s_config.wakeup_triggers &= ~RTC_EXT1_TRIG_EN; - } - else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_TOUCHPAD, RTC_TOUCH_TRIG_EN)) { + } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_TOUCHPAD, RTC_TOUCH_TRIG_EN)) { s_config.wakeup_triggers &= ~RTC_TOUCH_TRIG_EN; + } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_GPIO, RTC_GPIO_TRIG_EN)) { + s_config.wakeup_triggers &= ~RTC_GPIO_TRIG_EN; + } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_UART, (RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN))) { + s_config.wakeup_triggers &= ~(RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN); } #ifdef CONFIG_ULP_COPROC_ENABLED else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_ULP, RTC_ULP_TRIG_EN)) { @@ -561,6 +563,29 @@ uint64_t esp_sleep_get_ext1_wakeup_status() return gpio_mask; } +esp_err_t esp_sleep_enable_gpio_wakeup() +{ + if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) { + ESP_LOGE(TAG, "Conflicting wake-up triggers: touch / ULP"); + return ESP_ERR_INVALID_STATE; + } + s_config.wakeup_triggers |= RTC_GPIO_TRIG_EN; + return ESP_OK; +} + +esp_err_t esp_sleep_enable_uart_wakeup(int uart_num) +{ + if (uart_num == UART_NUM_0) { + s_config.wakeup_triggers |= RTC_UART0_TRIG_EN; + } else if (uart_num == UART_NUM_1) { + s_config.wakeup_triggers |= RTC_UART1_TRIG_EN; + } else { + return ESP_ERR_INVALID_ARG; + } + + return ESP_OK; +} + esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause() { if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) { @@ -578,6 +603,10 @@ esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause() return ESP_SLEEP_WAKEUP_TOUCHPAD; } else if (wakeup_cause & RTC_ULP_TRIG_EN) { return ESP_SLEEP_WAKEUP_ULP; + } else if (wakeup_cause & RTC_GPIO_TRIG_EN) { + return ESP_SLEEP_WAKEUP_GPIO; + } else if (wakeup_cause & (RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN)) { + return ESP_SLEEP_WAKEUP_UART; } else { return ESP_SLEEP_WAKEUP_UNDEFINED; } @@ -620,10 +649,10 @@ static uint32_t get_power_down_flags() s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM] = ESP_PD_OPTION_ON; } - // RTC_PERIPH is needed for EXT0 wakeup. - // If RTC_PERIPH is auto, and EXT0 isn't enabled, power down RTC_PERIPH. + // RTC_PERIPH is needed for EXT0 wakeup and GPIO wakeup. + // If RTC_PERIPH is auto, and EXT0/GPIO aren't enabled, power down RTC_PERIPH. if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] == ESP_PD_OPTION_AUTO) { - if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) { + if (s_config.wakeup_triggers & (RTC_EXT0_TRIG_EN | RTC_GPIO_TRIG_EN)) { s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] = ESP_PD_OPTION_ON; } else if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) { // In both rev. 0 and rev. 1 of ESP32, forcing power up of RTC_PERIPH