]> granicus.if.org Git - esp-idf/commitdiff
deep sleep: implement wake up using ULP, EXT0, EXT1 sources
authorIvan Grokhotkov <ivan@espressif.com>
Thu, 8 Dec 2016 14:22:10 +0000 (22:22 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Fri, 16 Dec 2016 06:30:27 +0000 (14:30 +0800)
This adds the following APIs to enable various wakeup sources:
- esp_deep_sleep_enable_timer_wakeup
- esp_deep_sleep_enable_ulp_wakeup
- esp_deep_sleep_enable_ext0_wakeup
- esp_deep_sleep_enable_ext1_wakeup

And an API to start deep sleep:
- esp_deep_sleep_start

components/driver/gpio.c
components/driver/include/driver/rtc_io.h
components/driver/rtc_module.c
components/esp32/deepsleep.c
components/esp32/include/esp_deepsleep.h
components/esp32/test/test_deepsleep.c [new file with mode: 0644]

index 1f916921bc3a3061afb9f51409782de2cd64e844..4bdd716f362f8a3de9c103c442147942af9167fe 100644 (file)
@@ -77,7 +77,7 @@ esp_err_t gpio_pullup_en(gpio_num_t gpio_num) {
     if(RTC_GPIO_IS_VALID_GPIO(gpio_num)){
         rtc_gpio_pullup_en(gpio_num);
     }else{
-         REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU);
+        REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU);
     }
     return ESP_OK;
 }
index 2e351cf13aa88024fe5713e762deac2570cf1ed3..04f699e50ff80357b5fda0914ed75ce2ddcbcd1c 100644 (file)
@@ -33,6 +33,8 @@ typedef struct {
     uint32_t ie;        /*!< Mask of input enable */
     uint32_t pullup;    /*!< Mask of pullup enable */
     uint32_t pulldown;  /*!< Mask of pulldown enable */
+    uint32_t slpsel;    /*!< Mask of the bit to select pin as wakeup pin */
+    uint32_t slpie;     /*!< Mask of input enable in sleep mode */
     int rtc_num;        /*!< RTC IO number, or -1 if not an RTC GPIO */
 } rtc_gpio_desc_t;
 
