Merge branch 'feature/esp32c3_deep_sleep_rtcfastmem' into 'master'

esp32c3: Finish deep sleep support

Closes IDF-2560

See merge request espressif/esp-idf!12031
This commit is contained in:
Michael (XIAO Xufeng) 2021-01-26 12:53:34 +08:00
commit d741b08fe7
7 changed files with 135 additions and 14 deletions

View File

@ -24,8 +24,10 @@
#include "soc/nrx_reg.h"
#include "soc/fe_reg.h"
#include "soc/timer_group_reg.h"
#include "soc/system_reg.h"
#include "soc/rtc.h"
#include "esp32c3/rom/ets_sys.h"
#include "esp32c3/rom/rtc.h"
#include "regi2c_ctrl.h"
/**
@ -140,6 +142,8 @@ void rtc_sleep_set_wakeup_time(uint64_t t)
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32);
}
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu);
uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu)
{
REG_SET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_ENA, wakeup_opt);
@ -152,6 +156,88 @@ uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp
RTC_CNTL_SLP_REJECT_INT_RAW | RTC_CNTL_SLP_WAKEUP_INT_RAW) == 0) {
;
}
return rtc_sleep_finish(lslp_mem_inf_fpu);
}
#define STR2(X) #X
#define STR(X) STR2(X)
uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
{
REG_SET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_ENA, wakeup_opt);
WRITE_PERI_REG(RTC_CNTL_SLP_REJECT_CONF_REG, reject_opt);
/* Calculate RTC Fast Memory CRC (for wake stub) & go to deep sleep
Because we may be running from RTC memory as stack, we can't easily call any
functions to do this (as registers will spill to stack, corrupting the CRC).
Instead, load all the values we need into registers then use register ops only to calculate
the CRC value, write it to the RTC CRC value register, and immediately go into deep sleep.
*/
/* Values used to set the SYSTEM_RTC_FASTMEM_CONFIG_REG value */
const unsigned CRC_START_ADDR = 0;
const unsigned CRC_LEN = 0x7ff;
asm volatile(
/* Start CRC calculation */
"sw %1, 0(%0)\n" // set RTC_MEM_CRC_ADDR & RTC_MEM_CRC_LEN
"or t0, %1, %2\n"
"sw t0, 0(%0)\n" // set RTC_MEM_CRC_START
/* Wait for the CRC calculation to finish */
".Lwaitcrc:\n"
"fence\n"
"lw t0, 0(%0)\n"
"li t1, "STR(SYSTEM_RTC_MEM_CRC_FINISH)"\n"
"and t0, t0, t1\n"
"beqz t0, .Lwaitcrc\n"
"not %2, %2\n" // %2 -> ~DPORT_RTC_MEM_CRC_START
"and t0, t0, %2\n"
"sw t0, 0(%0)\n" // clear RTC_MEM_CRC_START
"fence\n"
"not %2, %2\n" // %2 -> DPORT_RTC_MEM_CRC_START, probably unnecessary but gcc assumes inputs unchanged
/* Store the calculated value in RTC_MEM_CRC_REG */
"lw t0, 0(%3)\n"
"sw t0, 0(%4)\n"
"fence\n"
/* Set register bit to go into deep sleep */
"lw t0, 0(%5)\n"
"or t0, t0, %6\n"
"sw t0, 0(%5)\n"
"fence\n"
/* Wait for sleep reject interrupt (never finishes if successful) */
".Lwaitsleep:"
"fence\n"
"lw t0, 0(%7)\n"
"and t0, t0, %8\n"
"beqz t0, .Lwaitsleep\n"
:
:
"r" (SYSTEM_RTC_FASTMEM_CONFIG_REG), // %0
"r" ( (CRC_START_ADDR << SYSTEM_RTC_MEM_CRC_START_S)
| (CRC_LEN << SYSTEM_RTC_MEM_CRC_LEN_S)), // %1
"r" (SYSTEM_RTC_MEM_CRC_START), // %2
"r" (SYSTEM_RTC_FASTMEM_CRC_REG), // %3
"r" (RTC_MEMORY_CRC_REG), // %4
"r" (RTC_CNTL_STATE0_REG), // %5
"r" (RTC_CNTL_SLEEP_EN), // %6
"r" (RTC_CNTL_INT_RAW_REG), // %7
"r" (RTC_CNTL_SLP_REJECT_INT_RAW | RTC_CNTL_SLP_WAKEUP_INT_RAW) // %8
: "t0", "t1" // working registers
);
return rtc_sleep_finish(0);
}
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);
SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG,
@ -164,8 +250,3 @@ uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp
}
return reject;
}
uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
{
abort(); // ESP32-C3 TODO IDF-2560
}

