]> granicus.if.org Git - esp-idf/commitdiff
sleep: add support for GPIO and UART wakeup from light sleep
authorIvan Grokhotkov <ivan@espressif.com>
Tue, 14 Aug 2018 00:42:03 +0000 (03:42 +0300)
committerIvan Grokhotkov <ivan@espressif.com>
Thu, 6 Sep 2018 07:40:46 +0000 (15:40 +0800)
components/esp32/include/esp_sleep.h
components/esp32/sleep_modes.c

index 8e50c7e20ae2e892dd34bdd45cc3141c03a30970..57fb4780e822b6394bedce7a6fbb0470d8920a0b 100644 (file)
@@ -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)
index ac9ea70dca64b211804ee145fe82ae6b05ed0b7f..13681a52d978645d2ab9ade3d803e685273b1b6b 100644 (file)
@@ -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