mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-09 12:35:28 +00:00
esp32: Deactivate wakeup trigger after first wakeup
Added function esp_sleep_disable_wakeup_source() to deactivate wakeup trigger for selected source. Updated documentation for this function in sleep_modes.rst file. Updated unit test to check this functionality for light sleep. The test_sleep.c unit test is updated to add reliability for unit testing. (TW#18952) Closes https://github.com/espressif/esp-idf/issues/1677
This commit is contained in:
@@ -37,6 +37,11 @@ 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;
|
||||
|
||||
inline static esp_err_t esp_deep_sleep_disable_wakeup_source(esp_sleep_source_t source)
|
||||
{
|
||||
return esp_sleep_disable_wakeup_source(source);
|
||||
}
|
||||
|
||||
inline static esp_err_t esp_deep_sleep_enable_ulp_wakeup(void)
|
||||
{
|
||||
return esp_sleep_enable_ulp_wakeup();
|
||||
@@ -47,11 +52,6 @@ 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);
|
||||
}
|
||||
|
||||
inline static esp_err_t esp_deep_sleep_disable_timer_wakeup(void)
|
||||
{
|
||||
return esp_sleep_disable_timer_wakeup();
|
||||
}
|
||||
|
||||
inline static esp_err_t esp_deep_sleep_enable_touchpad_wakeup(void)
|
||||
{
|
||||
return esp_sleep_enable_touchpad_wakeup();
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/touch_pad.h"
|
||||
#include "soc/rtc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -62,6 +63,35 @@ typedef enum {
|
||||
ESP_SLEEP_WAKEUP_ULP, //!< Wakeup caused by ULP program
|
||||
} esp_sleep_wakeup_cause_t;
|
||||
|
||||
/**
|
||||
* @brief Sleep wakeup sources for esp_sleep_disable_wakeup_source function
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_SLEEP_SOURCE_UNDEFINED, //!< Wakeup source is not defined
|
||||
ESP_SLEEP_SOURCE_EXT0, //!< Wakeup source for external signal using RTC_IO
|
||||
ESP_SLEEP_SOURCE_EXT1, //!< Wakeup source for external signal using RTC_CNTL
|
||||
ESP_SLEEP_SOURCE_TIMER, //!< Wakeup source for timer
|
||||
ESP_SLEEP_SOURCE_TOUCHPAD, //!< Wakeup source for touchpad
|
||||
ESP_SLEEP_SOURCE_ULP, //!< Wakeup source for ULP program
|
||||
} esp_sleep_source_t;
|
||||
|
||||
/**
|
||||
* @brief Disable wakeup source
|
||||
*
|
||||
* This function is used to deactivate wake up trigger for source
|
||||
* defined as parameter of the function.
|
||||
*
|
||||
* @note This function does not modify wake up configuration in RTC.
|
||||
* It will be performed in esp_sleep_start function.
|
||||
*
|
||||
* See docs/sleep-modes.rst for details.
|
||||
*
|
||||
* @param source - number of source to disable of type esp_sleep_source_t
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if trigger was not active
|
||||
*/
|
||||
esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source);
|
||||
|
||||
/**
|
||||
* @brief Enable wakeup by ULP coprocessor
|
||||
@@ -75,7 +105,7 @@ typedef enum {
|
||||
*/
|
||||
esp_err_t esp_sleep_enable_ulp_wakeup();
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Enable wakeup by timer
|
||||
* @param time_in_us time before wakeup, in microseconds
|
||||
* @return
|
||||
@@ -84,23 +114,6 @@ esp_err_t esp_sleep_enable_ulp_wakeup();
|
||||
*/
|
||||
esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us);
|
||||
|
||||
/**
|
||||
* @brief Disable timer wakeup
|
||||
*
|
||||
* This function is used to deactivate timer wakeup trigger
|
||||
* after first sleep for example to allow wakeup from other sources.
|
||||
*
|
||||
* @note This function does not modify wakeup configuration in RTC.
|
||||
* It will be performed in esp_sleep_start function.
|
||||
*
|
||||
* See docs/sleep-modes.rst for details.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if trigger was not active
|
||||
*/
|
||||
esp_err_t esp_sleep_disable_timer_wakeup();
|
||||
|
||||
/**
|
||||
* @brief Enable wakeup by touch sensor
|
||||
*
|
||||
|
@@ -42,6 +42,9 @@
|
||||
// Time from VDD_SDIO power up to first flash read in ROM code
|
||||
#define VDD_SDIO_POWERUP_TO_FLASH_READ_US 700
|
||||
|
||||
#define CHECK_SOURCE(source, value, mask) ((s_config.wakeup_triggers & mask) && \
|
||||
(source == value))
|
||||
|
||||
/**
|
||||
* Internal structure which holds all requested deep sleep parameters
|
||||
*/
|
||||
@@ -282,6 +285,43 @@ esp_err_t esp_light_sleep_start()
|
||||
|
||||
void system_deep_sleep(uint64_t) __attribute__((alias("esp_deep_sleep")));
|
||||
|
||||
esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source)
|
||||
{
|
||||
// For most of sources it is enough to set trigger mask in local
|
||||
// configuration structure. The actual RTC wake up options
|
||||
// will be updated by esp_sleep_start().
|
||||
if (CHECK_SOURCE(source, ESP_SLEEP_SOURCE_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_SOURCE_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_SOURCE_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_SOURCE_TOUCHPAD, RTC_TOUCH_TRIG_EN)) {
|
||||
s_config.wakeup_triggers &= ~RTC_TOUCH_TRIG_EN;
|
||||
}
|
||||
#ifdef CONFIG_ULP_COPROC_ENABLED
|
||||
else if (CHECK_SOURCE(source, ESP_SLEEP_SOURCE_ULP, RTC_ULP_TRIG_EN)) {
|
||||
// The ulp wake up option is disabled immediately
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_WAKEUP_FORCE_EN);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
|
||||
s_config.wakeup_triggers &= ~RTC_ULP_TRIG_EN;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
ESP_LOGE(TAG, "Incorrect wakeup source (%d) to disable.", (int) source);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_sleep_enable_ulp_wakeup()
|
||||
{
|
||||
#ifdef CONFIG_ULP_COPROC_ENABLED
|
||||
@@ -303,22 +343,6 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_sleep_disable_timer_wakeup()
|
||||
{
|
||||
if (s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) {
|
||||
// The only timer wakeup trigger should be disabled, setup will
|
||||
// be performed in rtc_sleep_start() which updates wakeup options
|
||||
// in RTC peripheral registers
|
||||
s_config.wakeup_triggers &= ~RTC_TIMER_TRIG_EN;
|
||||
s_config.sleep_duration = 0;
|
||||
}
|
||||
else {
|
||||
ESP_LOGE(TAG, "The timer wake-up trigger is not set.");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void timer_wakeup_prepare()
|
||||
{
|
||||
uint32_t period = esp_clk_slowclk_cal_get();
|
||||
|
@@ -5,9 +5,27 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "soc/rtc_cntl_reg.h" // for read rtc registers directly (cause)
|
||||
#include "soc/soc.h"
|
||||
|
||||
#define ESP_EXT0_WAKEUP_LEVEL_LOW 0
|
||||
#define ESP_EXT0_WAKEUP_LEVEL_HIGH 1
|
||||
|
||||
// These are flags for wakeup cause to get it directly from RTC
|
||||
#define RTC_EXT0_TRIG_EN BIT(0) //!< EXT0 GPIO wakeup
|
||||
#define RTC_EXT1_TRIG_EN BIT(1) //!< EXT1 GPIO wakeup
|
||||
#define RTC_GPIO_TRIG_EN BIT(2) //!< GPIO wakeup (light sleep only)
|
||||
#define RTC_TIMER_TRIG_EN BIT(3) //!< Timer wakeup
|
||||
#define RTC_SDIO_TRIG_EN BIT(4) //!< SDIO wakeup (light sleep only)
|
||||
#define RTC_MAC_TRIG_EN BIT(5) //!< MAC wakeup (light sleep only)
|
||||
#define RTC_UART0_TRIG_EN BIT(6) //!< UART0 wakeup (light sleep only)
|
||||
#define RTC_UART1_TRIG_EN BIT(7) //!< UART1 wakeup (light sleep only)
|
||||
#define RTC_TOUCH_TRIG_EN BIT(8) //!< Touch wakeup
|
||||
#define RTC_ULP_TRIG_EN BIT(9) //!< ULP wakeup
|
||||
#define RTC_BT_TRIG_EN BIT(10) //!< BT wakeup (light sleep only)
|
||||
|
||||
static struct timeval tv_start, tv_stop;
|
||||
|
||||
TEST_CASE("esp_deepsleep works", "[deepsleep][reset=DEEPSLEEP_RESET]")
|
||||
{
|
||||
esp_deep_sleep(2000000);
|
||||
@@ -48,44 +66,6 @@ TEST_CASE("wake up from light sleep using timer", "[deepsleep]")
|
||||
TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt);
|
||||
}
|
||||
|
||||
TEST_CASE("wake up disable timer for ext0 wakeup (13 low)", "[deepsleep][ignore]")
|
||||
{
|
||||
// Setup timer to wakeup with timeout
|
||||
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;
|
||||
printf("Timer sleep time = %d\r\n", (int)dt);
|
||||
|
||||
TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt);
|
||||
|
||||
// Setup ext0 configuration to wake up
|
||||
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_sleep_enable_ext0_wakeup(GPIO_NUM_13, ESP_EXT0_WAKEUP_LEVEL_LOW));
|
||||
|
||||
// Disable timer wakeup trigger to wakeup from ext0 source
|
||||
// instead of timer wakeup
|
||||
ESP_ERROR_CHECK(esp_sleep_disable_timer_wakeup());
|
||||
printf("Waiting low level on GPIO_13\r\n");
|
||||
|
||||
gettimeofday(&tv_start, NULL);
|
||||
esp_light_sleep_start();
|
||||
gettimeofday(&tv_stop, NULL);
|
||||
|
||||
dt = (tv_stop.tv_sec - tv_start.tv_sec) * 1e3f +
|
||||
(tv_stop.tv_usec - tv_start.tv_usec) * 1e-3f;
|
||||
printf("Ext0 sleep time = %d\r\n", (int)dt);
|
||||
|
||||
// Check error message
|
||||
esp_err_t err_code = esp_sleep_disable_timer_wakeup();
|
||||
TEST_ASSERT(err_code == ESP_ERR_INVALID_STATE);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
TEST_CASE("enter deep sleep on APP CPU and wake up using timer", "[deepsleep][reset=DEEPSLEEP_RESET]")
|
||||
{
|
||||
@@ -148,3 +128,90 @@ TEST_CASE("wake up using ext1 when RTC_PERIPH is on (13 low)", "[deepsleep][igno
|
||||
ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(BIT(GPIO_NUM_13), ESP_EXT1_WAKEUP_ALL_LOW));
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
static float get_time(void)
|
||||
{
|
||||
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;
|
||||
return abs(dt);
|
||||
}
|
||||
|
||||
static uint32_t get_cause()
|
||||
{
|
||||
uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, \
|
||||
RTC_CNTL_WAKEUP_CAUSE);
|
||||
return wakeup_cause;
|
||||
}
|
||||
|
||||
// This test case verifies deactivation of trigger for wake up sources
|
||||
TEST_CASE("disable source behavior", "[deepsleep][ignore]")
|
||||
{
|
||||
float dt = 0;
|
||||
|
||||
printf("Setup timer and ext0 to wakeup imediately from GPIO_13 \n");
|
||||
|
||||
// Setup ext0 configuration to wake up almost immediately
|
||||
// The wakeup time is proportional to input capacitance * pullup resistance
|
||||
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_sleep_enable_ext0_wakeup(GPIO_NUM_13, ESP_EXT0_WAKEUP_LEVEL_HIGH));
|
||||
|
||||
// Setup timer to wakeup with timeout
|
||||
esp_sleep_enable_timer_wakeup(2000000);
|
||||
|
||||
// Save start time
|
||||
gettimeofday(&tv_start, NULL);
|
||||
esp_light_sleep_start();
|
||||
|
||||
dt = get_time();
|
||||
printf("Ext0 sleep time = %d \n", (int) dt);
|
||||
|
||||
// Check wakeup from Ext0 using time measurement because wakeup cause is
|
||||
// not available in light sleep mode
|
||||
TEST_ASSERT_INT32_WITHIN(297, 300, (int) dt);
|
||||
|
||||
TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0);
|
||||
|
||||
// Disable Ext0 source. Timer source should be triggered
|
||||
ESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_SOURCE_EXT0));
|
||||
printf("Disable ext0 source leave timer active.\n");
|
||||
|
||||
gettimeofday(&tv_start, NULL);
|
||||
esp_light_sleep_start();
|
||||
|
||||
dt = get_time();
|
||||
printf("Timer sleep time = %d \n", (int) dt);
|
||||
|
||||
TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt);
|
||||
|
||||
// Additionaly check wakeup cause
|
||||
TEST_ASSERT((get_cause() & RTC_TIMER_TRIG_EN) != 0);
|
||||
|
||||
// Disable timer source.
|
||||
ESP_ERROR_CHECK(esp_sleep_disable_wakeup_source(ESP_SLEEP_SOURCE_TIMER));
|
||||
|
||||
// Setup ext0 configuration to wake up immediately
|
||||
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_sleep_enable_ext0_wakeup(GPIO_NUM_13, ESP_EXT0_WAKEUP_LEVEL_HIGH));
|
||||
|
||||
printf("Disable timer and wake up from ext0 source.\n");
|
||||
|
||||
gettimeofday(&tv_start, NULL);
|
||||
esp_light_sleep_start();
|
||||
|
||||
dt = get_time();
|
||||
printf("Ext0 sleep time = %d \n", (int) dt);
|
||||
|
||||
TEST_ASSERT_INT32_WITHIN(198, 200, (int) dt);
|
||||
TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0);
|
||||
|
||||
// Check error message when source is already disabled
|
||||
esp_err_t err_code = esp_sleep_disable_wakeup_source(ESP_SLEEP_SOURCE_TIMER);
|
||||
TEST_ASSERT(err_code == ESP_ERR_INVALID_STATE);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user