View File

@ -95,6 +95,7 @@ typedef esp_sleep_source_t esp_sleep_wakeup_cause_t;
*/
esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source);
#if SOC_ULP_SUPPORTED
/**
* @brief Enable wakeup by ULP coprocessor
* @note In revisions 0 and 1 of the ESP32, ULP wakeup source
@ -108,6 +109,8 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source);
*/
esp_err_t esp_sleep_enable_ulp_wakeup(void);
#endif // SOC_ULP_SUPPORTED
/**
* @brief Enable wakeup by timer
* @param time_in_us time before wakeup, in microseconds
@ -117,6 +120,8 @@ esp_err_t esp_sleep_enable_ulp_wakeup(void);
*/
esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us);
#if SOC_TOUCH_SENSOR_NUM > 0
/**
* @brief Enable wakeup by touch sensor
*
@ -144,6 +149,10 @@ esp_err_t esp_sleep_enable_touchpad_wakeup(void);
*/
touch_pad_t esp_sleep_get_touchpad_wakeup_status(void);
#endif // SOC_TOUCH_SENSOR_NUM > 0
#if SOC_PM_SUPPORT_EXT_WAKEUP
/**
* @brief Returns true if a GPIO number is valid for use as wakeup source.
*
@ -213,6 +222,8 @@ 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);
#endif // SOC_PM_SUPPORT_EXT_WAKEUP
/**
* @brief Enable wakeup from light sleep using GPIOs
*

View File

@ -227,7 +227,7 @@ static void IRAM_ATTR flush_uarts(void)
for (int i = 0; i < SOC_UART_NUM; ++i) {
#ifdef CONFIG_IDF_TARGET_ESP32
esp_rom_uart_tx_wait_idle(i);
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#else
if (periph_ll_periph_enabled(PERIPH_UART0_MODULE + i)) {
esp_rom_uart_tx_wait_idle(i);
}
@ -789,6 +789,7 @@ static void touch_wakeup_prepare(void)
#endif
#if SOC_TOUCH_SENSOR_NUM > 0
esp_err_t esp_sleep_enable_touchpad_wakeup(void)
{
#if ((defined CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT) || (defined CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT_V2))
@ -813,18 +814,20 @@ touch_pad_t esp_sleep_get_touchpad_wakeup_status(void)
assert(ret == ESP_OK && "wakeup reason is RTC_TOUCH_TRIG_EN but SENS_TOUCH_MEAS_EN is zero");
return pad_num;
}
#endif // SOC_TOUCH_SENSOR_NUM > 0
#if SOC_PM_SUPPORT_EXT_WAKEUP
bool esp_sleep_is_valid_wakeup_gpio(gpio_num_t gpio_num)
{
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
return RTC_GPIO_IS_VALID_GPIO(gpio_num);
#else
return GPIO_IS_VALID_GPIO(gpio_num);
#endif
#endif // SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
}
#if SOC_PM_SUPPORT_EXT_WAKEUP
esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level)
{
if (level < 0 || level > 1) {
@ -931,6 +934,7 @@ uint64_t esp_sleep_get_ext1_wakeup_status(void)
}
return gpio_mask;
}
#endif // SOC_PM_SUPPORT_EXT_WAKEUP
esp_err_t esp_sleep_enable_gpio_wakeup(void)

View File

@ -81,7 +81,7 @@ TEST_CASE("reset reason ESP_RST_POWERON", "[reset][ignore]")
TEST_ASSERT_EQUAL(ESP_RST_POWERON, esp_reset_reason());
}
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3, ESP32C3) // TODO ESP32-C3 IDF-2560
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)
static void do_deep_sleep(void)
{
setup_values();
@ -104,7 +104,7 @@ static void check_reset_reason_deep_sleep(void)
TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_DEEPSLEEP", "[reset_reason][reset="DEEPSLEEP"]",
do_deep_sleep,
check_reset_reason_deep_sleep);
#endif // TODO ESP32-C3 IDF-2560
#endif // TEMPORARY_DISABLED_FOR_TARGETS
static void do_exception(void)
{

View File

@ -190,8 +190,10 @@ static void register_tasks(void)
static struct {
struct arg_int *wakeup_time;
#if SOC_PM_SUPPORT_EXT_WAKEUP
struct arg_int *wakeup_gpio_num;
struct arg_int *wakeup_gpio_level;
#endif
struct arg_end *end;
} deep_sleep_args;
@ -208,6 +210,8 @@ static int deep_sleep(int argc, char **argv)
ESP_LOGI(TAG, "Enabling timer wakeup, timeout=%lluus", timeout);
ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) );
}
#if SOC_PM_SUPPORT_EXT_WAKEUP
if (deep_sleep_args.wakeup_gpio_num->count) {
int io_num = deep_sleep_args.wakeup_gpio_num->ival[0];
if (!esp_sleep_is_valid_wakeup_gpio(io_num)) {
@ -226,26 +230,36 @@ static int deep_sleep(int argc, char **argv)
io_num, level ? "HIGH" : "LOW");
ESP_ERROR_CHECK( esp_sleep_enable_ext1_wakeup(1ULL << io_num, level) );
ESP_LOGE(TAG, "GPIO wakeup from deep sleep currently unsupported on ESP32-C3");
}
#endif // SOC_PM_SUPPORT_EXT_WAKEUP
rtc_gpio_isolate(GPIO_NUM_12);
esp_deep_sleep_start();
}
static void register_deep_sleep(void)
{
int num_args = 1;
deep_sleep_args.wakeup_time =
arg_int0("t", "time", "<t>", "Wake up time, ms");
#if SOC_PM_SUPPORT_EXT_WAKEUP
deep_sleep_args.wakeup_gpio_num =
arg_int0(NULL, "io", "<n>",
"If specified, wakeup using GPIO with given number");
deep_sleep_args.wakeup_gpio_level =
arg_int0(NULL, "io_level", "<0|1>", "GPIO level to trigger wakeup");
deep_sleep_args.end = arg_end(3);
num_args += 2;
#endif
deep_sleep_args.end = arg_end(num_args);
const esp_console_cmd_t cmd = {
.command = "deep_sleep",
.help = "Enter deep sleep mode. "
#if SOC_PM_SUPPORT_EXT_WAKEUP
"Two wakeup modes are supported: timer and GPIO. "
#else
"Timer wakeup mode is supported. "
#endif
"If no wakeup option is specified, will sleep indefinitely.",
.hint = NULL,
.func = &deep_sleep,

View File

@ -3,6 +3,7 @@ menu "Example Configuration"
config EXAMPLE_TOUCH_WAKEUP
bool "Enable touch wake up"
default y
depends on !IDF_TARGET_ESP32C3
help
This option enables wake up from deep sleep using touch pads
TOUCH8 and TOUCH9, which correspond to GPIO33 and GPIO32.
@ -10,6 +11,7 @@ menu "Example Configuration"
config EXAMPLE_ULP_TEMPERATURE_WAKEUP
bool "Enable temperature monitoring by ULP"
default y
depends on IDF_TARGET_ESP32
help
This option enables wake up from deep sleep using ULP.
ULP program monitors the on-chip temperature sensor and
@ -20,6 +22,7 @@ menu "Example Configuration"
config EXAMPLE_EXT1_WAKEUP
bool "Enable wakeup from GPIO"
default y
depends on !IDF_TARGET_ESP32C3
help
This option enables wake up from deep sleep from GPIO2 and GPIO4. They should be connected to LOW to avoid
floating pins. When triggering a wake up, connect one or both of the pins to HIGH. Note that floating

View File

@ -12,17 +12,25 @@
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "esp32/ulp.h"
#include "driver/touch_pad.h"
#include "driver/adc.h"
#include "driver/rtc_io.h"
#include "soc/sens_periph.h"
#include "soc/rtc.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/ulp.h"
#endif
#if SOC_TOUCH_SENSOR_NUM > 0
#include "soc/sens_periph.h"
#include "driver/touch_pad.h"
#endif
static RTC_DATA_ATTR struct timeval sleep_enter_time;
#ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP