diff --git a/components/esp32/include/esp_sleep.h b/components/esp32/include/esp_sleep.h index 2bdeac474..a8bce5f79 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 1a9c449a2..a5f14d7f2 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 fa1b902ac..ac090fff9 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 b0ffb2ff2..041c2d1b6 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);