Эх сурвалжийг харах

Merge branch 'feature/esp32c3_deep_sleep_rtcfastmem' into 'master'

esp32c3: Finish deep sleep support

Closes IDF-2560

See merge request espressif/esp-idf!12031
Michael (XIAO Xufeng) 5 жил өмнө
parent
commit
d741b08fe7

+ 86 - 5
components/esp_hw_support/port/esp32c3/rtc_sleep.c

@@ -24,8 +24,10 @@
 #include "soc/nrx_reg.h"
 #include "soc/nrx_reg.h"
 #include "soc/fe_reg.h"
 #include "soc/fe_reg.h"
 #include "soc/timer_group_reg.h"
 #include "soc/timer_group_reg.h"
+#include "soc/system_reg.h"
 #include "soc/rtc.h"
 #include "soc/rtc.h"
 #include "esp32c3/rom/ets_sys.h"
 #include "esp32c3/rom/ets_sys.h"
+#include "esp32c3/rom/rtc.h"
 #include "regi2c_ctrl.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);
     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)
 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);
     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) {
                              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 */
     /* 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);
     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,
     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;
     return reject;
 }
 }
-
-uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
-{
-    abort(); // ESP32-C3 TODO IDF-2560
-}

+ 11 - 0
components/esp_system/include/esp_sleep.h

@@ -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);
 esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source);
 
 
+#if SOC_ULP_SUPPORTED
 /**
 /**
  * @brief Enable wakeup by ULP coprocessor
  * @brief Enable wakeup by ULP coprocessor
  * @note In revisions 0 and 1 of the ESP32, ULP wakeup source
  * @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);
 esp_err_t esp_sleep_enable_ulp_wakeup(void);
 
 
+#endif // SOC_ULP_SUPPORTED
+
 /**
 /**
  * @brief Enable wakeup by timer
  * @brief Enable wakeup by timer
  * @param time_in_us  time before wakeup, in microseconds
  * @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);
 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
  * @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);
 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.
  * @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);
 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
  * @brief Enable wakeup from light sleep using GPIOs
  *
  *

+ 7 - 3
components/esp_system/sleep_modes.c

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

+ 2 - 2
components/esp_system/test/test_reset_reason.c

@@ -81,7 +81,7 @@ TEST_CASE("reset reason ESP_RST_POWERON", "[reset][ignore]")
     TEST_ASSERT_EQUAL(ESP_RST_POWERON, esp_reset_reason());
     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)
 static void do_deep_sleep(void)
 {
 {
     setup_values();
     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"]",
 TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_DEEPSLEEP", "[reset_reason][reset="DEEPSLEEP"]",
         do_deep_sleep,
         do_deep_sleep,
         check_reset_reason_deep_sleep);
         check_reset_reason_deep_sleep);
-#endif // TODO ESP32-C3 IDF-2560
+#endif // TEMPORARY_DISABLED_FOR_TARGETS
 
 
 static void do_exception(void)
 static void do_exception(void)
 {
 {

+ 15 - 1
examples/system/console/components/cmd_system/cmd_system.c

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

+ 3 - 0
examples/system/deep_sleep/main/Kconfig.projbuild

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

+ 11 - 3
examples/system/deep_sleep/main/deep_sleep_example_main.c

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