sleep: add light sleep, factor out APIs common for deep/light sleep

This commit is contained in:
Ivan Grokhotkov
2017-04-21 12:32:50 +08:00
parent 65b046f17f
commit d2acf1ce77
18 changed files with 716 additions and 475 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2015-2017 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.
@@ -14,281 +14,81 @@
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "driver/gpio.h"
#include "driver/touch_pad.h"
/**
* @file esp_deep_sleep.h
* @brief legacy definitions of esp_deep_sleep APIs
*
* This file provides compatibility for applications using esp_deep_sleep_* APIs.
* New applications should use functions defined in "esp_sleep.h" instead.
* These functions and types will be deprecated at some point.
*/
#warning esp_deep_sleep.h will be deprecated in the next release. Use esp_sleep.h instead.
#include "esp_sleep.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Logic function used for EXT1 wakeup mode.
*/
typedef enum {
ESP_EXT1_WAKEUP_ALL_LOW = 0, //!< Wake the chip when all selected GPIOs go low
ESP_EXT1_WAKEUP_ANY_HIGH = 1 //!< Wake the chip when any of the selected GPIOs go high
} esp_ext1_wakeup_mode_t;
typedef esp_sleep_pd_domain_t esp_deep_sleep_pd_domain_t;
typedef esp_sleep_pd_option_t esp_deep_sleep_pd_option_t;
typedef esp_sleep_ext1_wakeup_mode_t esp_ext1_wakeup_mode_t;
typedef esp_sleep_wakeup_cause_t esp_deep_sleep_wakeup_cause_t;
/**
* @brief Power domains which can be powered down in deep sleep
*/
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_MAX //!< Number of domains
} esp_deep_sleep_pd_domain_t;
inline static esp_err_t esp_deep_sleep_enable_ulp_wakeup(void)
{
return esp_sleep_enable_ulp_wakeup();
}
/**
* @brief Power down options
*/
typedef enum {
ESP_PD_OPTION_OFF, //!< Power down the power domain in deep sleep
ESP_PD_OPTION_ON, //!< Keep power domain enabled during deep sleep
ESP_PD_OPTION_AUTO //!< Keep power domain enabled in deep sleep, if it is needed by one of the wakeup options. Otherwise power it down.
} esp_deep_sleep_pd_option_t;
inline static esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us)
{
return esp_sleep_enable_timer_wakeup(time_in_us);
}
/**
* @brief Deep sleep wakeup cause
*/
typedef enum {
ESP_DEEP_SLEEP_WAKEUP_UNDEFINED, //! Wakeup was not caused by deep sleep
ESP_DEEP_SLEEP_WAKEUP_EXT0, //! Wakeup caused by external signal using RTC_IO
ESP_DEEP_SLEEP_WAKEUP_EXT1, //! Wakeup caused by external signal using RTC_CNTL
ESP_DEEP_SLEEP_WAKEUP_TIMER, //! Wakeup caused by timer
ESP_DEEP_SLEEP_WAKEUP_TOUCHPAD, //! Wakeup caused by touchpad
ESP_DEEP_SLEEP_WAKEUP_ULP, //! Wakeup caused by ULP program
} esp_deep_sleep_wakeup_cause_t;
inline static esp_err_t esp_deep_sleep_enable_touchpad_wakeup(void)
{
return esp_sleep_enable_touchpad_wakeup();
}
inline static touch_pad_t esp_deep_sleep_get_touchpad_wakeup_status()
{
return esp_sleep_get_touchpad_wakeup_status();
}
/**
* @brief Enable wakeup by ULP coprocessor
* @note In revisions 0 and 1 of the ESP32, ULP wakeup source
* can not be used when RTC_PERIPH power domain is forced
* to be powered on (ESP_PD_OPTION_ON) or when ext0 wakeup
* source is used.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if ULP co-processor is not enabled or if wakeup triggers conflict
*/
esp_err_t esp_deep_sleep_enable_ulp_wakeup();
inline static esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level)
{
return esp_sleep_enable_ext0_wakeup(gpio_num, level);
}
/**
* @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);
inline static esp_err_t esp_deep_sleep_enable_ext1_wakeup(uint64_t mask, esp_ext1_wakeup_mode_t mode)
{
return esp_sleep_enable_ext1_wakeup(mask, mode);
}
/**
* @brief Enable wakeup by touch sensor
*
* @note In revisions 0 and 1 of the ESP32, touch wakeup source
* can not be used when RTC_PERIPH power domain is forced
* to be powered on (ESP_PD_OPTION_ON) or when ext0 wakeup
* source is used.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if wakeup triggers conflict
*/
esp_err_t esp_deep_sleep_enable_touchpad_wakeup();
inline static esp_err_t esp_deep_sleep_pd_config(
esp_deep_sleep_pd_domain_t domain,
esp_deep_sleep_pd_option_t option)
{
return esp_sleep_pd_config(domain, option);
}
/**
* @brief Get the touch pad which caused wakeup
*
* If wakeup was caused by another source, this function will return TOUCH_PAD_MAX;
*
* @return touch pad which caused wakeup
*/
touch_pad_t esp_deep_sleep_get_touchpad_wakeup_status();
inline static esp_deep_sleep_wakeup_cause_t esp_deep_sleep_get_wakeup_cause()
{
return esp_sleep_get_wakeup_cause();
}
/**
* @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.
*
* @note This function does not modify pin configuration. The pin is
* configured in esp_deep_sleep_start, immediately before
* entering deep sleep.
*
* @note In revisions 0 and 1 of the ESP32, ext0 wakeup source
* can not be used together with touch or ULP wakeup sources.
*
* @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 the selected GPIO is not an RTC GPIO,
* or the mode is invalid
* - ESP_ERR_INVALID_STATE if wakeup triggers conflict
*/
esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level);
#define ESP_DEEP_SLEEP_WAKEUP_UNDEFINED ESP_SLEEP_WAKEUP_UNDEFINED
#define ESP_DEEP_SLEEP_WAKEUP_EXT0 ESP_SLEEP_WAKEUP_EXT0
#define ESP_DEEP_SLEEP_WAKEUP_EXT1 ESP_SLEEP_WAKEUP_EXT1
#define ESP_DEEP_SLEEP_WAKEUP_TIMER ESP_SLEEP_WAKEUP_TIMER
#define ESP_DEEP_SLEEP_WAKEUP_TOUCHPAD ESP_SLEEP_WAKEUP_TOUCHPAD
#define ESP_DEEP_SLEEP_WAKEUP_ULP ESP_SLEEP_WAKEUP_ULP
/**
* @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 mode argument,
* the chip will be woken up.
*
* @note This function does not modify pin configuration. The pins are
* configured in esp_deep_sleep_start, immediately before
* entering deep sleep.
*
* @note internal pullups and pulldowns don't work when RTC peripherals are
* shut down. In this case, external resistors need to be added.
* Alternatively, RTC peripherals (and pullups/pulldowns) may be
* kept enabled using esp_deep_sleep_pd_config function.
*
* @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:
* - ESP_EXT1_WAKEUP_ALL_LOW: wake up when all selected GPIOs are low
* - ESP_EXT1_WAKEUP_ANY_HIGH: wake up when any of the selected GPIOs is high
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if any of the selected GPIOs is not an RTC GPIO,
* or mode is invalid
*/
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 Set power down mode for an RTC power domain in deep sleep
*
* If not set set using this API, all power domains default to ESP_PD_OPTION_AUTO.
*
* @param domain power domain to configure
* @param option power down option (ESP_PD_OPTION_OFF, ESP_PD_OPTION_ON, or ESP_PD_OPTION_AUTO)
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if either of the arguments is out of range
*/
esp_err_t esp_deep_sleep_pd_config(esp_deep_sleep_pd_domain_t domain,
esp_deep_sleep_pd_option_t option);
/**
* @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
*
* The device will automatically wake up after the deep-sleep time
* 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.
*
* esp_deep_sleep does not shut down WiFi, BT, and higher level protocol
* connections gracefully.
* Make sure relevant WiFi and BT stack functions are called to close any
* connections and deinitialize the peripherals. These include:
* - esp_bluedroid_disable
* - esp_bt_controller_disable
* - esp_wifi_stop
*
* 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 Enter deep-sleep mode
*
* Function has been renamed to esp_deep_sleep.
* This name is deprecated and will be removed in a future version.
*
* @param time_in_us deep-sleep time, unit: microsecond
*/
void system_deep_sleep(uint64_t time_in_us) __attribute__((noreturn, deprecated));
/**
* @brief Get the source which caused deep sleep wakeup
*
* @return wakeup cause, or ESP_DEEP_SLEEP_WAKEUP_UNDEFINED if reset reason is other than deep sleep reset.
*/
esp_deep_sleep_wakeup_cause_t esp_deep_sleep_get_wakeup_cause();
/**
* @brief Default stub to run on wake from deep sleep.
*
* Allows for executing code immediately on wake from sleep, before
* the software bootloader or ESP-IDF app has started up.
*
* This function is weak-linked, so you can implement your own version
* to run code immediately when the chip wakes from
* sleep.
*
* See docs/deep-sleep-stub.rst for details.
*/
void esp_wake_deep_sleep(void);
/**
* @brief Function type for stub to run on wake from sleep.
*
*/
typedef void (*esp_deep_sleep_wake_stub_fn_t)(void);
/**
* @brief Install a new stub at runtime to run on wake from deep sleep
*
* If implementing esp_wake_deep_sleep() then it is not necessary to
* call this function.
*
* However, it is possible to call this function to substitute a
* different deep sleep stub. Any function used as a deep sleep stub
* must be marked RTC_IRAM_ATTR, and must obey the same rules given
* for esp_wake_deep_sleep().
*/
void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub);
/**
* @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);
/**
* @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);
#ifdef __cplusplus
}
#endif

View File

@@ -1,2 +1,2 @@
#warning esp_deepsleep.h has been renamed to esp_deep_sleep.h, please update include directives
#include "esp_deep_sleep.h"
#warning esp_deepsleep.h has been renamed to esp_sleep.h, please update include directives
#include "esp_sleep.h"

View File

@@ -0,0 +1,301 @@
// Copyright 2015-2017 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.
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "driver/gpio.h"
#include "driver/touch_pad.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Logic function used for EXT1 wakeup mode.
*/
typedef enum {
ESP_EXT1_WAKEUP_ALL_LOW = 0, //!< Wake the chip when all selected GPIOs go low
ESP_EXT1_WAKEUP_ANY_HIGH = 1 //!< Wake the chip when any of the selected GPIOs go high
} esp_sleep_ext1_wakeup_mode_t;
/**
* @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_MAX //!< Number of domains
} esp_sleep_pd_domain_t;
/**
* @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;
/**
* @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_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_cause_t;
/**
* @brief Enable wakeup by ULP coprocessor
* @note In revisions 0 and 1 of the ESP32, ULP wakeup source
* can not be used when RTC_PERIPH power domain is forced
* to be powered on (ESP_PD_OPTION_ON) or when ext0 wakeup
* source is used.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if ULP co-processor is not enabled or if wakeup triggers conflict
*/
esp_err_t esp_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_sleep_enable_timer_wakeup(uint64_t time_in_us);
/**
* @brief Enable wakeup by touch sensor
*
* @note In revisions 0 and 1 of the ESP32, touch wakeup source
* can not be used when RTC_PERIPH power domain is forced
* to be powered on (ESP_PD_OPTION_ON) or when ext0 wakeup
* source is used.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if wakeup triggers conflict
*/
esp_err_t esp_sleep_enable_touchpad_wakeup();
/**
* @brief Get the touch pad which caused wakeup
*
* If wakeup was caused by another source, this function will return TOUCH_PAD_MAX;
*
* @return touch pad which caused wakeup
*/
touch_pad_t esp_sleep_get_touchpad_wakeup_status();
/**
* @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 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.
*
* @note This function does not modify pin configuration. The pin is
* configured in esp_sleep_start, immediately before entering sleep mode.
*
* @note In revisions 0 and 1 of the ESP32, ext0 wakeup source
* can not be used together with touch or ULP wakeup sources.
*
* @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 the selected GPIO is not an RTC GPIO,
* or the mode is invalid
* - ESP_ERR_INVALID_STATE if wakeup triggers conflict
*/
esp_err_t esp_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 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 mode argument,
* the chip will be woken up.
*
* @note This function does not modify pin configuration. The pins are
* configured in esp_sleep_start, immediately before
* entering sleep mode.
*
* @note internal pullups and pulldowns don't work when RTC peripherals are
* shut down. In this case, external resistors need to be added.
* Alternatively, RTC peripherals (and pullups/pulldowns) may be
* kept enabled using esp_sleep_pd_config function.
*
* @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:
* - ESP_EXT1_WAKEUP_ALL_LOW: wake up when all selected GPIOs are low
* - ESP_EXT1_WAKEUP_ANY_HIGH: wake up when any of the selected GPIOs is high
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if any of the selected GPIOs is not an RTC GPIO,
* or mode is invalid
*/
esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_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_sleep_get_ext1_wakeup_status();
/**
* @brief Set power down mode for an RTC power domain in sleep mode
*
* If not set set using this API, all power domains default to ESP_PD_OPTION_AUTO.
*
* @param domain power domain to configure
* @param option power down option (ESP_PD_OPTION_OFF, ESP_PD_OPTION_ON, or ESP_PD_OPTION_AUTO)
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if either of the arguments is out of range
*/
esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain,
esp_sleep_pd_option_t option);
/**
* @brief Enter deep sleep with the configured wakeup options
*
* This function does not return.
*/
void esp_deep_sleep_start() __attribute__((noreturn));
/**
* @brief Enter light sleep with the configured wakeup options
*
* @return
* - ESP_OK on success (returned after wakeup)
* - ESP_ERR_INVALID_STATE if WiFi or BT is not stopped
*/
esp_err_t esp_light_sleep_start();
/**
* @brief Enter deep-sleep mode
*
* The device will automatically wake up after the deep-sleep time
* 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.
*
* esp_deep_sleep does not shut down WiFi, BT, and higher level protocol
* connections gracefully.
* Make sure relevant WiFi and BT stack functions are called to close any
* connections and deinitialize the peripherals. These include:
* - esp_bluedroid_disable
* - esp_bt_controller_disable
* - esp_wifi_stop
*
* 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 Enter deep-sleep mode
*
* Function has been renamed to esp_deep_sleep.
* This name is deprecated and will be removed in a future version.
*
* @param time_in_us deep-sleep time, unit: microsecond
*/
void system_deep_sleep(uint64_t time_in_us) __attribute__((noreturn, deprecated));
/**
* @brief Get the source which caused wakeup from sleep
*
* @return wakeup cause, or ESP_DEEP_SLEEP_WAKEUP_UNDEFINED if reset happened for reason other than deep sleep wakeup
*/
esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause();
/**
* @brief Default stub to run on wake from deep sleep.
*
* Allows for executing code immediately on wake from sleep, before
* the software bootloader or ESP-IDF app has started up.
*
* This function is weak-linked, so you can implement your own version
* to run code immediately when the chip wakes from
* sleep.
*
* See docs/deep-sleep-stub.rst for details.
*/
void esp_wake_deep_sleep(void);
/**
* @brief Function type for stub to run on wake from sleep.
*
*/
typedef void (*esp_deep_sleep_wake_stub_fn_t)(void);
/**
* @brief Install a new stub at runtime to run on wake from deep sleep
*
* If implementing esp_wake_deep_sleep() then it is not necessary to
* call this function.
*
* However, it is possible to call this function to substitute a
* different deep sleep stub. Any function used as a deep sleep stub
* must be marked RTC_IRAM_ATTR, and must obey the same rules given
* for esp_wake_deep_sleep().
*/
void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub);
/**
* @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);
/**
* @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);
#ifdef __cplusplus
}
#endif

View File

@@ -18,7 +18,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "esp_deep_sleep.h"
#include "esp_sleep.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -1,4 +1,4 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2015-2017 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.
@@ -14,10 +14,13 @@
#include <stddef.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_deep_sleep.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "esp_clk.h"
#include "esp_newlib.h"
#include "esp_spi_flash.h"
#include "rom/cache.h"
#include "rom/rtc.h"
#include "rom/uart.h"
@@ -25,6 +28,7 @@
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/spi_reg.h"
#include "soc/sens_reg.h"
#include "soc/dport_reg.h"
#include "driver/rtc_io.h"
@@ -32,11 +36,17 @@
#include "freertos/task.h"
#include "sdkconfig.h"
// If light sleep time is less than that, don't power down flash
#define FLASH_PD_MIN_SLEEP_TIME_US 2000
// Time from VDD_SDIO power up to first flash read in ROM code
#define VDD_SDIO_POWERUP_TO_FLASH_READ_US 700
/**
* Internal structure which holds all requested deep sleep parameters
*/
typedef struct {
esp_deep_sleep_pd_option_t pd_options[ESP_PD_DOMAIN_MAX];
esp_sleep_pd_option_t pd_options[ESP_PD_DOMAIN_MAX];
uint64_t sleep_duration;
uint32_t wakeup_triggers : 11;
uint32_t ext1_trigger_mode : 1;
@@ -54,7 +64,7 @@ static deep_sleep_config_t s_config = {
is not thread-safe. */
static _lock_t lock_rtc_memory_crc;
static const char* TAG = "deepsleep";
static const char* TAG = "sleep";
static uint32_t get_power_down_flags();
static void ext0_wakeup_prepare();
@@ -106,31 +116,17 @@ void __attribute__((weak, alias("esp_default_wake_deep_sleep"))) esp_wake_deep_s
void esp_deep_sleep(uint64_t time_in_us)
{
esp_deep_sleep_enable_timer_wakeup(time_in_us);
esp_sleep_enable_timer_wakeup(time_in_us);
esp_deep_sleep_start();
}
void IRAM_ATTR esp_deep_sleep_start()
static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
{
// Decide which power domains can be powered down
uint32_t pd_flags = get_power_down_flags();
// Shut down parts of RTC which may have been left enabled by the wireless drivers
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG,
RTC_CNTL_CKGEN_I2C_PU | RTC_CNTL_PLL_I2C_PU |
RTC_CNTL_RFRX_PBUS_PU | RTC_CNTL_TXRF_I2C_PU);
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_M, 0, SENS_FORCE_XPD_SAR_S);
// Flush UARTs so that output is not lost due to APB frequency change
uart_tx_wait_idle(0);
uart_tx_wait_idle(1);
uart_tx_wait_idle(2);
if (esp_get_deep_sleep_wake_stub() == NULL) {
esp_set_deep_sleep_wake_stub(esp_wake_deep_sleep);
}
// Configure pins for external wakeup
if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) {
ext0_wakeup_prepare();
@@ -148,10 +144,25 @@ void IRAM_ATTR esp_deep_sleep_start()
timer_wakeup_prepare();
}
// Enter deep sleep
// Enter sleep
rtc_sleep_config_t config = RTC_SLEEP_CONFIG_DEFAULT(pd_flags);
rtc_sleep_init(config);
rtc_sleep_start(s_config.wakeup_triggers, 0);
return rtc_sleep_start(s_config.wakeup_triggers, 0);
}
void IRAM_ATTR esp_deep_sleep_start()
{
// Configure wake stub
if (esp_get_deep_sleep_wake_stub() == NULL) {
esp_set_deep_sleep_wake_stub(esp_wake_deep_sleep);
}
// Decide which power domains can be powered down
uint32_t pd_flags = get_power_down_flags();
// Enter sleep
esp_sleep_start(RTC_SLEEP_PD_DIG | RTC_SLEEP_PD_VDDSDIO | pd_flags);
// Because RTC is in a slower clock domain than the CPU, it
// can take several CPU cycles for the sleep mode to start.
while (1) {
@@ -159,9 +170,101 @@ void IRAM_ATTR esp_deep_sleep_start()
}
}
static void rtc_wdt_enable(int time_ms)
{
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, 7);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_RTC);
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * time_ms / 1000);
SET_PERI_REG_MASK(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN | RTC_CNTL_WDT_PAUSE_IN_SLP);
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
}
static void rtc_wdt_disable()
{
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_OFF);
REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
}
/**
* Helper function which handles entry to and exit from light sleep
* Placed into IRAM as flash may need some time to be powered on.
*/
static esp_err_t IRAM_ATTR esp_light_sleep_inner(uint32_t pd_flags,
rtc_cpu_freq_t cpu_freq, uint32_t flash_enable_time_us)
{
// Enter sleep
esp_err_t err = esp_sleep_start(pd_flags);
// Restore CPU frequency
rtc_clk_cpu_freq_set(cpu_freq);
// If SPI flash was powered down, wait for it to become ready
if (pd_flags & RTC_SLEEP_PD_VDDSDIO) {
// Wait for the flash chip to start up
ets_delay_us(flash_enable_time_us);
}
return err;
}
esp_err_t esp_light_sleep_start()
{
static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&light_sleep_lock);
int other_cpu = xPortGetCoreID() ? 0 : 1;
esp_cpu_stall(other_cpu);
// Other CPU is stalled, need to disable DPORT protection
esp_dport_access_int_pause();
// Decide which power domains can be powered down
uint32_t pd_flags = get_power_down_flags();
// Decide if flash needs to be powered down;
// If it needs to be powered down, adjust sleep time
const uint32_t flash_enable_time_us = VDD_SDIO_POWERUP_TO_FLASH_READ_US
+ CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY;
if (s_config.sleep_duration > FLASH_PD_MIN_SLEEP_TIME_US &&
s_config.sleep_duration > flash_enable_time_us) {
pd_flags |= RTC_SLEEP_PD_VDDSDIO;
s_config.sleep_duration -= flash_enable_time_us;
}
// Safety net: enable WDT in case exit from light sleep fails
rtc_wdt_enable(1000);
// Save current CPU frequency, light sleep will switch to XTAL
rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get();
// Enter sleep, then wait for flash to be ready on wakeup
esp_err_t err = esp_light_sleep_inner(pd_flags, cpu_freq, flash_enable_time_us);
// At this point, if FRC1 is used for timekeeping, time will be lagging behind.
// This will update the microsecond count based on RTC timer.
esp_setup_time_syscalls();
// However, we do not advance RTOS ticks here; doing so would be rather messy,
// as ticks can only be advanced on CPU0.
// If this is needed by the application, automatic light sleep (tickless idle)
// will handle that better.
esp_cpu_unstall(other_cpu);
esp_dport_access_int_resume();
rtc_wdt_disable();
portEXIT_CRITICAL(&light_sleep_lock);
return err;
}
void system_deep_sleep(uint64_t) __attribute__((alias("esp_deep_sleep")));
esp_err_t esp_deep_sleep_enable_ulp_wakeup()
esp_err_t esp_sleep_enable_ulp_wakeup()
{
#ifdef CONFIG_ULP_COPROC_ENABLED
if(s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) {
@@ -175,7 +278,7 @@ esp_err_t esp_deep_sleep_enable_ulp_wakeup()
#endif
}
esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us)
esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
{
s_config.wakeup_triggers |= RTC_TIMER_TRIG_EN;
s_config.sleep_duration = time_in_us;
@@ -190,7 +293,7 @@ static void timer_wakeup_prepare()
rtc_sleep_set_wakeup_time(cur_rtc_count + rtc_count_delta);
}
esp_err_t esp_deep_sleep_enable_touchpad_wakeup()
esp_err_t esp_sleep_enable_touchpad_wakeup()
{
if (s_config.wakeup_triggers & (RTC_EXT0_TRIG_EN)) {
ESP_LOGE(TAG, "Conflicting wake-up trigger: ext0");
@@ -200,9 +303,9 @@ esp_err_t esp_deep_sleep_enable_touchpad_wakeup()
return ESP_OK;
}
touch_pad_t esp_deep_sleep_get_touchpad_wakeup_status()
touch_pad_t esp_sleep_get_touchpad_wakeup_status()
{
if (esp_deep_sleep_get_wakeup_cause() != ESP_DEEP_SLEEP_WAKEUP_TOUCHPAD) {
if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_TOUCHPAD) {
return TOUCH_PAD_MAX;
}
uint32_t touch_mask = REG_GET_FIELD(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN);
@@ -210,7 +313,7 @@ touch_pad_t esp_deep_sleep_get_touchpad_wakeup_status()
return (touch_pad_t) (__builtin_ffs(touch_mask) - 1);
}
esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level)
esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level)
{
if (level < 0 || level > 1) {
return ESP_ERR_INVALID_ARG;
@@ -249,7 +352,7 @@ static void ext0_wakeup_prepare()
}
}
esp_err_t esp_deep_sleep_enable_ext1_wakeup(uint64_t mask, esp_ext1_wakeup_mode_t mode)
esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode)
{
if (mode > ESP_EXT1_WAKEUP_ANY_HIGH) {
return ESP_ERR_INVALID_ARG;
@@ -311,9 +414,9 @@ static void ext1_wakeup_prepare()
s_config.ext1_trigger_mode, RTC_CNTL_EXT_WAKEUP1_LV_S);
}
uint64_t esp_deep_sleep_get_ext1_wakeup_status()
uint64_t esp_sleep_get_ext1_wakeup_status()
{
if (esp_deep_sleep_get_wakeup_cause() != ESP_DEEP_SLEEP_WAKEUP_EXT1) {
if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_EXT1) {
return 0;
}
uint32_t status = REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS);
@@ -332,30 +435,30 @@ uint64_t esp_deep_sleep_get_ext1_wakeup_status()
return gpio_mask;
}
esp_deep_sleep_wakeup_cause_t esp_deep_sleep_get_wakeup_cause()
esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause()
{
if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) {
return ESP_DEEP_SLEEP_WAKEUP_UNDEFINED;
return ESP_SLEEP_WAKEUP_UNDEFINED;
}
uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE);
if (wakeup_cause & RTC_EXT0_TRIG_EN) {
return ESP_DEEP_SLEEP_WAKEUP_EXT0;
return ESP_SLEEP_WAKEUP_EXT0;
} else if (wakeup_cause & RTC_EXT1_TRIG_EN) {
return ESP_DEEP_SLEEP_WAKEUP_EXT1;
return ESP_SLEEP_WAKEUP_EXT1;
} else if (wakeup_cause & RTC_TIMER_TRIG_EN) {
return ESP_DEEP_SLEEP_WAKEUP_TIMER;
return ESP_SLEEP_WAKEUP_TIMER;
} else if (wakeup_cause & RTC_TOUCH_TRIG_EN) {
return ESP_DEEP_SLEEP_WAKEUP_TOUCHPAD;
return ESP_SLEEP_WAKEUP_TOUCHPAD;
} else if (wakeup_cause & RTC_ULP_TRIG_EN) {
return ESP_DEEP_SLEEP_WAKEUP_ULP;
return ESP_SLEEP_WAKEUP_ULP;
} else {
return ESP_DEEP_SLEEP_WAKEUP_UNDEFINED;
return ESP_SLEEP_WAKEUP_UNDEFINED;
}
}
esp_err_t esp_deep_sleep_pd_config(esp_deep_sleep_pd_domain_t domain,
esp_deep_sleep_pd_option_t option)
esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain,
esp_sleep_pd_option_t option)
{
if (domain >= ESP_PD_DOMAIN_MAX || option > ESP_PD_OPTION_AUTO) {
return ESP_ERR_INVALID_ARG;
@@ -410,7 +513,7 @@ static uint32_t get_power_down_flags()
option_str[s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM]]);
// Prepare flags based on the selected options
uint32_t pd_flags = RTC_SLEEP_PD_DIG;
uint32_t pd_flags = 0;
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_FAST_MEM;
}