index ecb7e434d18e14d96d88d40d45a13b7d927931aa..804ad6c0d3697c4728ebcb16af725990403b856a 100644 (file)
@@ -40,46 +40,46 @@ portMUX_TYPE rtc_spinlock = portMUX_INITIALIZER_UNLOCKED;
 
 //Reg,Mux,Fun,IE,Up,Down,Rtc_number
 const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = {
-    {RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_MUX_SEL_M, RTC_IO_TOUCH_PAD1_FUN_SEL_S, RTC_IO_TOUCH_PAD1_FUN_IE_M, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M, 11}, //0
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //1
-    {RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_MUX_SEL_M, RTC_IO_TOUCH_PAD2_FUN_SEL_S, RTC_IO_TOUCH_PAD2_FUN_IE_M, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M, 12}, //2
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //3
-    {RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_MUX_SEL_M, RTC_IO_TOUCH_PAD0_FUN_SEL_S, RTC_IO_TOUCH_PAD0_FUN_IE_M, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M, 10}, //4
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //5
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //6
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //7
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //8
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //9
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //10
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //11
-    {RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_MUX_SEL_M, RTC_IO_TOUCH_PAD5_FUN_SEL_S, RTC_IO_TOUCH_PAD5_FUN_IE_M, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M, 15}, //12
-    {RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_MUX_SEL_M, RTC_IO_TOUCH_PAD4_FUN_SEL_S, RTC_IO_TOUCH_PAD4_FUN_IE_M, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M, 14}, //13
-    {RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_MUX_SEL_M, RTC_IO_TOUCH_PAD6_FUN_SEL_S, RTC_IO_TOUCH_PAD6_FUN_IE_M, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M, 16}, //14
-    {RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_MUX_SEL_M, RTC_IO_TOUCH_PAD3_FUN_SEL_S, RTC_IO_TOUCH_PAD3_FUN_IE_M, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M, 13}, //15
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //16
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //17
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //18
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //19
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //20
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //21
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //22
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //23
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //24
-    {RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M, RTC_IO_PDAC1_FUN_SEL_S, RTC_IO_PDAC1_FUN_IE_M, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M, 6},                           //25
-    {RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_MUX_SEL_M, RTC_IO_PDAC2_FUN_SEL_S, RTC_IO_PDAC2_FUN_IE_M, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M, 7},                           //26
-    {RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M, RTC_IO_TOUCH_PAD7_FUN_SEL_S, RTC_IO_TOUCH_PAD7_FUN_IE_M, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M, 17}, //27
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //28
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //29
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //30
-    {0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //31
-    {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_MUX_SEL_M, RTC_IO_X32P_FUN_SEL_S, RTC_IO_X32P_FUN_IE_M, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M, 9},                            //32
-    {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL_M, RTC_IO_X32N_FUN_SEL_S, RTC_IO_X32N_FUN_IE_M, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M, 8},                            //33
-    {RTC_IO_ADC_PAD_REG, RTC_IO_ADC1_MUX_SEL_M, RTC_IO_ADC1_FUN_SEL_S, RTC_IO_ADC1_FUN_IE_M, 0, 0, 4},                                                                //34
-    {RTC_IO_ADC_PAD_REG, RTC_IO_ADC2_MUX_SEL_M, RTC_IO_ADC2_FUN_SEL_S, RTC_IO_ADC2_FUN_IE_M, 0, 0, 5},                                                                //35
-    {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE1_MUX_SEL_M, RTC_IO_SENSE1_FUN_SEL_S, RTC_IO_SENSE1_FUN_IE_M, 0, 0, 0},                                                      //36
-    {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE2_MUX_SEL_M, RTC_IO_SENSE2_FUN_SEL_S, RTC_IO_SENSE2_FUN_IE_M, 0, 0, 1},                                                      //37
-    {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE3_MUX_SEL_M, RTC_IO_SENSE3_FUN_SEL_S, RTC_IO_SENSE3_FUN_IE_M, 0, 0, 2},                                                       //38
-    {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE4_MUX_SEL_M, RTC_IO_SENSE4_FUN_SEL_S, RTC_IO_SENSE4_FUN_IE_M, 0, 0, 3},                                                      //39
+    {RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_MUX_SEL_M, RTC_IO_TOUCH_PAD1_FUN_SEL_S, RTC_IO_TOUCH_PAD1_FUN_IE_M, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M, RTC_IO_TOUCH_PAD1_SLP_SEL_M, RTC_IO_TOUCH_PAD1_SLP_IE_M, 11}, //0
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //1
+    {RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_MUX_SEL_M, RTC_IO_TOUCH_PAD2_FUN_SEL_S, RTC_IO_TOUCH_PAD2_FUN_IE_M, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M, RTC_IO_TOUCH_PAD2_SLP_SEL_M, RTC_IO_TOUCH_PAD2_SLP_IE_M, 12}, //2
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //3
+    {RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_MUX_SEL_M, RTC_IO_TOUCH_PAD0_FUN_SEL_S, RTC_IO_TOUCH_PAD0_FUN_IE_M, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M, RTC_IO_TOUCH_PAD0_SLP_SEL_M, RTC_IO_TOUCH_PAD0_SLP_IE_M, 10}, //4
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //5
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //6
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //7
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //8
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //9
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //10
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //11
+    {RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_MUX_SEL_M, RTC_IO_TOUCH_PAD5_FUN_SEL_S, RTC_IO_TOUCH_PAD5_FUN_IE_M, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M, RTC_IO_TOUCH_PAD5_SLP_SEL_M, RTC_IO_TOUCH_PAD5_SLP_IE_M, 15}, //12
+    {RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_MUX_SEL_M, RTC_IO_TOUCH_PAD4_FUN_SEL_S, RTC_IO_TOUCH_PAD4_FUN_IE_M, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M, RTC_IO_TOUCH_PAD4_SLP_SEL_M, RTC_IO_TOUCH_PAD4_SLP_IE_M, 14}, //13
+    {RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_MUX_SEL_M, RTC_IO_TOUCH_PAD6_FUN_SEL_S, RTC_IO_TOUCH_PAD6_FUN_IE_M, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M, RTC_IO_TOUCH_PAD6_SLP_SEL_M, RTC_IO_TOUCH_PAD6_SLP_IE_M, 16}, //14
+    {RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_MUX_SEL_M, RTC_IO_TOUCH_PAD3_FUN_SEL_S, RTC_IO_TOUCH_PAD3_FUN_IE_M, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M, RTC_IO_TOUCH_PAD3_SLP_SEL_M, RTC_IO_TOUCH_PAD3_SLP_IE_M, 13}, //15
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //16
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //17
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //18
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //19
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //20
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //21
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //22
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //23
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //24
+    {RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M, RTC_IO_PDAC1_FUN_SEL_S, RTC_IO_PDAC1_FUN_IE_M, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M, RTC_IO_PDAC1_SLP_SEL_M, RTC_IO_PDAC1_SLP_IE_M, 6},                           //25
+    {RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_MUX_SEL_M, RTC_IO_PDAC2_FUN_SEL_S, RTC_IO_PDAC2_FUN_IE_M, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M, RTC_IO_PDAC2_SLP_SEL_M, RTC_IO_PDAC2_SLP_IE_M, 7},                           //26
+    {RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M, RTC_IO_TOUCH_PAD7_FUN_SEL_S, RTC_IO_TOUCH_PAD7_FUN_IE_M, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M, RTC_IO_TOUCH_PAD7_SLP_SEL_M, RTC_IO_TOUCH_PAD7_SLP_IE_M, 17}, //27
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //28
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //29
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //30
+    {0, 0, 0, 0, 0, 0, 0, 0, -1},                                                                                                                                            //31
+    {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_MUX_SEL_M, RTC_IO_X32P_FUN_SEL_S, RTC_IO_X32P_FUN_IE_M, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M, RTC_IO_X32P_SLP_SEL_M, RTC_IO_X32P_SLP_IE_M, 9},                            //32
+    {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL_M, RTC_IO_X32N_FUN_SEL_S, RTC_IO_X32N_FUN_IE_M, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M, RTC_IO_X32N_SLP_SEL_M, RTC_IO_X32N_SLP_IE_M, 8},                            //33
+    {RTC_IO_ADC_PAD_REG, RTC_IO_ADC1_MUX_SEL_M, RTC_IO_ADC1_FUN_SEL_S, RTC_IO_ADC1_FUN_IE_M, 0, 0, RTC_IO_ADC1_SLP_SEL_M, RTC_IO_ADC1_SLP_IE_M, 4},                                                                //34
+    {RTC_IO_ADC_PAD_REG, RTC_IO_ADC2_MUX_SEL_M, RTC_IO_ADC2_FUN_SEL_S, RTC_IO_ADC2_FUN_IE_M, 0, 0, RTC_IO_ADC2_SLP_SEL_M, RTC_IO_ADC2_SLP_IE_M, 5},                                                                //35
+    {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE1_MUX_SEL_M, RTC_IO_SENSE1_FUN_SEL_S, RTC_IO_SENSE1_FUN_IE_M, 0, 0, RTC_IO_SENSE1_SLP_SEL_M, RTC_IO_SENSE1_SLP_IE_M, 0},                                                      //36
+    {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE2_MUX_SEL_M, RTC_IO_SENSE2_FUN_SEL_S, RTC_IO_SENSE2_FUN_IE_M, 0, 0, RTC_IO_SENSE2_SLP_SEL_M, RTC_IO_SENSE2_SLP_IE_M, 1},                                                      //37
+    {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE3_MUX_SEL_M, RTC_IO_SENSE3_FUN_SEL_S, RTC_IO_SENSE3_FUN_IE_M, 0, 0, RTC_IO_SENSE3_SLP_SEL_M, RTC_IO_SENSE3_SLP_IE_M, 2},                                                       //38
+    {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE4_MUX_SEL_M, RTC_IO_SENSE4_FUN_SEL_S, RTC_IO_SENSE4_FUN_IE_M, 0, 0, RTC_IO_SENSE4_SLP_SEL_M, RTC_IO_SENSE4_SLP_IE_M, 3},                                                      //39
 };
 
 /*---------------------------------------------------------------
index b8b73a3b1ffd0456832c19b81406dad397387660..cf9ee852e5d0bbf8f8339230f23ce16645b20914 100644 (file)
@@ -1,7 +1,17 @@
-/* Wake from deep sleep stub
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
-   See esp_deepsleep.h esp_wake_deep_sleep() comments for details.
-*/
 #include <stddef.h>
 #include <sys/lock.h>
 #include "rom/cache.h"
 #include "soc/dport_reg.h"
 #include "esp_attr.h"
 #include "esp_deepsleep.h"
+#include "esp_log.h"
+#include "soc/cpu.h"
 #include "rtc.h"
+#include "driver/rtc_io.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
 
 /* Updating RTC_MEMORY_CRC_REG register via set_rtc_memory_crc()
    is not thread-safe. */
 static _lock_t lock_rtc_memory_crc;
+static uint32_t s_wakeup_options = 0;
+static uint64_t s_sleep_duration = 0;
 
+static const char* TAG = "deepsleep";
+
+/* Wake from deep sleep stub
+   See esp_deepsleep.h esp_wake_deep_sleep() comments for details.
+*/
 esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void)
 {
     _lock_acquire(&lock_rtc_memory_crc);
@@ -50,18 +72,112 @@ void __attribute__((weak, alias("esp_default_wake_deep_sleep"))) esp_wake_deep_s
 
 void esp_deep_sleep(uint64_t time_in_us)
 {
-    rtc_set_cpu_freq(CPU_XTAL);
+    esp_deep_sleep_enable_timer_wakeup(time_in_us);
+    esp_deep_sleep_start();
+}
+
+void IRAM_ATTR esp_deep_sleep_start()
+{
     if (esp_get_deep_sleep_wake_stub() == NULL) {
         esp_set_deep_sleep_wake_stub(esp_wake_deep_sleep);
     }
-    uint32_t period = rtc_slowck_cali(CALI_RTC_MUX, 128);
-    uint32_t cycle_l, cycle_h;
-    rtc_usec2rtc(time_in_us >> 32, time_in_us, period, &cycle_h, &cycle_l);
-    rtc_slp_prep_lite(1, 0);
-    rtc_sleep(cycle_h, cycle_l, TIMER_EXPIRE_EN, 0);
+
+    rtc_set_cpu_freq(CPU_XTAL);
+    uint32_t cycle_h = 0;
+    uint32_t cycle_l = 0;
+    if (s_sleep_duration > 0) {
+        uint32_t period = rtc_slowck_cali(CALI_RTC_MUX, 128);
+        rtc_usec2rtc(s_sleep_duration >> 32, s_sleep_duration & 0xffffffff, period, &cycle_h, &cycle_l);
+    }
+    rtc_slp_prep_lite(DEEP_SLEEP_PD_NORMAL, 0);
+    rtc_sleep(cycle_h, cycle_l, s_wakeup_options, 0);
     while (1) {
         ;
     }
 }
 
 void system_deep_sleep(uint64_t) __attribute__((alias("esp_deep_sleep")));
+
+esp_err_t esp_deep_sleep_enable_ulp_wakeup()
+{
+#ifdef CONFIG_ULP_COPROC_ENABLED
+    s_wakeup_options |= SAR_TRIG_EN;
+    return ESP_OK;
+#else
+    return ESP_ERR_INVALID_STATE;
+#endif
+}
+
+esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us)
+{
+    s_wakeup_options |= TIMER_EXPIRE_EN;
+    s_sleep_duration = time_in_us;
+    return ESP_OK;
+}
+
+esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level)
+{
+    if (level < 0 || level > 1) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (!RTC_GPIO_IS_VALID_GPIO(gpio_num)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    const rtc_gpio_desc_t* desc = &rtc_gpio_desc[gpio_num];
+    REG_SET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL, desc->rtc_num);
+    SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1, level, RTC_CNTL_EXT_WAKEUP0_LV_S);
+    REG_SET_BIT(desc->reg, desc->slpsel);
+    REG_SET_BIT(desc->reg, desc->slpie);
+    s_wakeup_options |= RTC_EXT_EVENT0_TRIG_EN;
+    return ESP_OK;
+}
+
+esp_err_t esp_deep_sleep_enable_ext1_wakeup(uint64_t mask, esp_ext1_wakeup_mode_t mode)
+{
+    if (mode > EXT1_WAKEUP_ANY_HIGH) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    // Translate bit map of GPIO numbers into the bit map of RTC IO numbers
+    uint32_t rtc_gpio_mask = 0;
+    for (int gpio = 0; mask; ++gpio, mask >>= 1) {
+        if ((mask & 1) == 0) {
+            continue;
+        }
+        if (!RTC_GPIO_IS_VALID_GPIO(gpio)) {
+            ESP_LOGE(TAG, "Not an RTC IO: GPIO%d", gpio);
+            return ESP_ERR_INVALID_ARG;
+        }
+        const rtc_gpio_desc_t* desc = &rtc_gpio_desc[gpio];
+        int rtc_pin = desc->rtc_num;
+        rtc_gpio_mask |= BIT(rtc_pin);
+        REG_SET_BIT(desc->reg, desc->slpsel);
+        REG_SET_BIT(desc->reg, desc->slpie);
+    }
+    REG_SET_BIT(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_STATUS_CLR);
+    REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, rtc_gpio_mask);
+    SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1, mode, RTC_CNTL_EXT_WAKEUP1_LV_S);
+    s_wakeup_options |= RTC_EXT_EVENT1_TRIG_EN;
+    return ESP_OK;
+}
+
+uint64_t esp_deep_sleep_get_ext1_wakeup_status()
+{
+    int wakeup_reason = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE);
+    if (wakeup_reason != RTC_EXT_EVENT1_TRIG) {
+        return 0;
+    }
+    uint32_t status = REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS);
+    // Translate bit map of RTC IO numbers into the bit map of GPIO numbers
+    uint64_t gpio_mask = 0;
+    for (int gpio = 0; gpio < 40; ++gpio) {
+        if (!RTC_GPIO_IS_VALID_GPIO(gpio)) {
+            continue;
+        }
+        int rtc_pin = rtc_gpio_desc[gpio].rtc_num;
+        if ((status & BIT(rtc_pin)) == 0) {
+            continue;
+        }
+        gpio_mask |= BIT(gpio);
+    }
+    return gpio_mask;
+}
index 051ad14c3c8b42550af0438545b431bb96e93d87..ab2e2cbc532401d0dd0085af859eec6742437de9 100644 (file)
@@ -3,7 +3,7 @@
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
-
+//
 //     http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef __ESP_DEEPSLEEP_H__
