From 4ba19abeb690b7fd276b6ed9721c538dd54bfda3 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 3 Apr 2018 18:12:47 +0800 Subject: [PATCH 1/9] esp_timer: add a function to get next alarm time --- components/esp32/esp_timer.c | 12 ++++++++++++ components/esp32/include/esp_timer.h | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/components/esp32/esp_timer.c b/components/esp32/esp_timer.c index 6987b4c64c..72bd9dd73b 100644 --- a/components/esp32/esp_timer.c +++ b/components/esp32/esp_timer.c @@ -455,6 +455,18 @@ esp_err_t esp_timer_dump(FILE* stream) return ESP_OK; } +int64_t IRAM_ATTR esp_timer_get_next_alarm() +{ + int64_t next_alarm = INT64_MAX; + timer_list_lock(); + esp_timer_handle_t it = LIST_FIRST(&s_timers); + if (it) { + next_alarm = it->alarm; + } + timer_list_unlock(); + return next_alarm; +} + int64_t IRAM_ATTR esp_timer_get_time() { return (int64_t) esp_timer_impl_get_time(); diff --git a/components/esp32/include/esp_timer.h b/components/esp32/include/esp_timer.h index 07e2372140..ff5c13ab4c 100644 --- a/components/esp32/include/esp_timer.h +++ b/components/esp32/include/esp_timer.h @@ -189,6 +189,13 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer); */ int64_t esp_timer_get_time(); +/** + * @brief Get the timestamp when the next timeout is expected to occur + * @return Timestamp of the nearest timer event, in microseconds. + * The timebase is the same as for the values returned by esp_timer_get_time. + */ +int64_t esp_timer_get_next_alarm(); + /** * @brief Dump the list of timers to a stream * From c61c2a63d0aa914098fd828a8e5a305cddd5261d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 26 Apr 2018 16:47:35 +0800 Subject: [PATCH 2/9] unity: flush test name before starting the test, use printf everywhere Unit test runner expects to see the test name echoed after test selection is made. If the unit test immediately goes into sleep mode, UART output will not be complete, and test runner will not see the test name. This flushes the stream buffer and waits for UART FIFO to be empty before starting the test. Additionally some parts of code used unity_printf and some used printf. Since unity_printf was only useful during very early tests when newlib was not available, replace all its usages with printf. --- .../components/unity/unity_platform.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/unit-test-app/components/unity/unity_platform.c b/tools/unit-test-app/components/unity/unity_platform.c index 0a33eb66cc..fa1adf6333 100644 --- a/tools/unit-test-app/components/unity/unity_platform.c +++ b/tools/unit-test-app/components/unity/unity_platform.c @@ -17,8 +17,6 @@ #include "esp_heap_trace.h" #endif -#define unity_printf ets_printf - // Pointers to the head and tail of linked list of test description structs: static struct test_desc_t* s_unity_tests_first = NULL; static struct test_desc_t* s_unity_tests_last = NULL; @@ -153,10 +151,10 @@ void unity_testcase_register(struct test_desc_t* desc) * */ static void print_multiple_function_test_menu(const struct test_desc_t* test_ms) { - unity_printf("%s\n", test_ms->name); + printf("%s\n", test_ms->name); for (int i = 0; i < test_ms->test_fn_count; i++) { - unity_printf("\t(%d)\t\"%s\"\n", i+1, test_ms->test_fn_name[i]); + printf("\t(%d)\t\"%s\"\n", i+1, test_ms->test_fn_name[i]); } } @@ -189,6 +187,10 @@ void multiple_function_option(const struct test_desc_t* test_ms) static void unity_run_single_test(const struct test_desc_t* test) { printf("Running %s...\n", test->name); + // Unit test runner expects to see test name before the test starts + fflush(stdout); + uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM); + Unity.TestFile = test->file; Unity.CurrentDetail1 = test->desc; if(test->test_fn_count == 1) { @@ -293,17 +295,17 @@ static void trim_trailing_space(char* str) static int print_test_menu(void) { int test_counter = 0; - unity_printf("\n\nHere's the test menu, pick your combo:\n"); + printf("\n\nHere's the test menu, pick your combo:\n"); for (const struct test_desc_t* test = s_unity_tests_first; test != NULL; test = test->next, ++test_counter) { - unity_printf("(%d)\t\"%s\" %s\n", test_counter + 1, test->name, test->desc); + printf("(%d)\t\"%s\" %s\n", test_counter + 1, test->name, test->desc); if(test->test_fn_count > 1) { for (int i = 0; i < test->test_fn_count; i++) { - unity_printf("\t(%d)\t\"%s\"\n", i+1, test->test_fn_name[i]); + printf("\t(%d)\t\"%s\"\n", i+1, test->test_fn_name[i]); } } } @@ -324,7 +326,7 @@ static int get_test_count(void) void unity_run_menu() { - unity_printf("\n\nPress ENTER to see the list of tests.\n"); + printf("\n\nPress ENTER to see the list of tests.\n"); int test_count = get_test_count(); while (true) { From 48379b8bbe6e9d5ea448427d5834457c8471aa6c Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 26 Apr 2018 17:57:33 +0800 Subject: [PATCH 3/9] unit-test.py: increase timeout for test app start up --- tools/unit-test-app/unit_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/unit-test-app/unit_test.py b/tools/unit-test-app/unit_test.py index 4ea7ddf579..594a71becf 100644 --- a/tools/unit-test-app/unit_test.py +++ b/tools/unit-test-app/unit_test.py @@ -142,7 +142,7 @@ def run_unit_test_cases(env, extra_data): # to determine if DUT is ready to test. dut.write("-", flush=False) dut.expect_any(UT_APP_BOOT_UP_DONE, - "0 Tests 0 Failures 0 Ignored") + "0 Tests 0 Failures 0 Ignored", timeout=UT_TIMEOUT) # run test case dut.write("\"{}\"".format(one_case["name"])) From 487210221bef86f6022413d330300a44cd093f00 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 3 Apr 2018 18:13:22 +0800 Subject: [PATCH 4/9] esp_timer: add internal function to adjust time --- components/esp32/esp_timer_esp32.c | 12 ++++++++++++ components/esp32/esp_timer_impl.h | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/components/esp32/esp_timer_esp32.c b/components/esp32/esp_timer_esp32.c index 4c21910e8a..1bc4885756 100644 --- a/components/esp32/esp_timer_esp32.c +++ b/components/esp32/esp_timer_esp32.c @@ -311,6 +311,18 @@ void IRAM_ATTR esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us) portEXIT_CRITICAL_ISR(&s_time_update_lock); } +void esp_timer_impl_advance(int64_t time_us) +{ + assert(time_us > 0 && "negative adjustments not supported yet"); + + portENTER_CRITICAL(&s_time_update_lock); + uint64_t count = REG_READ(FRC_TIMER_COUNT_REG(1)); + REG_WRITE(FRC_TIMER_LOAD_REG(1), 0); + s_time_base_us += count / s_timer_ticks_per_us + time_us; + esp_timer_impl_set_alarm(esp_timer_get_next_alarm()); + portEXIT_CRITICAL(&s_time_update_lock); +} + esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) { s_alarm_handler = alarm_handler; diff --git a/components/esp32/esp_timer_impl.h b/components/esp32/esp_timer_impl.h index 7d49e3eeb0..9c4642c474 100644 --- a/components/esp32/esp_timer_impl.h +++ b/components/esp32/esp_timer_impl.h @@ -60,6 +60,15 @@ void esp_timer_impl_set_alarm(uint64_t timestamp); */ void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); +/** + * @brief Adjust current esp_timer time by a certain value + * + * Called from light sleep code to synchronize esp_timer time with RTC time. + * + * @param time_us adjustment to apply to esp_timer time, in microseconds + */ +void esp_timer_impl_advance(int64_t time_us); + /** * @brief Get time, in microseconds, since esp_timer_impl_init was called * @return timestamp in microseconds From 3c78faa0a929188598ef4ee6c24f6fafed29495d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 3 Apr 2018 18:14:55 +0800 Subject: [PATCH 5/9] =?UTF-8?q?soc/rtc:=20don=E2=80=99t=20switch=20frequen?= =?UTF-8?q?cy=20in=20rtc=5Fsleep=5Finit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/soc/esp32/include/soc/rtc.h | 2 -- components/soc/esp32/rtc_pm.c | 1 - components/soc/esp32/rtc_sleep.c | 13 ------------- 3 files changed, 16 deletions(-) diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index ec9935fd57..3fe26eed5d 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/components/soc/esp32/include/soc/rtc.h @@ -427,7 +427,6 @@ void rtc_clk_wait_for_slow_cycle(); * @brief sleep configuration for rtc_sleep_init function */ typedef struct { - uint32_t soc_clk_sel : 2; //!< SoC clock select, see RTC_CNTL_SOC_CLK_SEL uint32_t lslp_mem_inf_fpu : 1; //!< force normal voltage in sleep mode (digital domain memory) uint32_t rtc_mem_inf_fpu : 1; //!< force normal voltage in sleep mode (RTC memory) uint32_t rtc_mem_inf_follow_cpu : 1;//!< keep low voltage in sleep mode (even if ULP/touch is used) @@ -455,7 +454,6 @@ typedef struct { * @param RTC_SLEEP_PD_x flags combined using bitwise OR */ #define RTC_SLEEP_CONFIG_DEFAULT(sleep_flags) { \ - .soc_clk_sel = RTC_CNTL_SOC_CLK_SEL_XTL, \ .lslp_mem_inf_fpu = 0, \ .rtc_mem_inf_fpu = 0, \ .rtc_mem_inf_follow_cpu = ((sleep_flags) & RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU) ? 1 : 0, \ diff --git a/components/soc/esp32/rtc_pm.c b/components/soc/esp32/rtc_pm.c index 2023bd824a..e5e7377259 100644 --- a/components/soc/esp32/rtc_pm.c +++ b/components/soc/esp32/rtc_pm.c @@ -48,7 +48,6 @@ pm_sw_reject_t pm_set_sleep_mode(pm_sleep_mode_t sleep_mode, void(*pmac_save_par } rtc_sleep_config_t cfg = { 0 }; - cfg.soc_clk_sel = RTC_CNTL_SOC_CLK_SEL_XTL; switch (sleep_mode) { case PM_LIGHT_SLEEP: diff --git a/components/soc/esp32/rtc_sleep.c b/components/soc/esp32/rtc_sleep.c index 82a04d8cab..60cddf17e8 100644 --- a/components/soc/esp32/rtc_sleep.c +++ b/components/soc/esp32/rtc_sleep.c @@ -89,9 +89,6 @@ static void rtc_sleep_pd(rtc_sleep_pd_config_t cfg) void rtc_sleep_init(rtc_sleep_config_t cfg) { - rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); - REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, cfg.soc_clk_sel); - //set 5 PWC state machine times to fit in main state machine time REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, 1); REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, RTC_CNTL_XTL_BUF_WAIT_DEFAULT); @@ -112,16 +109,6 @@ void rtc_sleep_init(rtc_sleep_config_t cfg) REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_POWERUP_TIMER, RTC_MEM_POWERUP_DELAY); REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_WAIT_TIMER, RTC_MEM_WAIT_DELAY); - if (cfg.soc_clk_sel == RTC_CNTL_SOC_CLK_SEL_PLL) { - REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, RTC_CNTL_PLL_BUF_WAIT_DEFAULT); - } else if (cfg.soc_clk_sel == RTC_CNTL_SOC_CLK_SEL_XTL) { - ets_update_cpu_frequency(xtal_freq); - rtc_clk_apb_freq_update(xtal_freq * MHZ); - } else if (cfg.soc_clk_sel == RTC_CNTL_SOC_CLK_SEL_8M) { - ets_update_cpu_frequency(8); - rtc_clk_apb_freq_update(8 * MHZ); - } - if (cfg.lslp_mem_inf_fpu) { SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU); } else { From b0a91630fb22577314ff15a26e5743f5819ae16c Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 3 Apr 2018 18:15:59 +0800 Subject: [PATCH 6/9] soc/rtc: allow main XTAL to be powered on in sleep --- components/soc/esp32/include/soc/rtc.h | 3 +++ components/soc/esp32/rtc_sleep.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index 3fe26eed5d..2f8cf3fe43 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/components/soc/esp32/include/soc/rtc.h @@ -443,6 +443,7 @@ typedef struct { uint32_t rtc_dbias_slp : 3; //!< set bias for RTC domain, in sleep mode uint32_t lslp_meminf_pd : 1; //!< remove all peripheral force power up flags uint32_t vddsdio_pd_en : 1; //!< power down VDDSDIO regulator + uint32_t xtal_fpu : 1; //!< keep main XTAL powered up in sleep } rtc_sleep_config_t; /** @@ -470,6 +471,7 @@ typedef struct { .rtc_dbias_slp = RTC_CNTL_DBIAS_0V90, \ .lslp_meminf_pd = 1, \ .vddsdio_pd_en = ((sleep_flags) & RTC_SLEEP_PD_VDDSDIO) ? 1 : 0, \ + .xtal_fpu = ((sleep_flags) & RTC_SLEEP_PD_XTAL) ? 0 : 1 \ }; #define RTC_SLEEP_PD_DIG BIT(0) //!< Deep sleep (power down digital domain) @@ -478,6 +480,7 @@ typedef struct { #define RTC_SLEEP_PD_RTC_FAST_MEM BIT(3) //!< Power down RTC FAST memory #define RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU BIT(4) //!< RTC FAST and SLOW memories are automatically powered up and down along with the CPU #define RTC_SLEEP_PD_VDDSDIO BIT(5) //!< Power down VDDSDIO regulator +#define RTC_SLEEP_PD_XTAL BIT(6) //!< Power down main XTAL /** * @brief Prepare the chip to enter sleep mode diff --git a/components/soc/esp32/rtc_sleep.c b/components/soc/esp32/rtc_sleep.c index 60cddf17e8..ae34e273af 100644 --- a/components/soc/esp32/rtc_sleep.c +++ b/components/soc/esp32/rtc_sleep.c @@ -185,6 +185,8 @@ void rtc_sleep_init(rtc_sleep_config_t cfg) REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, 0); } + REG_SET_FIELD(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_XTL_FORCE_PU, cfg.xtal_fpu); + /* enable VDDSDIO control by state machine */ REG_CLR_BIT(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_FORCE); REG_SET_FIELD(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_PD_EN, cfg.vddsdio_pd_en); From d38b22b11bf03364eb32577329469c6c3cc6c37b Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 4 Apr 2018 15:04:29 +0800 Subject: [PATCH 7/9] =?UTF-8?q?soc/rtc,=20sleep:=20don=E2=80=99t=20lower?= =?UTF-8?q?=20the=20bias=20for=20wakeup=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes watchdog resets occurring during wakeup from light sleep. --- components/soc/esp32/include/soc/rtc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index 2f8cf3fe43..86beea5342 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/components/soc/esp32/include/soc/rtc.h @@ -467,7 +467,7 @@ typedef struct { .wdt_flashboot_mod_en = 0, \ .dig_dbias_wak = RTC_CNTL_DBIAS_1V10, \ .dig_dbias_slp = RTC_CNTL_DBIAS_0V90, \ - .rtc_dbias_wak = RTC_CNTL_DBIAS_0V90, \ + .rtc_dbias_wak = RTC_CNTL_DBIAS_1V10, \ .rtc_dbias_slp = RTC_CNTL_DBIAS_0V90, \ .lslp_meminf_pd = 1, \ .vddsdio_pd_en = ((sleep_flags) & RTC_SLEEP_PD_VDDSDIO) ? 1 : 0, \ From ac623a97561929750c8cdcc8d679b21d288a2ab1 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 4 Apr 2018 15:05:16 +0800 Subject: [PATCH 8/9] soc/rtc: restore dbg attenuation when waking from sleep This fixes inability to enter deep sleep after waking up from light sleep --- components/soc/esp32/include/soc/rtc_cntl_reg.h | 2 +- components/soc/esp32/rtc_init.c | 2 +- components/soc/esp32/rtc_sleep.c | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/components/soc/esp32/include/soc/rtc_cntl_reg.h b/components/soc/esp32/include/soc/rtc_cntl_reg.h index d54a7dde7c..090b3f7072 100644 --- a/components/soc/esp32/include/soc/rtc_cntl_reg.h +++ b/components/soc/esp32/include/soc/rtc_cntl_reg.h @@ -1070,7 +1070,7 @@ #define RTC_CNTL_DBG_ATTEN_M ((RTC_CNTL_DBG_ATTEN_V)<<(RTC_CNTL_DBG_ATTEN_S)) #define RTC_CNTL_DBG_ATTEN_V 0x3 #define RTC_CNTL_DBG_ATTEN_S 24 - +#define RTC_CNTL_DBG_ATTEN_DEFAULT 3 #define RTC_CNTL_REG (DR_REG_RTCCNTL_BASE + 0x7c) /* RTC_CNTL_FORCE_PU : R/W ;bitpos:[31] ;default: 1'd1 ; */ /*description: RTC_REG force power up*/ diff --git a/components/soc/esp32/rtc_init.c b/components/soc/esp32/rtc_init.c index dfd0669087..43374d6b02 100644 --- a/components/soc/esp32/rtc_init.c +++ b/components/soc/esp32/rtc_init.c @@ -30,7 +30,7 @@ void rtc_init(rtc_config_t cfg) REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, cfg.xtal_wait); REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, cfg.ck8m_wait); - REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, 0x3); + REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, RTC_CNTL_DBG_ATTEN_DEFAULT); SET_PERI_REG_MASK(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DEC_HEARTBEAT_WIDTH | RTC_CNTL_INC_HEARTBEAT_PERIOD); diff --git a/components/soc/esp32/rtc_sleep.c b/components/soc/esp32/rtc_sleep.c index ae34e273af..b0ffb2ff2b 100644 --- a/components/soc/esp32/rtc_sleep.c +++ b/components/soc/esp32/rtc_sleep.c @@ -219,5 +219,8 @@ uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt) 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, RTC_CNTL_SLP_REJECT_INT_CLR | RTC_CNTL_SLP_WAKEUP_INT_CLR); + + /* restore DBG_ATTEN to the default value */ + REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, RTC_CNTL_DBG_ATTEN_DEFAULT); return reject; } From 94250e42a064e59f63d14b9eaf8e7dabb4ab6dd7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 4 Apr 2018 15:05:50 +0800 Subject: [PATCH 9/9] sleep: optimize light sleep wakeup latency --- components/esp32/include/esp_sleep.h | 1 + components/esp32/sleep_modes.c | 150 +++++++++++++++++++-------- components/esp32/test/test_sleep.c | 127 +++++++++++++++++++++-- components/soc/esp32/rtc_sleep.c | 78 ++++++++------ 4 files changed, 269 insertions(+), 87 deletions(-) diff --git a/components/esp32/include/esp_sleep.h b/components/esp32/include/esp_sleep.h index 2bdeac474f..a8bce5f796 100644 --- a/components/esp32/include/esp_sleep.h +++ b/components/esp32/include/esp_sleep.h @@ -38,6 +38,7 @@ 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_XTAL, //!< XTAL oscillator ESP_PD_DOMAIN_MAX //!< Number of domains } esp_sleep_pd_domain_t; diff --git a/components/esp32/sleep_modes.c b/components/esp32/sleep_modes.c index 1a9c449a2a..a5f14d7f2b 100644 --- a/components/esp32/sleep_modes.c +++ b/components/esp32/sleep_modes.c @@ -17,6 +17,7 @@ #include #include "esp_attr.h" #include "esp_sleep.h" +#include "esp_timer_impl.h" #include "esp_log.h" #include "esp_clk.h" #include "esp_newlib.h" @@ -42,6 +43,19 @@ // Time from VDD_SDIO power up to first flash read in ROM code #define VDD_SDIO_POWERUP_TO_FLASH_READ_US 700 +// Extra time it takes to enter and exit light sleep and deep sleep +// For deep sleep, this is until the wake stub runs (not the app). +#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL +#define LIGHT_SLEEP_TIME_OVERHEAD_US (650 + 30 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) +#define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) +#else +#define LIGHT_SLEEP_TIME_OVERHEAD_US (250 + 30 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) +#define DEEP_SLEEP_TIME_OVERHEAD_US (250 + 100 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) +#endif // CONFIG_ESP32_RTC_CLOCK_SOURCE + +// Minimal amount of time we can sleep for +#define LIGHT_SLEEP_MIN_TIME_US 200 + #define CHECK_SOURCE(source, value, mask) ((s_config.wakeup_triggers & mask) && \ (source == value)) @@ -56,9 +70,11 @@ typedef struct { uint32_t ext1_rtc_gpio_mask : 18; uint32_t ext0_trigger_level : 1; uint32_t ext0_rtc_gpio_num : 5; -} deep_sleep_config_t; + uint32_t sleep_time_adjustment; + uint64_t rtc_ticks_at_sleep_start; +} sleep_config_t; -static deep_sleep_config_t s_config = { +static sleep_config_t s_config = { .pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO }, .wakeup_triggers = 0 }; @@ -125,12 +141,31 @@ void esp_deep_sleep(uint64_t time_in_us) esp_deep_sleep_start(); } +static void IRAM_ATTR suspend_uarts() +{ + for (int i = 0; i < 3; ++i) { + REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF); + uart_tx_wait_idle(i); + } +} + +static void IRAM_ATTR resume_uarts() +{ + for (int i = 0; i < 3; ++i) { + REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF); + REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON); + REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON); + } +} + static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) { - // 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); + // Stop UART output so that output is not lost due to APB frequency change + suspend_uarts(); + + // Save current frequency and switch to XTAL + rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get(); + rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL); // Configure pins for external wakeup if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) { @@ -143,20 +178,32 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) if (s_config.wakeup_triggers & RTC_ULP_TRIG_EN) { SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_WAKEUP_FORCE_EN); } + + // Enter sleep + rtc_sleep_config_t config = RTC_SLEEP_CONFIG_DEFAULT(pd_flags); + rtc_sleep_init(config); + // Configure timer wakeup if ((s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) && s_config.sleep_duration > 0) { timer_wakeup_prepare(); } + uint32_t result = rtc_sleep_start(s_config.wakeup_triggers, 0); - // Enter sleep - rtc_sleep_config_t config = RTC_SLEEP_CONFIG_DEFAULT(pd_flags); - rtc_sleep_init(config); - return rtc_sleep_start(s_config.wakeup_triggers, 0); + // Restore CPU frequency + rtc_clk_cpu_freq_set(cpu_freq); + + // re-enable UART output + resume_uarts(); + + return result; } void IRAM_ATTR esp_deep_sleep_start() { + // record current RTC time + s_config.rtc_ticks_at_sleep_start = rtc_time_get(); + // Configure wake stub if (esp_get_deep_sleep_wake_stub() == NULL) { esp_set_deep_sleep_wake_stub(esp_wake_deep_sleep); @@ -165,8 +212,11 @@ void IRAM_ATTR esp_deep_sleep_start() // Decide which power domains can be powered down uint32_t pd_flags = get_power_down_flags(); + // Correct the sleep time + s_config.sleep_time_adjustment = DEEP_SLEEP_TIME_OVERHEAD_US; + // Enter sleep - esp_sleep_start(RTC_SLEEP_PD_DIG | RTC_SLEEP_PD_VDDSDIO | pd_flags); + esp_sleep_start(RTC_SLEEP_PD_DIG | RTC_SLEEP_PD_VDDSDIO | RTC_SLEEP_PD_XTAL | 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. @@ -201,11 +251,11 @@ static void rtc_wdt_disable() * Placed into IRAM as flash may need some time to be powered on. */ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags, - rtc_cpu_freq_t cpu_freq, uint32_t flash_enable_time_us, + uint32_t flash_enable_time_us, rtc_vddsdio_config_t vddsdio_config) IRAM_ATTR __attribute__((noinline)); static esp_err_t esp_light_sleep_inner(uint32_t pd_flags, - rtc_cpu_freq_t cpu_freq, uint32_t flash_enable_time_us, + uint32_t flash_enable_time_us, rtc_vddsdio_config_t vddsdio_config) { // Enter sleep @@ -217,9 +267,6 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags, rtc_vddsdio_set_config(vddsdio_config); } - // 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 @@ -231,53 +278,61 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags, 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(); + s_config.rtc_ticks_at_sleep_start = rtc_time_get(); + uint64_t frc_time_at_start = esp_timer_get_time(); + DPORT_STALL_OTHER_CPU_START(); // Decide which power domains can be powered down uint32_t pd_flags = get_power_down_flags(); + // Amount of time to subtract from actual sleep time. + // This is spent on entering and leaving light sleep. + s_config.sleep_time_adjustment = LIGHT_SLEEP_TIME_OVERHEAD_US; + // Decide if VDD_SDIO 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; - // Don't power down VDD_SDIO if pSRAM is used. #ifndef CONFIG_SPIRAM_SUPPORT - if (s_config.sleep_duration > FLASH_PD_MIN_SLEEP_TIME_US && - s_config.sleep_duration > flash_enable_time_us) { + const uint32_t vddsdio_pd_sleep_duration = MAX(FLASH_PD_MIN_SLEEP_TIME_US, + flash_enable_time_us + LIGHT_SLEEP_TIME_OVERHEAD_US + LIGHT_SLEEP_MIN_TIME_US); + + if (s_config.sleep_duration > vddsdio_pd_sleep_duration) { pd_flags |= RTC_SLEEP_PD_VDDSDIO; - s_config.sleep_duration -= flash_enable_time_us; + s_config.sleep_time_adjustment += flash_enable_time_us; } #endif //CONFIG_SPIRAM_SUPPORT + rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config(); // 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, + esp_err_t err = esp_light_sleep_inner(pd_flags, flash_enable_time_us, vddsdio_config); - // At this point, if FRC1 is used for timekeeping, time will be lagging behind. - // This will update the microsecond count based on RTC timer. + // FRC1 has been clock gated for the duration of the sleep, correct for that. + uint64_t rtc_ticks_at_end = rtc_time_get(); + uint64_t frc_time_at_end = esp_timer_get_time(); + + uint64_t rtc_time_diff = rtc_time_slowclk_to_us(rtc_ticks_at_end - s_config.rtc_ticks_at_sleep_start, + esp_clk_slowclk_cal_get()); + uint64_t frc_time_diff = frc_time_at_end - frc_time_at_start; + + int64_t time_diff = rtc_time_diff - frc_time_diff; + /* Small negative values (up to 1 RTC_SLOW clock period) are possible, + * for very small values of sleep_duration. Ignore those to keep esp_timer + * monotonic. + */ + if (time_diff > 0) { + esp_timer_impl_advance(time_diff); + } esp_set_time_from_rtc(); - // 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(); + DPORT_STALL_OTHER_CPU_END(); rtc_wdt_disable(); portEXIT_CRITICAL(&light_sleep_lock); return err; @@ -343,9 +398,13 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us) static void timer_wakeup_prepare() { uint32_t period = esp_clk_slowclk_cal_get(); - uint64_t rtc_count_delta = rtc_time_us_to_slowclk(s_config.sleep_duration, period); - uint64_t cur_rtc_count = rtc_time_get(); - rtc_sleep_set_wakeup_time(cur_rtc_count + rtc_count_delta); + int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment; + if (sleep_duration < 0) { + sleep_duration = 0; + } + int64_t rtc_count_delta = rtc_time_us_to_slowclk(sleep_duration, period); + + rtc_sleep_set_wakeup_time(s_config.rtc_ticks_at_sleep_start + rtc_count_delta); } esp_err_t esp_sleep_enable_touchpad_wakeup() @@ -561,6 +620,10 @@ static uint32_t get_power_down_flags() } } + if (s_config.pd_options[ESP_PD_DOMAIN_XTAL] == ESP_PD_OPTION_AUTO) { + s_config.pd_options[ESP_PD_DOMAIN_XTAL] = ESP_PD_OPTION_OFF; + } + const char* option_str[] = {"OFF", "ON", "AUTO(OFF)" /* Auto works as OFF */}; ESP_LOGD(TAG, "RTC_PERIPH: %s, RTC_SLOW_MEM: %s, RTC_FAST_MEM: %s", option_str[s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH]], @@ -578,5 +641,8 @@ static uint32_t get_power_down_flags() if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] != ESP_PD_OPTION_ON) { pd_flags |= RTC_SLEEP_PD_RTC_PERIPH; } + if (s_config.pd_options[ESP_PD_DOMAIN_XTAL] != ESP_PD_OPTION_ON) { + pd_flags |= RTC_SLEEP_PD_XTAL; + } return pd_flags; } diff --git a/components/esp32/test/test_sleep.c b/components/esp32/test/test_sleep.c index fa1b902ac2..ac090fff98 100644 --- a/components/esp32/test/test_sleep.c +++ b/components/esp32/test/test_sleep.c @@ -1,10 +1,16 @@ #include "unity.h" #include +#include #include "esp_sleep.h" +#include "esp_clk.h" #include "driver/rtc_io.h" +#include "soc/gpio_reg.h" +#include "soc/rtc.h" +#include "soc/uart_reg.h" +#include "rom/uart.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" - +#include "freertos/semphr.h" #include "soc/rtc.h" // for wakeup trigger defines #include "soc/rtc_cntl_reg.h" // for read rtc registers directly (cause) #include "soc/soc.h" // for direct register read macros @@ -14,10 +20,6 @@ static struct timeval tv_start, tv_stop; -TEST_CASE("esp_deepsleep works", "[deepsleep][reset=DEEPSLEEP_RESET]") -{ - esp_deep_sleep(2000000); -} static void deep_sleep_task(void *arg) { @@ -36,12 +38,19 @@ static void do_deep_sleep_from_app_cpu() } } -TEST_CASE("wake up using timer", "[deepsleep][reset=DEEPSLEEP_RESET]") +TEST_CASE("wake up from deep sleep using timer", "[deepsleep][reset=DEEPSLEEP_RESET]") { esp_sleep_enable_timer_wakeup(2000000); esp_deep_sleep_start(); } +TEST_CASE("light sleep followed by deep sleep", "[deepsleep][reset=DEEPSLEEP_RESET]") +{ + esp_sleep_enable_timer_wakeup(1000000); + esp_light_sleep_start(); + esp_deep_sleep_start(); +} + TEST_CASE("wake up from light sleep using timer", "[deepsleep]") { esp_sleep_enable_timer_wakeup(2000000); @@ -54,6 +63,103 @@ TEST_CASE("wake up from light sleep using timer", "[deepsleep]") TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt); } +static void test_light_sleep(void* arg) +{ + vTaskDelay(2); + for (int i = 0; i < 1000; ++i) { + printf("%d %d\n", xPortGetCoreID(), i); + fflush(stdout); + esp_light_sleep_start(); + } + SemaphoreHandle_t done = (SemaphoreHandle_t) arg; + xSemaphoreGive(done); + vTaskDelete(NULL); +} + +TEST_CASE("light sleep stress test", "[deepsleep]") +{ + SemaphoreHandle_t done = xSemaphoreCreateCounting(2, 0); + esp_sleep_enable_timer_wakeup(1000); + xTaskCreatePinnedToCore(&test_light_sleep, "ls0", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 0); +#if portNUM_PROCESSORS == 2 + xTaskCreatePinnedToCore(&test_light_sleep, "ls1", 4096, done, UNITY_FREERTOS_PRIORITY + 1, NULL, 1); +#endif + xSemaphoreTake(done, portMAX_DELAY); +#if portNUM_PROCESSORS == 2 + xSemaphoreTake(done, portMAX_DELAY); +#endif + vSemaphoreDelete(done); +} + +#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL +#define MAX_SLEEP_TIME_ERROR_US 200 +#else +#define MAX_SLEEP_TIME_ERROR_US 100 +#endif + + +TEST_CASE("light sleep duration is correct", "[deepsleep]") +{ + // don't power down XTAL — powering it up takes different time on + // different boards + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); + + // run one light sleep without checking timing, to warm up the cache + esp_sleep_enable_timer_wakeup(1000); + esp_light_sleep_start(); + + const int sleep_intervals_ms[] = { + 1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 15, + 20, 25, 50, 100, 200, 500, + }; + + const int sleep_intervals_count = sizeof(sleep_intervals_ms)/sizeof(sleep_intervals_ms[0]); + for (int i = 0; i < sleep_intervals_count; ++i) { + uint64_t sleep_time = sleep_intervals_ms[i] * 1000; + esp_sleep_enable_timer_wakeup(sleep_time); + for (int repeat = 0; repeat < 5; ++repeat) { + uint64_t start = esp_clk_rtc_time(); + int64_t start_hs = esp_timer_get_time(); + esp_light_sleep_start(); + int64_t stop_hs = esp_timer_get_time(); + uint64_t stop = esp_clk_rtc_time(); + + int diff_us = (int) (stop - start); + int diff_hs_us = (int) (stop_hs - start_hs); + printf("%lld %d\n", sleep_time, (int) (diff_us - sleep_time)); + int32_t threshold = MAX(sleep_time / 100, MAX_SLEEP_TIME_ERROR_US); + TEST_ASSERT_INT32_WITHIN(threshold, sleep_time, diff_us); + TEST_ASSERT_INT32_WITHIN(threshold, sleep_time, diff_hs_us); + fflush(stdout); + } + + vTaskDelay(10/portTICK_PERIOD_MS); + } +} + + +TEST_CASE("light sleep and frequency switching", "[deepsleep]") +{ +#ifndef CONFIG_PM_ENABLE + const int uart_clk_freq = REF_CLK_FREQ; + CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON); + uart_div_modify(CONFIG_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_CONSOLE_UART_BAUDRATE); +#endif + + esp_sleep_enable_timer_wakeup(1000); + rtc_cpu_freq_t default_freq = rtc_clk_cpu_freq_get(); + for (int i = 0; i < 1000; ++i) { + if (i % 2 == 0) { + rtc_clk_cpu_freq_set_fast(RTC_CPU_FREQ_XTAL); + } else { + rtc_clk_cpu_freq_set_fast(default_freq); + } + printf("%d\n", i); + fflush(stdout); + esp_light_sleep_start(); + } +} + #ifndef CONFIG_FREERTOS_UNICORE TEST_CASE("enter deep sleep on APP CPU and wake up using timer", "[deepsleep][reset=DEEPSLEEP_RESET]") { @@ -138,7 +244,7 @@ TEST_CASE("disable source trigger behavior", "[deepsleep]") { float dt = 0; - printf("Setup timer and ext0 to wakeup imediately from GPIO_13 \n"); + printf("Setup timer and ext0 to wake up immediately from GPIO_13 \n"); // Setup ext0 configuration to wake up almost immediately // The wakeup time is proportional to input capacitance * pullup resistance @@ -159,7 +265,7 @@ TEST_CASE("disable source trigger behavior", "[deepsleep]") // Check wakeup from Ext0 using time measurement because wakeup cause is // not available in light sleep mode - TEST_ASSERT_INT32_WITHIN(299, 300, (int) dt); + TEST_ASSERT_INT32_WITHIN(100, 100, (int) dt); TEST_ASSERT((get_cause() & RTC_EXT0_TRIG_EN) != 0); @@ -175,7 +281,7 @@ TEST_CASE("disable source trigger behavior", "[deepsleep]") TEST_ASSERT_INT32_WITHIN(500, 2000, (int) dt); - // Additionaly check wakeup cause + // Additionally check wakeup cause TEST_ASSERT((get_cause() & RTC_TIMER_TRIG_EN) != 0); // Disable timer source. @@ -195,12 +301,11 @@ TEST_CASE("disable source trigger behavior", "[deepsleep]") dt = get_time_ms(); printf("Ext0 sleep time = %d \n", (int) dt); - TEST_ASSERT_INT32_WITHIN(199, 200, (int) dt); + TEST_ASSERT_INT32_WITHIN(100, 100, (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_WAKEUP_TIMER); TEST_ASSERT(err_code == ESP_ERR_INVALID_STATE); - printf("Test case completed successfully."); } diff --git a/components/soc/esp32/rtc_sleep.c b/components/soc/esp32/rtc_sleep.c index b0ffb2ff2b..041c2d1b6b 100644 --- a/components/soc/esp32/rtc_sleep.c +++ b/components/soc/esp32/rtc_sleep.c @@ -29,16 +29,26 @@ #define MHZ (1000000) /* Various delays to be programmed into power control state machines */ -#define ROM_RAM_POWERUP_DELAY 3 -#define ROM_RAM_WAIT_DELAY 3 -#define WIFI_POWERUP_DELAY 3 -#define WIFI_WAIT_DELAY 3 -#define RTC_POWERUP_DELAY 3 -#define RTC_WAIT_DELAY 3 -#define DG_WRAP_POWERUP_DELAY 3 -#define DG_WRAP_WAIT_DELAY 3 -#define RTC_MEM_POWERUP_DELAY 3 -#define RTC_MEM_WAIT_DELAY 3 +#define RTC_CNTL_XTL_BUF_WAIT_SLP 2 +#define RTC_CNTL_PLL_BUF_WAIT_SLP 2 +#define RTC_CNTL_CK8M_WAIT_SLP 4 +#define OTHER_BLOCKS_POWERUP 1 +#define OTHER_BLOCKS_WAIT 1 + +#define ROM_RAM_POWERUP_CYCLES OTHER_BLOCKS_POWERUP +#define ROM_RAM_WAIT_CYCLES OTHER_BLOCKS_WAIT + +#define WIFI_POWERUP_CYCLES OTHER_BLOCKS_POWERUP +#define WIFI_WAIT_CYCLES OTHER_BLOCKS_WAIT + +#define RTC_POWERUP_CYCLES OTHER_BLOCKS_POWERUP +#define RTC_WAIT_CYCLES OTHER_BLOCKS_WAIT + +#define DG_WRAP_POWERUP_CYCLES OTHER_BLOCKS_POWERUP +#define DG_WRAP_WAIT_CYCLES OTHER_BLOCKS_WAIT + +#define RTC_MEM_POWERUP_CYCLES OTHER_BLOCKS_POWERUP +#define RTC_MEM_WAIT_CYCLES OTHER_BLOCKS_WAIT /** * @brief Power down flags for rtc_sleep_pd function @@ -89,31 +99,31 @@ static void rtc_sleep_pd(rtc_sleep_pd_config_t cfg) void rtc_sleep_init(rtc_sleep_config_t cfg) { - //set 5 PWC state machine times to fit in main state machine time - REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, 1); - REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, RTC_CNTL_XTL_BUF_WAIT_DEFAULT); - REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT); - //set rom&ram timer - REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_ROM_RAM_POWERUP_TIMER, ROM_RAM_POWERUP_DELAY); - REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_ROM_RAM_WAIT_TIMER, ROM_RAM_WAIT_DELAY); - //set wifi timer - REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_POWERUP_TIMER, WIFI_POWERUP_DELAY); - REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_WAIT_TIMER, WIFI_WAIT_DELAY); - //set rtc peri timer - REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_POWERUP_TIMER, RTC_POWERUP_DELAY); - REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_WAIT_TIMER, RTC_WAIT_DELAY); - //set digital wrap timer - REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_POWERUP_TIMER, DG_WRAP_POWERUP_DELAY); - REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_WAIT_TIMER, DG_WRAP_WAIT_DELAY); - //set rtc memory timer - REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_POWERUP_TIMER, RTC_MEM_POWERUP_DELAY); - REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_WAIT_TIMER, RTC_MEM_WAIT_DELAY); + // set 5 PWC state machine times to fit in main state machine time + REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, RTC_CNTL_PLL_BUF_WAIT_SLP); + REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, RTC_CNTL_XTL_BUF_WAIT_SLP); + REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_SLP); - if (cfg.lslp_mem_inf_fpu) { - SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU); - } else { - CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU); - } + // set shortest possible sleep time limit + REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_MIN_SLP_VAL, RTC_CNTL_MIN_SLP_VAL_MIN); + + // set rom&ram timer + REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_ROM_RAM_POWERUP_TIMER, ROM_RAM_POWERUP_CYCLES); + REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_ROM_RAM_WAIT_TIMER, ROM_RAM_WAIT_CYCLES); + // set wifi timer + REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_POWERUP_TIMER, WIFI_POWERUP_CYCLES); + REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_WAIT_TIMER, WIFI_WAIT_CYCLES); + // set rtc peri timer + REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_POWERUP_TIMER, RTC_POWERUP_CYCLES); + REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_WAIT_TIMER, RTC_WAIT_CYCLES); + // set digital wrap timer + REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_POWERUP_TIMER, DG_WRAP_POWERUP_CYCLES); + REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_WAIT_TIMER, DG_WRAP_WAIT_CYCLES); + // set rtc memory timer + REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_POWERUP_TIMER, RTC_MEM_POWERUP_CYCLES); + REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_WAIT_TIMER, RTC_MEM_WAIT_CYCLES); + + REG_SET_FIELD(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU, cfg.lslp_mem_inf_fpu); rtc_sleep_pd_config_t pd_cfg = RTC_SLEEP_PD_CONFIG_ALL(cfg.lslp_meminf_pd); rtc_sleep_pd(pd_cfg);