diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 169baff466..b86929672d 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -79,6 +79,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "mspi_timing_tuning.c" "port/${target}/mspi_timing_config.c") endif() + if(CONFIG_SOC_RTC_FAST_MEM_SUPPORTED) + list(APPEND srcs "sleep_wake_stub.c") + endif() + if(CONFIG_IDF_TARGET_ESP32H2) list(REMOVE_ITEM srcs "adc_share_hw_ctrl.c" # TODO: IDF-6215 diff --git a/components/esp_hw_support/include/esp_wake_stub.h b/components/esp_hw_support/include/esp_wake_stub.h new file mode 100644 index 0000000000..211e66bd59 --- /dev/null +++ b/components/esp_hw_support/include/esp_wake_stub.h @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_log.h" +#include "esp_sleep.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTC_STR(str) (__extension__({static const RTC_RODATA_ATTR char _fmt[] = (str); (const char *)&_fmt;})) +#define RTC_LOG_FORMAT(letter, format) LOG_COLOR_ ## letter format LOG_RESET_COLOR "\n" + +#define ESP_RTC_LOG( level, format, ... ) if (LOG_LOCAL_LEVEL >= level) { esp_rom_printf(RTC_STR(format), ##__VA_ARGS__); \ + esp_wake_stub_uart_tx_wait_idle(0); } + +#define ESP_RTC_LOGE( format, ... ) ESP_RTC_LOG(ESP_LOG_ERROR, RTC_LOG_FORMAT(E, format), ##__VA_ARGS__) +#define ESP_RTC_LOGW( format, ... ) ESP_RTC_LOG(ESP_LOG_WARN, RTC_LOG_FORMAT(W, format), ##__VA_ARGS__) +#define ESP_RTC_LOGI( format, ... ) ESP_RTC_LOG(ESP_LOG_INFO, RTC_LOG_FORMAT(I, format), ##__VA_ARGS__) +#define ESP_RTC_LOGD( format, ... ) ESP_RTC_LOG(ESP_LOG_DEBUG, RTC_LOG_FORMAT(D, format), ##__VA_ARGS__) +#define ESP_RTC_LOGV( format, ... ) ESP_RTC_LOG(ESP_LOG_VERBOSE, RTC_LOG_FORMAT(V, format), ##__VA_ARGS__) + +/** + * @brief Enter deep-sleep mode from deep sleep wake stub code + * + * This should be called from the wake stub code. + * + * @param new_stub new wake stub function will be set + */ +void esp_wake_stub_sleep(esp_deep_sleep_wake_stub_fn_t new_stub); + +/** + * @brief Wait while uart transmission is in progress + * + * This function is waiting while uart transmission is not completed, + * and this function should be called from the wake stub code. + * + * @param uart_no UART port to wait idle + */ +void esp_wake_stub_uart_tx_wait_idle(uint8_t uart_no); + +/** + * @brief Set wakeup time from deep sleep stub. + * + * This should be called from the wake stub code. + * + * @param time_in_us wakeup time in us + */ +void esp_wake_stub_set_wakeup_time(uint64_t time_in_us); + +/** + * @brief Get wakeup cause from deep sleep stub. + * + * This should be called from the wake stub code. + * + * @return wakeup casue value + */ +uint32_t esp_wake_stub_get_wakeup_cause(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/port/esp32/rtc_time.c b/components/esp_hw_support/port/esp32/rtc_time.c index a92b88041f..d24d61e74c 100644 --- a/components/esp_hw_support/port/esp32/rtc_time.c +++ b/components/esp_hw_support/port/esp32/rtc_time.c @@ -7,6 +7,7 @@ #include #include "esp_rom_sys.h" #include "hal/clk_tree_ll.h" +#include "hal/rtc_cntl_ll.h" #include "soc/rtc.h" #include "soc/timer_periph.h" #include "esp_hw_log.h" @@ -152,20 +153,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) uint64_t rtc_time_get(void) { - SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); - int attempts = 1000; - while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) { - esp_rom_delay_us(1); // might take 1 RTC slowclk period, don't flood RTC bus - if (attempts) { - if (--attempts == 0 && clk_ll_xtal32k_digi_is_enabled()) { - ESP_HW_LOGE(TAG, "rtc_time_get() 32kHz xtal has been stopped"); - } - } - } - SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG, RTC_CNTL_TIME_VALID_INT_CLR); - uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); - t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; - return t; + return rtc_cntl_ll_get_rtc_time(); } void rtc_clk_wait_for_slow_cycle(void) diff --git a/components/esp_hw_support/port/esp32c2/rtc_time.c b/components/esp_hw_support/port/esp32c2/rtc_time.c index 0333f05aec..b2a6f77a4c 100644 --- a/components/esp_hw_support/port/esp32c2/rtc_time.c +++ b/components/esp_hw_support/port/esp32c2/rtc_time.c @@ -9,6 +9,7 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "hal/clk_tree_ll.h" +#include "hal/rtc_cntl_ll.h" #include "soc/timer_group_reg.h" #include "esp_rom_sys.h" @@ -166,10 +167,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) uint64_t rtc_time_get(void) { - SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); - uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); - t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; - return t; + return rtc_cntl_ll_get_rtc_time(); } uint64_t rtc_light_slp_time_get(void) diff --git a/components/esp_hw_support/port/esp32c3/rtc_time.c b/components/esp_hw_support/port/esp32c3/rtc_time.c index beaa4965e1..26327e58d3 100644 --- a/components/esp_hw_support/port/esp32c3/rtc_time.c +++ b/components/esp_hw_support/port/esp32c3/rtc_time.c @@ -9,6 +9,7 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "hal/clk_tree_ll.h" +#include "hal/rtc_cntl_ll.h" #include "soc/timer_group_reg.h" #include "esp_rom_sys.h" @@ -169,10 +170,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) uint64_t rtc_time_get(void) { - SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); - uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); - t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; - return t; + return rtc_cntl_ll_get_rtc_time(); } uint64_t rtc_light_slp_time_get(void) diff --git a/components/esp_hw_support/port/esp32c6/rtc_time.c b/components/esp_hw_support/port/esp32c6/rtc_time.c index bf4aad5fca..98bf1e6f82 100644 --- a/components/esp_hw_support/port/esp32c6/rtc_time.c +++ b/components/esp_hw_support/port/esp32c6/rtc_time.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,7 @@ #include "soc/rtc.h" #include "soc/lp_timer_reg.h" #include "hal/clk_tree_ll.h" +#include "hal/rtc_cntl_ll.h" #include "soc/timer_group_reg.h" #include "esp_rom_sys.h" #include "assert.h" @@ -206,10 +207,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) uint64_t rtc_time_get(void) { - SET_PERI_REG_MASK(LP_TIMER_UPDATE_REG, LP_TIMER_MAIN_TIMER_UPDATE); - uint64_t t = READ_PERI_REG(LP_TIMER_MAIN_BUF0_LOW_REG); - t |= ((uint64_t) READ_PERI_REG(LP_TIMER_MAIN_BUF0_HIGH_REG)) << 32; - return t; + return rtc_cntl_ll_get_rtc_time(); } uint64_t rtc_light_slp_time_get(void) diff --git a/components/esp_hw_support/port/esp32h4/rtc_time.c b/components/esp_hw_support/port/esp32h4/rtc_time.c index 81522556ca..743473a96a 100644 --- a/components/esp_hw_support/port/esp32h4/rtc_time.c +++ b/components/esp_hw_support/port/esp32h4/rtc_time.c @@ -9,6 +9,7 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "hal/clk_tree_ll.h" +#include "hal/rtc_cntl_ll.h" #include "soc/timer_group_reg.h" #include "esp_rom_sys.h" @@ -163,10 +164,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) uint64_t rtc_time_get(void) { - SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); - uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); - t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; - return t; + return rtc_cntl_ll_get_rtc_time(); } uint64_t rtc_light_slp_time_get(void) diff --git a/components/esp_hw_support/port/esp32s2/rtc_time.c b/components/esp_hw_support/port/esp32s2/rtc_time.c index c8e22bf8bf..57e248e9f1 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_time.c +++ b/components/esp_hw_support/port/esp32s2/rtc_time.c @@ -9,6 +9,7 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "hal/clk_tree_ll.h" +#include "hal/rtc_cntl_ll.h" #include "soc/timer_group_reg.h" /* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0. @@ -234,10 +235,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) uint64_t rtc_time_get(void) { - SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); - uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); - t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; - return t; + return rtc_cntl_ll_get_rtc_time(); } uint64_t rtc_light_slp_time_get(void) diff --git a/components/esp_hw_support/port/esp32s3/rtc_time.c b/components/esp_hw_support/port/esp32s3/rtc_time.c index 9c07e6a9d6..6333b68a19 100644 --- a/components/esp_hw_support/port/esp32s3/rtc_time.c +++ b/components/esp_hw_support/port/esp32s3/rtc_time.c @@ -9,6 +9,7 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "hal/clk_tree_ll.h" +#include "hal/rtc_cntl_ll.h" #include "soc/timer_group_reg.h" /* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0. @@ -168,10 +169,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period) uint64_t rtc_time_get(void) { - SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); - uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); - t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; - return t; + return rtc_cntl_ll_get_rtc_time(); } uint64_t rtc_light_slp_time_get(void) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 81861b59cd..c1e4f6f357 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -1272,11 +1272,7 @@ esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void) return ESP_SLEEP_WAKEUP_UNDEFINED; } -#ifdef CONFIG_IDF_TARGET_ESP32 - uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE); -#else - uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_SLP_WAKEUP_CAUSE_REG, RTC_CNTL_WAKEUP_CAUSE); -#endif + uint32_t wakeup_cause = rtc_cntl_ll_get_wakeup_cause(); if (wakeup_cause & RTC_TIMER_TRIG_EN) { return ESP_SLEEP_WAKEUP_TIMER; diff --git a/components/esp_hw_support/sleep_wake_stub.c b/components/esp_hw_support/sleep_wake_stub.c new file mode 100644 index 0000000000..bb6257a7b9 --- /dev/null +++ b/components/esp_hw_support/sleep_wake_stub.c @@ -0,0 +1,81 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "esp_attr.h" +#include "esp_sleep.h" + +#include "soc/soc.h" +#include "soc/rtc.h" +#include "soc/soc_caps.h" +#include "hal/rtc_cntl_ll.h" +#include "hal/uart_ll.h" + +#include "sdkconfig.h" +#include "esp_rom_uart.h" +#include "esp_rom_sys.h" + +#ifdef CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32H4 +#include "esp32h4/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/rtc.h" +#endif + +void RTC_IRAM_ATTR esp_wake_stub_sleep(esp_deep_sleep_wake_stub_fn_t new_stub) +{ +#if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY + extern char _rtc_text_start[]; + #if CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM + extern char _rtc_noinit_end[]; + size_t rtc_fast_length = (size_t)_rtc_noinit_end - (size_t)_rtc_text_start; + #else + extern char _rtc_force_fast_end[]; + size_t rtc_fast_length = (size_t)_rtc_force_fast_end - (size_t)_rtc_text_start; + #endif // CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM + esp_rom_set_rtc_wake_addr((esp_rom_wake_func_t)new_stub, rtc_fast_length); +#else + // Set the pointer of the wake stub function. + REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)new_stub); + set_rtc_memory_crc(); +#endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_MEM + + // Go to sleep. + rtc_cntl_ll_sleep_enable(); + // A few CPU cycles may be necessary for the sleep to start... + while (true) {}; + // never reaches here. +} + +void RTC_IRAM_ATTR esp_wake_stub_uart_tx_wait_idle(uint8_t uart_no) +{ + while (!uart_ll_is_tx_idle(UART_LL_GET_HW(uart_no))) {}; +} + +void RTC_IRAM_ATTR esp_wake_stub_set_wakeup_time(uint64_t time_in_us) +{ + uint64_t rtc_count_delta = rtc_cntl_ll_time_to_count(time_in_us); + uint64_t rtc_curr_count = rtc_cntl_ll_get_rtc_time(); + rtc_cntl_ll_set_wakeup_timer(rtc_curr_count + rtc_count_delta); +} + +uint32_t RTC_IRAM_ATTR esp_wake_stub_get_wakeup_cause(void) +{ + return rtc_cntl_ll_get_wakeup_cause(); +} diff --git a/components/esp_system/ld/esp32/sections.ld.in b/components/esp_system/ld/esp32/sections.ld.in index 5dffe85b09..089bc26f7e 100644 --- a/components/esp_system/ld/esp32/sections.ld.in +++ b/components/esp_system/ld/esp32/sections.ld.in @@ -63,7 +63,7 @@ SECTIONS mapping[rtc_data] - *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*) + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.*) _rtc_data_end = ABSOLUTE(.); } > rtc_data_location diff --git a/components/esp_system/ld/esp32c3/sections.ld.in b/components/esp_system/ld/esp32c3/sections.ld.in index d6670bf759..ac7ab6cfb8 100644 --- a/components/esp_system/ld/esp32c3/sections.ld.in +++ b/components/esp_system/ld/esp32c3/sections.ld.in @@ -59,7 +59,7 @@ SECTIONS mapping[rtc_data] - *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*) + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .srodata.*) _rtc_data_end = ABSOLUTE(.); } > rtc_data_location @@ -67,7 +67,7 @@ SECTIONS .rtc.bss (NOLOAD) : { _rtc_bss_start = ABSOLUTE(.); - *rtc_wake_stub*.*(.bss .bss.*) + *rtc_wake_stub*.*(.bss .bss.* .sbss .sbss.*) *rtc_wake_stub*.*(COMMON) mapping[rtc_bss] diff --git a/components/esp_system/ld/esp32c6/sections.ld.in b/components/esp_system/ld/esp32c6/sections.ld.in index b32633a5e5..7a17be374e 100644 --- a/components/esp_system/ld/esp32c6/sections.ld.in +++ b/components/esp_system/ld/esp32c6/sections.ld.in @@ -59,7 +59,7 @@ SECTIONS mapping[rtc_data] - *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*) + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .srodata.*) _rtc_data_end = ABSOLUTE(.); } > lp_ram_seg @@ -67,7 +67,7 @@ SECTIONS .rtc.bss (NOLOAD) : { _rtc_bss_start = ABSOLUTE(.); - *rtc_wake_stub*.*(.bss .bss.*) + *rtc_wake_stub*.*(.bss .bss.* .sbss .sbss.*) *rtc_wake_stub*.*(COMMON) mapping[rtc_bss] diff --git a/components/esp_system/ld/esp32h2/sections.ld.in b/components/esp_system/ld/esp32h2/sections.ld.in index 6ce606d2a0..68508de11b 100644 --- a/components/esp_system/ld/esp32h2/sections.ld.in +++ b/components/esp_system/ld/esp32h2/sections.ld.in @@ -59,7 +59,7 @@ SECTIONS mapping[rtc_data] - *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*) + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .srodata.*) _rtc_data_end = ABSOLUTE(.); } > lp_ram_seg @@ -67,7 +67,7 @@ SECTIONS .rtc.bss (NOLOAD) : { _rtc_bss_start = ABSOLUTE(.); - *rtc_wake_stub*.*(.bss .bss.*) + *rtc_wake_stub*.*(.bss .bss.* .sbss .sbss.*) *rtc_wake_stub*.*(COMMON) mapping[rtc_bss] diff --git a/components/esp_system/ld/esp32h4/sections.ld.in b/components/esp_system/ld/esp32h4/sections.ld.in index 47412fa31d..ec03a82fb2 100644 --- a/components/esp_system/ld/esp32h4/sections.ld.in +++ b/components/esp_system/ld/esp32h4/sections.ld.in @@ -61,7 +61,7 @@ SECTIONS mapping[rtc_data] - *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*) + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .srodata.*) _rtc_data_end = ABSOLUTE(.); } > rtc_data_location @@ -69,7 +69,7 @@ SECTIONS .rtc.bss (NOLOAD) : { _rtc_bss_start = ABSOLUTE(.); - *rtc_wake_stub*.*(.bss .bss.*) + *rtc_wake_stub*.*(.bss .bss.* .sbss .sbss.*) *rtc_wake_stub*.*(COMMON) mapping[rtc_bss] diff --git a/components/esp_system/ld/esp32s2/sections.ld.in b/components/esp_system/ld/esp32s2/sections.ld.in index 44f2b8da5e..1ea6eaa606 100644 --- a/components/esp_system/ld/esp32s2/sections.ld.in +++ b/components/esp_system/ld/esp32s2/sections.ld.in @@ -71,7 +71,7 @@ SECTIONS mapping[rtc_data] - *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*) + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.*) _rtc_data_end = ABSOLUTE(.); } > rtc_data_location diff --git a/components/esp_system/ld/esp32s3/sections.ld.in b/components/esp_system/ld/esp32s3/sections.ld.in index ab48772187..efe69736e9 100644 --- a/components/esp_system/ld/esp32s3/sections.ld.in +++ b/components/esp_system/ld/esp32s3/sections.ld.in @@ -65,7 +65,7 @@ SECTIONS mapping[rtc_data] - *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*) + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.*) _rtc_data_end = ABSOLUTE(.); } > rtc_data_location diff --git a/components/esp_system/test/test_sleep.c b/components/esp_system/test/test_sleep.c index d2564ff79a..dd5f34a10f 100644 --- a/components/esp_system/test/test_sleep.c +++ b/components/esp_system/test/test_sleep.c @@ -445,8 +445,7 @@ __attribute__((unused)) static float get_time_ms(void) __attribute__((unused)) static uint32_t get_cause(void) { - uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, \ - RTC_CNTL_WAKEUP_CAUSE); + uint32_t wakeup_cause = rtc_cntl_ll_get_wakeup_cause(); return wakeup_cause; } diff --git a/components/hal/esp32/include/hal/rtc_cntl_ll.h b/components/hal/esp32/include/hal/rtc_cntl_ll.h index 30d24e60d7..7e87d1d2ab 100644 --- a/components/hal/esp32/include/hal/rtc_cntl_ll.h +++ b/components/hal/esp32/include/hal/rtc_cntl_ll.h @@ -8,71 +8,107 @@ #include "soc/soc.h" #include "soc/rtc.h" - +#include "esp_attr.h" +#include "clk_tree_ll.h" +#include "esp_rom_sys.h" #ifdef __cplusplus extern "C" { #endif -static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_wakeup_timer(uint64_t t) { WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX); WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32); } -static inline void rtc_cntl_ll_ext1_clear_wakeup_status(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_clear_wakeup_status(void) { REG_SET_BIT(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_STATUS_CLR); } -static inline uint32_t rtc_cntl_ll_ext1_get_wakeup_status(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_ext1_get_wakeup_status(void) { return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS); } -static inline void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode) +FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode) { REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, mask); SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1, mode, RTC_CNTL_EXT_WAKEUP1_LV_S); } -static inline void rtc_cntl_ll_ext1_clear_wakeup_pins(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_clear_wakeup_pins(void) { CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL_M); } -static inline uint32_t rtc_cntl_ll_ext1_get_wakeup_pins(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_ext1_get_wakeup_pins(void) { return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL); } -static inline void rtc_cntl_ll_ulp_wakeup_enable(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_ulp_wakeup_enable(void) { SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_WAKEUP_FORCE_EN); } -static inline void rtc_cntl_ll_ulp_int_clear(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_ulp_int_clear(void) { REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_SAR_INT_CLR); } -static inline void rtc_cntl_ll_timer2_set_touch_wait_cycle(uint32_t wait_cycle) +FORCE_INLINE_ATTR void rtc_cntl_ll_timer2_set_touch_wait_cycle(uint32_t wait_cycle) { REG_SET_FIELD(RTC_CNTL_TIMER2_REG, RTC_CNTL_ULPCP_TOUCH_START_WAIT, wait_cycle); } -static inline void rtc_cntl_ll_reset_system(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_system(void) { REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); } -static inline void rtc_cntl_ll_reset_cpu(int cpu_no) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_cpu(int cpu_no) { uint32_t rtc_cntl_rst = (cpu_no == 0) ? RTC_CNTL_SW_PROCPU_RST : RTC_CNTL_SW_APPCPU_RST; REG_WRITE(RTC_CNTL_OPTIONS0_REG, rtc_cntl_rst); } +FORCE_INLINE_ATTR void rtc_cntl_ll_sleep_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN); +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_get_rtc_time(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); + int attempts = 1000; + while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) { + esp_rom_delay_us(1); + if (attempts) { + if (--attempts == 0 && clk_ll_xtal32k_digi_is_enabled()) { + esp_rom_printf("32KHz xtal has been stopped\n"); + } + } + } + SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG, RTC_CNTL_TIME_VALID_INT_CLR); + uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); + t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; + return t; +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_time_to_count(uint64_t time_in_us) +{ + uint32_t slow_clk_value = REG_READ(RTC_CNTL_STORE1_REG); + return ((time_in_us * (1 << RTC_CLK_CAL_FRACT)) / slow_clk_value); +} + +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_get_wakeup_cause(void) +{ + return REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c2/include/hal/rtc_cntl_ll.h b/components/hal/esp32c2/include/hal/rtc_cntl_ll.h index a10f4912b4..585ebd9bd6 100644 --- a/components/hal/esp32c2/include/hal/rtc_cntl_ll.h +++ b/components/hal/esp32c2/include/hal/rtc_cntl_ll.h @@ -10,12 +10,13 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "soc/syscon_reg.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_wakeup_timer(uint64_t t) { WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX); WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32); @@ -24,18 +25,18 @@ static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) SET_PERI_REG_MASK(RTC_CNTL_SLP_TIMER1_REG, RTC_CNTL_MAIN_TIMER_ALARM_EN_M); } -static inline uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) { return GET_PERI_REG_MASK(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS); } -static inline void rtc_cntl_ll_gpio_clear_wakeup_status(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_gpio_clear_wakeup_status(void) { REG_SET_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS_CLR); REG_CLR_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS_CLR); } -static inline void rtc_cntl_ll_enable_cpu_retention(uint32_t addr) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention(uint32_t addr) { /* write memory address to register */ REG_SET_FIELD(SYSCON_RETENTION_CTRL_REG, SYSCON_RETENTION_LINK_ADDR, (uint32_t)addr); @@ -45,21 +46,45 @@ static inline void rtc_cntl_ll_enable_cpu_retention(uint32_t addr) REG_SET_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN); } -static inline void rtc_cntl_ll_disable_cpu_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_disable_cpu_retention(void) { REG_CLR_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN); } -static inline void rtc_cntl_ll_reset_system(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_system(void) { REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); } -static inline void rtc_cntl_ll_reset_cpu(int cpu_no) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_cpu(int cpu_no) { REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_PROCPU_RST); } +FORCE_INLINE_ATTR void rtc_cntl_ll_sleep_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN); +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_get_rtc_time(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); + uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); + t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; + return t; +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_time_to_count(uint64_t time_in_us) +{ + uint32_t slow_clk_value = REG_READ(RTC_CNTL_STORE1_REG); + return ((time_in_us * (1 << RTC_CLK_CAL_FRACT)) / slow_clk_value); +} + +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_get_wakeup_cause(void) +{ + return REG_GET_FIELD(RTC_CNTL_SLP_WAKEUP_CAUSE_REG, RTC_CNTL_WAKEUP_CAUSE); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/include/hal/rtc_cntl_ll.h b/components/hal/esp32c3/include/hal/rtc_cntl_ll.h index 50dcb59a88..0fa0e3a606 100644 --- a/components/hal/esp32c3/include/hal/rtc_cntl_ll.h +++ b/components/hal/esp32c3/include/hal/rtc_cntl_ll.h @@ -10,12 +10,13 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "soc/syscon_reg.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_wakeup_timer(uint64_t t) { WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX); WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32); @@ -24,48 +25,72 @@ static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) SET_PERI_REG_MASK(RTC_CNTL_SLP_TIMER1_REG, RTC_CNTL_MAIN_TIMER_ALARM_EN_M); } -static inline uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) { return GET_PERI_REG_MASK(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS); } -static inline void rtc_cntl_ll_gpio_clear_wakeup_status(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_gpio_clear_wakeup_status(void) { REG_SET_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS_CLR); REG_CLR_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS_CLR); } -static inline void rtc_cntl_ll_set_cpu_retention_link_addr(uint32_t addr) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_cpu_retention_link_addr(uint32_t addr) { REG_SET_FIELD(SYSCON_RETENTION_CTRL_REG, SYSCON_RETENTION_LINK_ADDR, (uint32_t)addr); } -static inline void rtc_cntl_ll_enable_cpu_retention_clock(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention_clock(void) { REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN); } -static inline void rtc_cntl_ll_enable_cpu_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention(void) { /* Enable retention when cpu sleep enable */ REG_SET_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN); } -static inline void rtc_cntl_ll_disable_cpu_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_disable_cpu_retention(void) { REG_CLR_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN); } -static inline void rtc_cntl_ll_reset_system(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_system(void) { REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); } -static inline void rtc_cntl_ll_reset_cpu(int cpu_no) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_cpu(int cpu_no) { REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_PROCPU_RST); } +FORCE_INLINE_ATTR void rtc_cntl_ll_sleep_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN); +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_get_rtc_time(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); + uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); + t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; + return t; +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_time_to_count(uint64_t time_in_us) +{ + uint32_t slow_clk_value = REG_READ(RTC_CNTL_STORE1_REG); + return ((time_in_us * (1 << RTC_CLK_CAL_FRACT)) / slow_clk_value); +} + +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_get_wakeup_cause(void) +{ + return REG_GET_FIELD(RTC_CNTL_SLP_WAKEUP_CAUSE_REG, RTC_CNTL_WAKEUP_CAUSE); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/rtc_cntl_ll.h b/components/hal/esp32c6/include/hal/rtc_cntl_ll.h index 058a53a2e1..25a1f55372 100644 --- a/components/hal/esp32c6/include/hal/rtc_cntl_ll.h +++ b/components/hal/esp32c6/include/hal/rtc_cntl_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,57 +9,81 @@ #include "soc/soc.h" #include "soc/rtc.h" #include "soc/lp_aon_reg.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_wakeup_timer(uint64_t t) { // TODO: IDF-5645 } -static inline uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) { // TODO: IDF-5645 return 0; } -static inline void rtc_cntl_ll_gpio_clear_wakeup_status(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_gpio_clear_wakeup_status(void) { // TODO: IDF-5645 } -static inline void rtc_cntl_ll_set_cpu_retention_link_addr(uint32_t addr) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_cpu_retention_link_addr(uint32_t addr) { // TODO: IDF-5718 has removed the retention feature } -static inline void rtc_cntl_ll_enable_cpu_retention_clock(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention_clock(void) { // TODO: IDF-5718 has removed the retention feature } -static inline void rtc_cntl_ll_enable_cpu_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention(void) { // TODO: IDF-5718 has removed the retention feature } -static inline void rtc_cntl_ll_disable_cpu_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_disable_cpu_retention(void) { // TODO: IDF-5718 has removed the retention feature } -static inline void rtc_cntl_ll_reset_system(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_system(void) { REG_SET_BIT(LP_AON_SYS_CFG_REG, LP_AON_HPSYS_SW_RESET); } -static inline void rtc_cntl_ll_reset_cpu(int cpu_no) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_cpu(int cpu_no) { REG_SET_BIT(LP_AON_CPUCORE0_CFG_REG, LP_AON_CPU_CORE0_SW_RESET); } +FORCE_INLINE_ATTR void rtc_cntl_ll_sleep_enable(void) +{ + // TODO: IDF-6064 +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_get_rtc_time(void) +{ + // TODO: IDF-6064 + return 0; +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_time_to_count(uint64_t time_in_us) +{ + // TODO: IDF-6064 + return 0; +} + +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_get_wakeup_cause(void) +{ + // TODO: IDF-6064 + return 0; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h2/include/hal/rtc_cntl_ll.h b/components/hal/esp32h2/include/hal/rtc_cntl_ll.h index 3817849cad..2df27b8dcf 100644 --- a/components/hal/esp32h2/include/hal/rtc_cntl_ll.h +++ b/components/hal/esp32h2/include/hal/rtc_cntl_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,63 +8,87 @@ #include "soc/soc.h" #include "soc/rtc.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_wakeup_timer(uint64_t t) { // ESP32H2-TODO: IDF-6401 } -static inline uint32_t rtc_cntl_ll_gpio_get_wakeup_pins(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_gpio_get_wakeup_pins(void) { return 0; // ESP32H2-TODO: IDF-6401 } -static inline uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) { // ESP32H2-TODO: IDF-6401 return 0; } -static inline void rtc_cntl_ll_gpio_clear_wakeup_status(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_gpio_clear_wakeup_status(void) { // ESP32H2-TODO: IDF-6401 } -static inline void rtc_cntl_ll_gpio_set_wakeup_pins(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_gpio_set_wakeup_pins(void) { // ESP32H2-TODO: IDF-5718 } -static inline void rtc_cntl_ll_gpio_clear_wakeup_pins(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_gpio_clear_wakeup_pins(void) { // ESP32H2-TODO: IDF-5718 } -static inline void rtc_cntl_ll_set_cpu_retention_link_addr(uint32_t addr) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_cpu_retention_link_addr(uint32_t addr) { // ESP32H2-TODO: IDF-5718 has removed the retention feature } -static inline void rtc_cntl_ll_enable_cpu_retention_clock(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention_clock(void) { // ESP32H2-TODO: IDF-5718 has removed the retention feature } -static inline void rtc_cntl_ll_enable_cpu_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention(void) { // ESP32H2-TODO: IDF-5718 has removed the retention feature } -static inline void rtc_cntl_ll_disable_cpu_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_disable_cpu_retention(void) { // ESP32H2-TODO: IDF-5718 has removed the retention feature } +FORCE_INLINE_ATTR void rtc_cntl_ll_sleep_enable(void) +{ + // TODO: IDF-6572 +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_get_rtc_time(void) +{ + // TODO: IDF-6572 + return 0; +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_time_to_count(uint64_t time_in_us) +{ + // TODO: IDF-6572 + return 0; +} + +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_get_wakeup_cause(void) +{ + // TODO: IDF-6572 + return 0; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h4/include/hal/rtc_cntl_ll.h b/components/hal/esp32h4/include/hal/rtc_cntl_ll.h index c3839240bc..0f086e5f62 100644 --- a/components/hal/esp32h4/include/hal/rtc_cntl_ll.h +++ b/components/hal/esp32h4/include/hal/rtc_cntl_ll.h @@ -10,12 +10,13 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "soc/syscon_reg.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_wakeup_timer(uint64_t t) { WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX); WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32); @@ -24,37 +25,61 @@ static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) SET_PERI_REG_MASK(RTC_CNTL_SLP_TIMER1_REG, RTC_CNTL_MAIN_TIMER_ALARM_EN_M); } -static inline uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) { return GET_PERI_REG_MASK(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS); } -static inline void rtc_cntl_ll_gpio_clear_wakeup_status(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_gpio_clear_wakeup_status(void) { REG_SET_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS_CLR); REG_CLR_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS_CLR); } -static inline void rtc_cntl_ll_enable_cpu_retention(uint32_t addr) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention(uint32_t addr) { // ESP32H4-TODO: IDF-3383 } -static inline void rtc_cntl_ll_disable_cpu_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_disable_cpu_retention(void) { // ESP32H4-TODO: IDF-3383 } -static inline void rtc_cntl_ll_reset_system(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_system(void) { REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); } -static inline void rtc_cntl_ll_reset_cpu(int cpu_no) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_cpu(int cpu_no) { REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_PROCPU_RST); } +FORCE_INLINE_ATTR void rtc_cntl_ll_sleep_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN); +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_get_rtc_time(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); + uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); + t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; + return t; +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_time_to_count(uint64_t time_in_us) +{ + uint32_t slow_clk_value = REG_READ(RTC_CNTL_STORE1_REG); + return ((time_in_us * (1 << RTC_CLK_CAL_FRACT)) / slow_clk_value); +} + +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_get_wakeup_cause(void) +{ + return REG_GET_FIELD(RTC_CNTL_SLP_WAKEUP_CAUSE_REG, RTC_CNTL_WAKEUP_CAUSE); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s2/include/hal/rtc_cntl_ll.h b/components/hal/esp32s2/include/hal/rtc_cntl_ll.h index 885422569e..0ccdedc879 100644 --- a/components/hal/esp32s2/include/hal/rtc_cntl_ll.h +++ b/components/hal/esp32s2/include/hal/rtc_cntl_ll.h @@ -9,12 +9,13 @@ #include "soc/soc.h" #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_wakeup_timer(uint64_t t) { WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX); WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32); @@ -23,55 +24,79 @@ static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) SET_PERI_REG_MASK(RTC_CNTL_SLP_TIMER1_REG, RTC_CNTL_MAIN_TIMER_ALARM_EN_M); } -static inline void rtc_cntl_ll_ext1_clear_wakeup_status(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_clear_wakeup_status(void) { REG_SET_BIT(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_STATUS_CLR); } -static inline uint32_t rtc_cntl_ll_ext1_get_wakeup_status(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_ext1_get_wakeup_status(void) { return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS); } -static inline void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode) +FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode) { REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, mask); SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1, mode, RTC_CNTL_EXT_WAKEUP1_LV_S); } -static inline void rtc_cntl_ll_ext1_clear_wakeup_pins(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_clear_wakeup_pins(void) { CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL_M); } -static inline uint32_t rtc_cntl_ll_ext1_get_wakeup_pins(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_ext1_get_wakeup_pins(void) { return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL); } -static inline void rtc_cntl_ll_ulp_int_clear(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_ulp_int_clear(void) { REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_ULP_CP_INT_CLR); REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_COCPU_INT_CLR); REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_COCPU_TRAP_INT_CLR); } -static inline void rtc_cntl_ll_timer2_set_touch_wait_cycle(uint32_t wait_cycle) +FORCE_INLINE_ATTR void rtc_cntl_ll_timer2_set_touch_wait_cycle(uint32_t wait_cycle) { REG_SET_FIELD(RTC_CNTL_TIMER2_REG, RTC_CNTL_ULPCP_TOUCH_START_WAIT, wait_cycle); } -static inline void rtc_cntl_ll_reset_system(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_system(void) { REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); } -static inline void rtc_cntl_ll_reset_cpu(int cpu_no) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_cpu(int cpu_no) { REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_PROCPU_RST); } +FORCE_INLINE_ATTR void rtc_cntl_ll_sleep_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN); +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_get_rtc_time(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); + uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); + t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; + return t; +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_time_to_count(uint64_t time_in_us) +{ + uint32_t slow_clk_value = REG_READ(RTC_CNTL_STORE1_REG); + return ((time_in_us * (1 << RTC_CLK_CAL_FRACT)) / slow_clk_value); +} + +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_get_wakeup_cause(void) +{ + return REG_GET_FIELD(RTC_CNTL_SLP_WAKEUP_CAUSE_REG, RTC_CNTL_WAKEUP_CAUSE); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/rtc_cntl_ll.h b/components/hal/esp32s3/include/hal/rtc_cntl_ll.h index e57532808f..464aa99cd6 100644 --- a/components/hal/esp32s3/include/hal/rtc_cntl_ll.h +++ b/components/hal/esp32s3/include/hal/rtc_cntl_ll.h @@ -10,6 +10,7 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "soc/apb_ctrl_reg.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { @@ -18,7 +19,7 @@ extern "C" { #define RTC_CNTL_LL_RETENTION_TARGET_CPU (BIT(0)) #define RTC_CNTL_LL_RETENTION_TARGET_TAGMEM (BIT(1)) -static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_wakeup_timer(uint64_t t) { WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX); WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32); @@ -27,46 +28,46 @@ static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) SET_PERI_REG_MASK(RTC_CNTL_SLP_TIMER1_REG, RTC_CNTL_MAIN_TIMER_ALARM_EN_M); } -static inline void rtc_cntl_ll_ext1_clear_wakeup_status(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_clear_wakeup_status(void) { REG_SET_BIT(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_STATUS_CLR); } -static inline uint32_t rtc_cntl_ll_ext1_get_wakeup_status(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_ext1_get_wakeup_status(void) { return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS); } -static inline void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode) +FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode) { REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, mask); SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1, mode, RTC_CNTL_EXT_WAKEUP1_LV_S); } -static inline void rtc_cntl_ll_ext1_clear_wakeup_pins(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_ext1_clear_wakeup_pins(void) { CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL_M); } -static inline uint32_t rtc_cntl_ll_ext1_get_wakeup_pins(void) +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_ext1_get_wakeup_pins(void) { return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL); } -static inline void rtc_cntl_ll_set_tagmem_retention_link_addr(uint32_t link_addr) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_tagmem_retention_link_addr(uint32_t link_addr) { REG_SET_FIELD(APB_CTRL_RETENTION_CTRL1_REG, APB_CTRL_RETENTION_TAG_LINK_ADDR, link_addr); } -static inline void rtc_cntl_ll_enable_tagmem_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_tagmem_retention(void) { /* Enable i/d-cache tagmem retenttion. cpu: 1, tagmem: 2, cpu + tagmem: 3 */ uint32_t target = REG_GET_FIELD(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_TARGET); REG_SET_FIELD(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_TARGET, (target | RTC_CNTL_LL_RETENTION_TARGET_TAGMEM)); } -static inline void rtc_cntl_ll_enable_icache_tagmem_retention(uint32_t start_point, uint32_t vld_size, uint32_t size) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_icache_tagmem_retention(uint32_t start_point, uint32_t vld_size, uint32_t size) { REG_SET_FIELD(APB_CTRL_RETENTION_CTRL2_REG, APB_CTRL_RET_ICACHE_START_POINT, start_point); REG_SET_FIELD(APB_CTRL_RETENTION_CTRL2_REG, APB_CTRL_RET_ICACHE_VLD_SIZE, vld_size); @@ -74,7 +75,7 @@ static inline void rtc_cntl_ll_enable_icache_tagmem_retention(uint32_t start_poi REG_SET_BIT(APB_CTRL_RETENTION_CTRL2_REG, APB_CTRL_RET_ICACHE_ENABLE); } -static inline void rtc_cntl_ll_enable_dcache_tagmem_retention(uint32_t start_point, uint32_t vld_size, uint32_t size) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_dcache_tagmem_retention(uint32_t start_point, uint32_t vld_size, uint32_t size) { REG_SET_FIELD(APB_CTRL_RETENTION_CTRL3_REG, APB_CTRL_RET_DCACHE_START_POINT, start_point); REG_SET_FIELD(APB_CTRL_RETENTION_CTRL3_REG, APB_CTRL_RET_DCACHE_VLD_SIZE, vld_size); @@ -82,34 +83,34 @@ static inline void rtc_cntl_ll_enable_dcache_tagmem_retention(uint32_t start_poi REG_SET_BIT(APB_CTRL_RETENTION_CTRL3_REG, APB_CTRL_RET_DCACHE_ENABLE); } -static inline void rtc_cntl_ll_disable_tagmem_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_disable_tagmem_retention(void) { /* Enable i/d-cache tagmem retenttion. cpu: 1, tagmem: 2, cpu + tagmem: 3 */ uint32_t target = REG_GET_FIELD(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_TARGET); REG_SET_FIELD(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_TARGET, (target & ~RTC_CNTL_LL_RETENTION_TARGET_TAGMEM)); } -static inline void rtc_cntl_ll_disable_icache_tagmem_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_disable_icache_tagmem_retention(void) { REG_CLR_BIT(APB_CTRL_RETENTION_CTRL2_REG, APB_CTRL_RET_ICACHE_ENABLE); } -static inline void rtc_cntl_ll_disable_dcache_tagmem_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_disable_dcache_tagmem_retention(void) { REG_CLR_BIT(APB_CTRL_RETENTION_CTRL3_REG, APB_CTRL_RET_DCACHE_ENABLE); } -static inline void rtc_cntl_ll_set_cpu_retention_link_addr(uint32_t link_addr) +FORCE_INLINE_ATTR void rtc_cntl_ll_set_cpu_retention_link_addr(uint32_t link_addr) { REG_SET_FIELD(APB_CTRL_RETENTION_CTRL_REG, APB_CTRL_RETENTION_CPU_LINK_ADDR, link_addr); } -static inline void rtc_cntl_ll_enable_cpu_retention_clock(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention_clock(void) { REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN); /* Enable internal 20 MHz clock */ } -static inline void rtc_cntl_ll_enable_cpu_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_enable_cpu_retention(void) { uint32_t target = REG_GET_FIELD(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_TARGET); @@ -118,41 +119,65 @@ static inline void rtc_cntl_ll_enable_cpu_retention(void) REG_SET_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN); } -static inline void rtc_cntl_ll_config_cpu_retention_timing(int wait, int clkoff_wait, int done_wait) +FORCE_INLINE_ATTR void rtc_cntl_ll_config_cpu_retention_timing(int wait, int clkoff_wait, int done_wait) { REG_SET_FIELD(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_WAIT, wait); REG_SET_FIELD(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_CLKOFF_WAIT, clkoff_wait); REG_SET_FIELD(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_DONE_WAIT, done_wait); } -static inline void rtc_cntl_ll_disable_cpu_retention(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_disable_cpu_retention(void) { REG_CLR_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN); } -static inline void rtc_cntl_ll_ulp_int_clear(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_ulp_int_clear(void) { REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_ULP_CP_INT_CLR); REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_COCPU_INT_CLR); REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_COCPU_TRAP_INT_CLR); } -static inline void rtc_cntl_ll_timer2_set_touch_wait_cycle(uint32_t wait_cycle) +FORCE_INLINE_ATTR void rtc_cntl_ll_timer2_set_touch_wait_cycle(uint32_t wait_cycle) { REG_SET_FIELD(RTC_CNTL_TIMER2_REG, RTC_CNTL_ULPCP_TOUCH_START_WAIT, wait_cycle); } -static inline void rtc_cntl_ll_reset_system(void) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_system(void) { REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); } -static inline void rtc_cntl_ll_reset_cpu(int cpu_no) +FORCE_INLINE_ATTR void rtc_cntl_ll_reset_cpu(int cpu_no) { uint32_t rtc_cntl_rst = (cpu_no == 0) ? RTC_CNTL_SW_PROCPU_RST : RTC_CNTL_SW_APPCPU_RST; REG_WRITE(RTC_CNTL_OPTIONS0_REG, rtc_cntl_rst); } +FORCE_INLINE_ATTR void rtc_cntl_ll_sleep_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN); +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_get_rtc_time(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); + uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); + t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; + return t; +} + +FORCE_INLINE_ATTR uint64_t rtc_cntl_ll_time_to_count(uint64_t time_in_us) +{ + uint32_t slow_clk_value = REG_READ(RTC_CNTL_STORE1_REG); + return ((time_in_us * (1 << RTC_CLK_CAL_FRACT)) / slow_clk_value); +} + +FORCE_INLINE_ATTR uint32_t rtc_cntl_ll_get_wakeup_cause(void) +{ + return REG_GET_FIELD(RTC_CNTL_SLP_WAKEUP_CAUSE_REG, RTC_CNTL_WAKEUP_CAUSE); +} + #ifdef __cplusplus } #endif diff --git a/docs/en/api-guides/deep-sleep-stub.rst b/docs/en/api-guides/deep-sleep-stub.rst index 8c59f5bbb0..4c96e3180f 100644 --- a/docs/en/api-guides/deep-sleep-stub.rst +++ b/docs/en/api-guides/deep-sleep-stub.rst @@ -115,3 +115,12 @@ CRC Check For Wake Stubs .. note:: When the `CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP` option is enabled, all the RTC fast memory except the wake stubs area is added to the heap. + +Example +------- + +.. only:: SOC_RTC_FAST_MEM_SUPPORTED + +ESP-IDF provides an example to show how to implement the Deep-sleep wake stub. + +- :example:`system/deep_sleep_wake_stub` diff --git a/examples/system/.build-test-rules.yml b/examples/system/.build-test-rules.yml index cd4b610aef..05c458b38a 100644 --- a/examples/system/.build-test-rules.yml +++ b/examples/system/.build-test-rules.yml @@ -42,6 +42,12 @@ examples/system/deep_sleep: temporary: true reason: target(s) not supported yet +examples/system/deep_sleep_wake_stub: + disable: + - if: IDF_TARGET in ["esp32c2", "esp32c6", "esp32h2"] + temporary: true + reason: target(s) is not supported yet + examples/system/efuse: disable_test: - if: IDF_TARGET == "esp32s3" diff --git a/examples/system/deep_sleep/README.md b/examples/system/deep_sleep/README.md index a22ecabd6f..60a03d51c6 100644 --- a/examples/system/deep_sleep/README.md +++ b/examples/system/deep_sleep/README.md @@ -68,7 +68,7 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui ## Example Output -On initial startup, this example will detect that this is the first boot and output the following low: +On initial startup, this example will detect that this is the first boot and output the following log: ``` ... diff --git a/examples/system/deep_sleep_wake_stub/CMakeLists.txt b/examples/system/deep_sleep_wake_stub/CMakeLists.txt new file mode 100644 index 0000000000..ce31ed4013 --- /dev/null +++ b/examples/system/deep_sleep_wake_stub/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(deep_sleep_wake_stub) diff --git a/examples/system/deep_sleep_wake_stub/README.md b/examples/system/deep_sleep_wake_stub/README.md new file mode 100644 index 0000000000..c93e69a9dd --- /dev/null +++ b/examples/system/deep_sleep_wake_stub/README.md @@ -0,0 +1,75 @@ +| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | + +# Deep Sleep Wake Stub Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +The [Deep-sleep wake stub](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/deep-sleep-stub.html) is used to RTC fast boot mode that avoid the SPI flash booting, thus speeding up the wakeup process. This example demonstrates how to implement the wake stub. + +In this example, the `CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` Kconfig option is used, which allows you to reduce the boot time of the bootloader during waking up from deep sleep. The bootloader stores in rtc memory the address of a running partition and uses it when it wakes up. This example allows you to skip all image checks and speed up the boot. + +## How to use example + +### Hardware Required + +This example should be able to run on any commonly available ESP32/ESP32-S2/ESP32-S3/ESP32-C3 development board without any extra hardware if only **Timer** wake up sources are used. + +### Configure the project + + +``` +idf.py menuconfig +``` + +* **Wake up time** can be configured via `Example configuration > Wake up interval in seconds` +Wake up sources that are unused or unconnected should be disabled in configuration to prevent inadvertent triggering of wake up as a result of floating pins. + + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(Replace PORT with the name of the serial port to use.) + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +On initial startup, this example will detect that this is the first boot and output the following log: + +``` +... +I (309) cpu_start: Starting scheduler on PRO CPU. +I (0) cpu_start: Starting scheduler on APP CPU. +Not a deep sleep reset +Enabling timer wakeup, 10s +Entering deep sleep +``` + +The ESP chips will then enter deep sleep. When a timer wake up occurs, if deep sleep wake stub enabled, the ESP chips will boot from RTC memory and execute stub code. The output log such as the following: + +``` +... +ESP-ROM:esp32s3-20210327 +Build:Mar 27 2021 +rst:0x5 (DSLEEP),boot:0x8 (SPI_FAST_FLASH_BOOT) +wake stub: wakeup count is 1, wakeup cause is 8 +wake stub: going to deep sleep +ESP-ROM:esp32s3-20210327 +Build:Mar 27 2021 +rst:0x5 (DSLEEP),boot:0x8 (SPI_FAST_FLASH_BOOT) +wake stub: wakeup count is 2, wakeup cause is 8 +wake stub: going to deep sleep +ESP-ROM:esp32s3-20210327 +Build:Mar 27 2021 +rst:0x5 (DSLEEP),boot:0x8 (SPI_FAST_FLASH_BOOT) +wake stub: wakeup count is 3, wakeup cause is 8 +wake stub: going to deep sleep +``` diff --git a/examples/system/deep_sleep_wake_stub/main/CMakeLists.txt b/examples/system/deep_sleep_wake_stub/main/CMakeLists.txt new file mode 100644 index 0000000000..f7d75837a3 --- /dev/null +++ b/examples/system/deep_sleep_wake_stub/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "wake_stub_example_main.c" + "rtc_wake_stub_example.c" + INCLUDE_DIRS ".") diff --git a/examples/system/deep_sleep_wake_stub/main/Kconfig.projbuild b/examples/system/deep_sleep_wake_stub/main/Kconfig.projbuild new file mode 100644 index 0000000000..ff7a20ca73 --- /dev/null +++ b/examples/system/deep_sleep_wake_stub/main/Kconfig.projbuild @@ -0,0 +1,10 @@ +menu "Example Configuration" + + config WAKE_UP_TIME + int "Wake up interval in seconds" + default 10 + range 1 60 + help + Configurable wake up interval in seconds. + +endmenu diff --git a/examples/system/deep_sleep_wake_stub/main/rtc_wake_stub_example.c b/examples/system/deep_sleep_wake_stub/main/rtc_wake_stub_example.c new file mode 100644 index 0000000000..628af418c1 --- /dev/null +++ b/examples/system/deep_sleep_wake_stub/main/rtc_wake_stub_example.c @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include "esp_sleep.h" +#include "esp_wake_stub.h" +#include "sdkconfig.h" + +/* + * Deep sleep wake stub function is a piece of code that will be loaded into 'RTC Fast Memory'. + * The first way is to use the RTC_IRAM_ATTR attribute to place a function into RTC memory, + * The second way is to place the function into any source file whose name starts with rtc_wake_stub. + * Files names rtc_wake_stub* have their contents automatically put into RTC memory by the linker. + * + * First, call esp_set_deep_sleep_wake_stub to set the wake stub function as the RTC stub entry, + * The wake stub function runs immediately as soon as the chip wakes up - before any normal + * initialisation, bootloader, or ESP-IDF code has run. After the wake stub runs, the SoC + * can go back to sleep or continue to start ESP-IDF normally. + * + * Wake stub code must be carefully written, there are some rules for wake stub: + * 1) The wake stub code can only access data loaded in RTC memory. + * 2) The wake stub code can only call functions implemented in ROM or loaded into RTC Fast Memory. + * 3) RTC memory must include any read-only data (.rodata) used by the wake stub. + */ + +// counter value, stored in RTC memory +static uint32_t s_count = 0; +static const uint32_t s_max_count = 20; + +// wakeup_cause stored in RTC memory +static uint32_t wakeup_cause; + +// wake up stub function stored in RTC memory +void wake_stub_example(void) +{ + // Get wakeup cause. + wakeup_cause = esp_wake_stub_get_wakeup_cause(); + // Increment the counter. + s_count++; + // Print the counter value and wakeup cause. + ESP_RTC_LOGI("wake stub: wakeup count is %d, wakeup cause is %d", s_count, wakeup_cause); + + if (s_count >= s_max_count) { + // Reset s_count + s_count = 0; + + // Set the default wake stub. + // There is a default version of this function provided in esp-idf. + esp_default_wake_deep_sleep(); + + // Return from the wake stub function to continue + // booting the firmware. + return; + } + // s_count is < s_max_count, go back to deep sleep. + + // Set wakeup time in stub, if need to check GPIOs or read some sensor periodically in the stub. + esp_wake_stub_set_wakeup_time(CONFIG_WAKE_UP_TIME*1000000); + + // Print status. + ESP_RTC_LOGI("wake stub: going to deep sleep"); + + // Set stub entry, then going to deep sleep again. + esp_wake_stub_sleep(&wake_stub_example); +} diff --git a/examples/system/deep_sleep_wake_stub/main/rtc_wake_stub_example.h b/examples/system/deep_sleep_wake_stub/main/rtc_wake_stub_example.h new file mode 100644 index 0000000000..f62d6f7bb5 --- /dev/null +++ b/examples/system/deep_sleep_wake_stub/main/rtc_wake_stub_example.h @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void wake_stub_example(void); + +#ifdef __cplusplus +} +#endif diff --git a/examples/system/deep_sleep_wake_stub/main/wake_stub_example_main.c b/examples/system/deep_sleep_wake_stub/main/wake_stub_example_main.c new file mode 100644 index 0000000000..47e49bc939 --- /dev/null +++ b/examples/system/deep_sleep_wake_stub/main/wake_stub_example_main.c @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_sleep.h" +#include "esp_wake_stub.h" +#include "driver/rtc_io.h" +#include "rtc_wake_stub_example.h" + +// sleep_enter_time stored in RTC memory +static RTC_DATA_ATTR struct timeval sleep_enter_time; + +void app_main(void) +{ + struct timeval now; + gettimeofday(&now, NULL); + int sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000; + + if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TIMER) { + printf("Wake up from timer. Time spent in deep sleep: %dms\n", sleep_time_ms); + } + + vTaskDelay(1000 / portTICK_PERIOD_MS); + + const int wakeup_time_sec = CONFIG_WAKE_UP_TIME; + printf("Enabling timer wakeup, %ds\n", wakeup_time_sec); + esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000); + +#if CONFIG_IDF_TARGET_ESP32 + // Isolate GPIO12 pin from external circuits. This is needed for modules + // which have an external pull-up resistor on GPIO12 (such as ESP32-WROVER) + // to minimize current consumption. + rtc_gpio_isolate(GPIO_NUM_12); +#endif + + // Set the wake stub function + esp_set_deep_sleep_wake_stub(&wake_stub_example); + + printf("Entering deep sleep\n"); + gettimeofday(&sleep_enter_time, NULL); + + esp_deep_sleep_start(); +} diff --git a/examples/system/deep_sleep_wake_stub/pytest_deep_sleep_wake_stub.py b/examples/system/deep_sleep_wake_stub/pytest_deep_sleep_wake_stub.py new file mode 100644 index 0000000000..29482ca5d3 --- /dev/null +++ b/examples/system/deep_sleep_wake_stub/pytest_deep_sleep_wake_stub.py @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import logging +import time + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32 +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.esp32c3 +@pytest.mark.generic +@pytest.mark.parametrize('config', ['default',], indirect=True) +def test_deep_sleep_wake_stub(config: str, dut: Dut) -> None: + if config == 'default': + dut.expect_exact('Enabling timer wakeup, 10s', timeout=10) + dut.expect_exact('Entering deep sleep', timeout=10) + + start_sleep = time.time() + logging.info('Waiting for wakeup...') + dut.expect_exact('wake stub: going to deep sleep') + + sleep_time = time.time() - start_sleep + logging.info('Host measured sleep time at {:.2f}s'.format(sleep_time)) + assert 8 < sleep_time < 12 # note: high tolerance as measuring time on the host may have some timing skew diff --git a/examples/system/deep_sleep_wake_stub/sdkconfig.defaults b/examples/system/deep_sleep_wake_stub/sdkconfig.defaults new file mode 100644 index 0000000000..3ba7ab36b7 --- /dev/null +++ b/examples/system/deep_sleep_wake_stub/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y