-#define __ESP_DEEPSLEEP_H_
+#pragma once
 
 #include <stdint.h>
+#include "esp_err.h"
+#include "driver/gpio.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -29,6 +30,14 @@ extern "C" {
   * @{
   */
 
+/**
+ * @brief Logic function used for EXT1 wakeup mode.
+ */
+typedef enum {
+    EXT1_WAKEUP_ALL_LOW = 0,    /*!< Wake the chip when all selected GPIOs go low */
+    EXT1_WAKEUP_ANY_HIGH = 1    /*!< Wake the chip when any of the selected GPIOs go high */
+} esp_ext1_wakeup_mode_t;
+
 /**
  * @brief Enter deep-sleep mode
  *
@@ -36,12 +45,88 @@ extern "C" {
  * Upon waking up, the device calls deep sleep wake stub, and then proceeds
  * to load application.
  *
+ * Call to this function is equivalent to a call to esp_deep_sleep_enable_timer_wakeup
+ * followed by a call to esp_deep_sleep_start.
+ *
  * This function does not return.
  *
  * @param time_in_us  deep-sleep time, unit: microsecond
  */
 void esp_deep_sleep(uint64_t time_in_us) __attribute__((noreturn));
 
+/**
+ * @brief Enable wakeup by ULP coprocessor
+ * @return
+ *      - ESP_OK on success
+ *      - ESP_ERR_INVALID_STATE if ULP co-processor is not enabled.
+ */
+esp_err_t esp_deep_sleep_enable_ulp_wakeup();
+
+/**
+ * @brief Enable wakeup by timer
+ * @param time_in_us  time before wakeup, in microseconds
+ * @return
+ *      - ESP_OK on success
+ *      - ESP_ERR_INVALID_ARG if value is out of range (TBD)
+ */
+esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us);
+
+/**
+ * @brief Enable wakeup using a pin
+ *
+ * This function uses external wakeup feature of RTC_IO peripheral.
+ * It will work only if RTC peripherals are kept on during deep sleep.
+ *
+ * This feature can monitor any pin which is an RTC IO. Once the pin transitions
+ * into the state given by level argument, the chip will be woken up.
+ *
+ * @param gpio_num  GPIO number used as wakeup source. Only GPIOs which are have RTC
+ *             functionality can be used: 0,2,4,12-15,25-27,32-39.
+ * @param level  input level which will trigger wakeup (0=low, 1=high)
+ * @return
+ *      - ESP_OK on success
+ *      - ESP_ERR_INVALID_ARG if either of the arguments is out of range
+ */
+esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level);
+
+/**
+ * @brief Enable wakeup using multiple pins
+ *
+ * This function uses external wakeup feature of RTC controller.
+ * It will work even if RTC peripherals are shut down during deep sleep.
+ *
+ * This feature can monitor any number of pins which are in RTC IOs.
+ * Once any of the selected pins goes into the state given by level argument,
+ * the chip will be woken up.
+ *
+ * @param mask  bit mask of GPIO numbers which will cause wakeup. Only GPIOs
+ *              which are have RTC functionality can be used in this bit map:
+ *              0,2,4,12-15,25-27,32-39.
+ * @param mode select logic function used to determine wakeup condition:
+ *            - EXT1_WAKEUP_ALL_LOW: wake up when all selected GPIOs are low
+ *            - EXT1_WAKEUP_ANY_HIGH: wake up when any of the selected GPIOs is high
+ * @return
+ *      - ESP_OK on success
+ *      - ESP_ERR_INVALID_ARG if either of the arguments is out of range
+ */
+esp_err_t esp_deep_sleep_enable_ext1_wakeup(uint64_t mask, esp_ext1_wakeup_mode_t mode);
+
+
+/**
+ * @brief Get the bit mask of GPIOs which caused wakeup (ext1)
+ *
+ * If wakeup was caused by another source, this function will return 0.
+ *
+ * @return bit mask, if GPIOn caused wakeup, BIT(n) will be set
+ */
+uint64_t esp_deep_sleep_get_ext1_wakeup_status();
+
+/**
+ * @brief Enter deep sleep with the configured wakeup options
+ *
+ * This function does not return.
+ */
+void esp_deep_sleep_start() __attribute__((noreturn));
 
 /**
  * @brief Enter deep-sleep mode
@@ -87,15 +172,17 @@ typedef void (*esp_deep_sleep_wake_stub_fn_t)(void);
 void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub);
 
 /**
- * @brief Return current wake from deep sleep stub, or NULL if
- * no stub is installed.
+ * @brief Get current wake from deep sleep stub
+ * @return Return current wake from deep sleep stub, or NULL if
+ *         no stub is installed.
  */
 esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void);
 
