]> granicus.if.org Git - esp-idf/commitdiff
sleep: optimize light sleep wakeup latency
authorIvan Grokhotkov <ivan@espressif.com>
Wed, 4 Apr 2018 07:05:50 +0000 (15:05 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Thu, 26 Apr 2018 11:36:47 +0000 (19:36 +0800)
components/esp32/include/esp_sleep.h
components/esp32/sleep_modes.c
components/esp32/test/test_sleep.c
components/soc/esp32/rtc_sleep.c

index 2bdeac474fac45a2aa9254aa51dd2b194036750f..a8bce5f796e1a76d264a43834e4b7873183a331d 100644 (file)
@@ -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;
 
index 1a9c449a2ae158da1d8b731b29232858c2d7af3a..a5f14d7f2bd5b102f3d9c5454d9e894dcf8ff27c 100644 (file)
@@ -17,6 +17,7 @@
 #include <sys/param.h>
 #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"
 // 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.
-    esp_set_time_from_rtc();
+    // 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();
 
-    // 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.
+    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();
 
-    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;
 }
index fa1b902ac23ff83c6fa5c8604f93ebff3363fe3f..ac090fff9821f6c0815a1c3a3252c88792ed4cb0 100644 (file)
@@ -1,10 +1,16 @@
 #include "unity.h"
 #include <sys/time.h>
+#include <sys/param.h>
 #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
 
 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.");
 }
 
index b0ffb2ff2bdcceab92e1cd32b6e43b79f89d4c72..041c2d1b6b9e82377cb3b45ee43c86ecc9bfa2fb 100644 (file)
 #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);
-
-    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 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);
+
+    // 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);