View File

@@ -1,5 +1,6 @@
#include "unity.h"
#include "esp_deep_sleep.h"
#include <sys/time.h>
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@@ -25,15 +26,27 @@ static void do_deep_sleep_from_app_cpu()
}
}
TEST_CASE("wake up using timer", "[deepsleep][ignore]")
TEST_CASE("wake up from deep sleep using timer", "[deepsleep][ignore]")
{
esp_deep_sleep_enable_timer_wakeup(2000000);
esp_sleep_enable_timer_wakeup(2000000);
esp_deep_sleep_start();
}
TEST_CASE("wake up from light sleep using timer", "[deepsleep]")
{
esp_sleep_enable_timer_wakeup(2000000);
struct timeval tv_start, tv_stop;
gettimeofday(&tv_start, NULL);
esp_light_sleep_start();
gettimeofday(&tv_stop, NULL);
float dt = (tv_stop.tv_sec - tv_start.tv_sec) * 1e3f +
(tv_stop.tv_usec - tv_start.tv_usec) * 1e-3f;
TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt);
}
TEST_CASE("enter deep sleep on APP CPU and wake up using timer", "[deepsleep][ignore]")
{
esp_deep_sleep_enable_timer_wakeup(2000000);
esp_sleep_enable_timer_wakeup(2000000);
do_deep_sleep_from_app_cpu();
}
@@ -43,7 +56,7 @@ TEST_CASE("wake up using ext0 (13 high)", "[deepsleep][ignore]")
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_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 1));
esp_deep_sleep_start();
}
@@ -52,7 +65,7 @@ TEST_CASE("wake up using ext0 (13 low)", "[deepsleep][ignore]")
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_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0));
esp_deep_sleep_start();
}
@@ -60,7 +73,7 @@ TEST_CASE("wake up using ext1 when RTC_PERIPH is off (13 high)", "[deepsleep][ig
{
// This test needs external pulldown
ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13));
ESP_ERROR_CHECK(esp_deep_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), ESP_EXT1_WAKEUP_ANY_HIGH));
ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), ESP_EXT1_WAKEUP_ANY_HIGH));
esp_deep_sleep_start();
}
@@ -68,7 +81,7 @@ TEST_CASE("wake up using ext1 when RTC_PERIPH is off (13 low)", "[deepsleep][ign
{
// This test needs external pullup
ESP_ERROR_CHECK(rtc_gpio_init(GPIO_NUM_13));
ESP_ERROR_CHECK(esp_deep_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), ESP_EXT1_WAKEUP_ALL_LOW));
ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), ESP_EXT1_WAKEUP_ALL_LOW));
esp_deep_sleep_start();
}
@@ -77,8 +90,8 @@ TEST_CASE("wake up using ext1 when RTC_PERIPH is on (13 high)", "[deepsleep][ign
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_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON));
ESP_ERROR_CHECK(esp_deep_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), ESP_EXT1_WAKEUP_ANY_HIGH));
ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON));
ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), ESP_EXT1_WAKEUP_ANY_HIGH));
esp_deep_sleep_start();
}
@@ -87,7 +100,7 @@ TEST_CASE("wake up using ext1 when RTC_PERIPH is on (13 low)", "[deepsleep][igno
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_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON));
ESP_ERROR_CHECK(esp_deep_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), ESP_EXT1_WAKEUP_ALL_LOW));
ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON));
ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), ESP_EXT1_WAKEUP_ALL_LOW));
esp_deep_sleep_start();
}