-/* The default esp-idf-provided esp_wake_deep_sleep() stub.
-
-   See docs/deep-sleep-stub.rst for details.
-*/
+/**
+ *  @brief The default esp-idf-provided esp_wake_deep_sleep() stub.
+ *
+ *  See docs/deep-sleep-stub.rst for details.
+ */
 void esp_default_wake_deep_sleep(void);
 
 /**
@@ -110,5 +197,3 @@ void esp_default_wake_deep_sleep(void);
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __ESP_SYSTEM_H__ */
diff --git a/components/esp32/test/test_deepsleep.c b/components/esp32/test/test_deepsleep.c
new file mode 100644 (file)
index 0000000..fb05f01
--- /dev/null
@@ -0,0 +1,75 @@
+#include "unity.h"
+#include "esp_deepsleep.h"
+#include "driver/rtc_io.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+TEST_CASE("esp_deepsleep works", "[deepsleep]")
+{
+    esp_deep_sleep(2000000);
+}
+
+static void deep_sleep_task(void* arg)
+{
+    esp_deep_sleep_start();
+}
+
+static void do_deep_sleep_from_app_cpu()
+{
+    xTaskCreatePinnedToCore(&deep_sleep_task, "ds", 2048, NULL, 5, NULL, 1);
+
+    // keep running some non-IRAM code
+    vTaskSuspendAll();
+    while(true) {
+        ;
+    }
+}
+
+TEST_CASE("can wake up from deep sleep using timer", "[deepsleep]")
+{
+    esp_deep_sleep_enable_timer_wakeup(2000000);
+    esp_deep_sleep_start();
+}
+
+TEST_CASE("go into deep sleep from APP CPU and wake up using timer", "[deepsleep]")
+{
+    esp_deep_sleep_enable_timer_wakeup(2000000);
+    do_deep_sleep_from_app_cpu();
+}
+
+
+TEST_CASE("can wake up from deep sleep using ext0 (13 high)", "[deepsleep]")
+{
+    ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13));
+    ESP_ERROR_CHECK(gpio_pullup_dis(GPIO_NUM_13));
+    ESP_ERROR_CHECK(gpio_pulldown_en(GPIO_NUM_13));
+    ESP_ERROR_CHECK(esp_deep_sleep_enable_ext0_wakeup(GPIO_NUM_13, 1));
+    esp_deep_sleep_start();
+}
+
+TEST_CASE("can wake up from deep sleep using ext0 (13 low)", "[deepsleep]")
+{
+    ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13));
+    ESP_ERROR_CHECK(gpio_pullup_en(GPIO_NUM_13));
+    ESP_ERROR_CHECK(gpio_pulldown_dis(GPIO_NUM_13));
+    ESP_ERROR_CHECK(esp_deep_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0));
+    esp_deep_sleep_start();
+}
+
+TEST_CASE("can wake up from deep sleep using ext1 (13 high)", "[deepsleep]")
+{
+    ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13));
+    ESP_ERROR_CHECK(gpio_pullup_dis(GPIO_NUM_13));
+    ESP_ERROR_CHECK(gpio_pulldown_en(GPIO_NUM_13));
+    ESP_ERROR_CHECK(esp_deep_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), EXT1_WAKEUP_ANY_HIGH));
+    esp_deep_sleep_start();
+}
+
+TEST_CASE("can wake up from deep sleep using ext1 (13 low)", "[deepsleep]")
+{
+    ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13));
+    ESP_ERROR_CHECK(gpio_pullup_en(GPIO_NUM_13));
+    ESP_ERROR_CHECK(gpio_pulldown_dis(GPIO_NUM_13));
+    ESP_ERROR_CHECK(esp_deep_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), EXT1_WAKEUP_ALL_LOW));
+    esp_deep_sleep_start();
+}