docs: update api-guides/deep-sleep-stub

pull/13651/head
Linda 2023-08-07 19:33:46 +08:00
rodzic d9a6ae2b3c
commit 2dc0be81fb
1 zmienionych plików z 94 dodań i 68 usunięć

Wyświetl plik

@ -1,131 +1,157 @@
Deep Sleep Wake Stubs
=====================
{IDF_TARGET_NAME} supports running a "deep sleep wake stub" when coming out of deep sleep. This 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.
Introduction
------------
Deep sleep wake stub code is loaded into "RTC Fast Memory" and any data which it uses must also be loaded into RTC memory. RTC memory regions hold their contents during deep sleep.
The wakeup time from Deep-sleep mode is much longer, compared to Light-sleep and Modem-sleep modes as ROM and RAM are both powered down in this case, and the CPU needs more time for SPI booting. However, {IDF_TARGET_NAME} supports running a “deep sleep wake stub” when coming out of deep sleep. This function runs immediately as soon as the chip wakes up - before any normal initialization, bootloader, or ESP-IDF code has run.
Specifically, after waking up from Deep-sleep mode, {IDF_TARGET_NAME} starts partial initialization. Then RTC fast memory will be validated with CRC. If validation passes, the wake stub code will be executed.
Rules for Wake Stubs
--------------------
As {IDF_TARGET_NAME} has just woken up from deep sleep, most of the peripherals are in the reset state. The SPI flash has not been mapped. Thus, wake stub code can only call functions implemented in ROM or loaded into RTC fast memory, which retains content during deep sleep.
Wake stub code must be carefully written:
From the above, utilizing the wake stub functionality in an application you can quickly run some code when waking up from Deep-sleep mode, without having to wait for the whole boot-up process. However, the stub size is restricted by the size of RTC fast memory.
* As the SoC has freshly woken from sleep, most of the peripherals are in reset states. The SPI flash is unmapped.
.. only:: SOC_RTC_SLOW_MEM_SUPPORTED
* The wake stub code can only call functions implemented in ROM or loaded into RTC Fast Memory (see below.)
{IDF_TARGET_NAME} supports RTC memory, including both RTC fast memory and RTC slow memory. The wake stub code should be loaded into RTC fast memory, with data utilized by the code being stored in RTC fast or RTC slow memory.
* The wake stub code can only access data loaded in RTC memory. All other RAM will be unintiailised and have random contents. The wake stub can use other RAM for temporary storage, but the contents will be overwritten when the SoC goes back to sleep or starts ESP-IDF.
.. only:: not SOC_RTC_SLOW_MEM_SUPPORTED
* RTC memory must include any read-only data (.rodata) used by the stub.
{IDF_TARGET_NAME} only supports RTC fast memory. The wake stub code and data that it utilizes should be loaded into RTC fast memory.
* Data in RTC memory is initialised whenever the SoC restarts, except when waking from deep sleep. When waking from deep sleep, the values which were present before going to sleep are kept.
Next we will introduce how to implement the wake stub code in an application.
* Wake stub code is a part of the main esp-idf app. During normal running of esp-idf, functions can call the wake stub functions or access RTC memory. It is as if these were regular parts of the app.
Implementing A Stub
Implement wake stub
-------------------
The wake stub in esp-idf is called ``esp_wake_deep_sleep()``. This function runs whenever the SoC wakes from deep sleep. There is a default version of this function provided in esp-idf, but the default function is weak-linked so if your app contains a function named ``esp_wake_deep_sleep()`` then this will override the default.
The wake stub in esp-idf is realized by the function :cpp:func:`esp_wake_deep_sleep()`. This function is executed whenever the SoC wakes from deep sleep. As this function is weakly-linked to the default function :cpp:func:`esp_default_wake_deep_sleep()`, if your application contains a function with the name ``esp_wake_deep_sleep()``, the default version :cpp:func:`esp_default_wake_deep_sleep()` in esp-idf will be overridden.
If supplying a custom wake stub, the first thing it does should be to call ``esp_default_wake_deep_sleep()``.
Please note that implementing the function :cpp:func:`esp_wake_deep_sleep()` in your application is not mandatory for utilizing the deep sleep functionality. It becomes necessary only if you want to introduce certain behavior immediately upon the SoC's wake-up.
It is not necessary to implement ``esp_wake_deep_sleep()`` in your app in order to use deep sleep. It is only necessary if you want to have special behaviour immediately on wake.
When you develop a customized wake stub, the first step it should do is to call the default function :cpp:func:`esp_default_wake_deep_sleep()`.
If you want to swap between different deep sleep stubs at runtime, it is also possible to do this by calling the ``esp_set_deep_sleep_wake_stub()`` function. This is not necessary if you only use the default ``esp_wake_deep_sleep()`` function.
In addition, you can switch between different wake stubs by calling the function :cpp:func:`esp_set_deep_sleep_wake_stub()` during runtime.
All of these functions are declared in the ``esp_sleep.h`` header under components/{IDF_TARGET_PATH_NAME}.
Implementing the wake stub function in your application includes the following steps:
.. list::
Loading Code Into RTC Memory
----------------------------
- Loading wake stub code into RTC fast memory
:SOC_RTC_SLOW_MEM_SUPPORTED: - Loading data into RTC memory
:not SOC_RTC_SLOW_MEM_SUPPORTED: - Loading data into RTC fast memory
Wake stub code must be resident in RTC Fast Memory. This can be done in one of two ways.
Load Wake Stub Code into RTC Fast Memory
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The first way is to use the ``RTC_IRAM_ATTR`` attribute to place a function into RTC memory::
The wake stub code can only call functions present in ROM or loaded into RTC fast memory. All other RAM locations are unintiailized and contain random data. While the wake stub code can use other RAM areas for temporary storage, the contents of these areas will be overwritten either upon returning to deep sleep mode or upon initiating esp-idf.
Wake stub code is a part of the main esp-idf application. During regular execution of esp-idf, functions can call the wake stub code or access RTC memory, treating them as a regular part of the application.
Wake stub code must reside in RTC fast memory. This can be realized in two ways.
- Employ the attribute ``RTC_IRAM_ATTR`` to place :cpp:func:`esp_wake_deep_sleep()` into RTC fast memory:
.. code:: c
void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
esp_default_wake_deep_sleep();
// Add additional functionality here
}
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.
The first approach is suitable for short and simple code segments or for source files including both "normal" and "RTC" code.
The first way is simpler for very short and simple code, or for source files where you want to mix "normal" and "RTC" code. The second way is simpler when you want to write longer pieces of code for RTC memory.
- Place the function :cpp:func:`esp_wake_deep_sleep()` into any source file with name starting with ``rtc_wake_stub``. For files with such names ``rtc_wake_stub*``, their contents can be automatically put into RTC fast memory by the linker.
Loading Data Into RTC Memory
----------------------------
Data used by stub code must be resident in RTC memory.
The second method is preferable when writing longer code segments in RTC fast memory.
.. only:: SOC_RTC_SLOW_MEM_SUPPORTED
The data can be placed in RTC Fast memory or in RTC Slow memory which is also used by the ULP.
Load Wake Stub Data into RTC memory
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Specifying this data can be done in one of two ways:
RTC memory must include read-only data used by the wake stub code. Data in RTC memory is initialized whenever the SoC restarts, except when waking from deep sleep. In such cases, the data retained before entering to deep sleep are kept. Data used by the wake stub code must be resident in RTC memory, i.e. RTC fast memory or in RTC slow memory.
The first way is to use the ``RTC_DATA_ATTR`` and ``RTC_RODATA_ATTR`` to specify any data (writeable or read-only, respectively) which should be loaded into RTC memory::
The data can be specified in the following two methods:
RTC_DATA_ATTR int wake_count;
- Utilize attributes ``RTC_DATA_ATTR`` and ``RTC_RODATA_ATTR`` to specify writable or read-only data, respectively.
void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
esp_default_wake_deep_sleep();
static RTC_RODATA_ATTR const char fmt_str[] = "Wake count %d\n";
esp_rom_printf(fmt_str, wake_count++);
}
.. code:: c
.. only:: SOC_RTC_SLOW_MEM_SUPPORTED
RTC_DATA_ATTR int wake_count;
The RTC memory area where this data will be placed can be configured via menuconfig option named ``CONFIG_{IDF_TARGET_CFG_PREFIX}_RTCDATA_IN_FAST_MEM``. This option allows to keep slow memory area for ULP programs and once it is enabled the data marked with ``RTC_DATA_ATTR`` and ``RTC_RODATA_ATTR`` are placed in the RTC fast memory segment otherwise it goes to RTC slow memory (default option). This option depends on the :ref:`CONFIG_FREERTOS_UNICORE` option because RTC fast memory can be accessed only by PRO_CPU.
void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
esp_default_wake_deep_sleep();
static RTC_RODATA_ATTR const char fmt_str[] = "Wake count %d\n";
esp_rom_printf(fmt_str, wake_count++);
}
The RTC memory area where the data will be placed can be configured via the menuconfig option :ref:`CONFIG_{IDF_TARGET_CFG_PREFIX}_RTCDATA_IN_FAST_MEM`. This option allows keeping slow memory area for ULP programs. Once it is enabled, the data marked with ``RTC_DATA_ATTR`` and ``RTC_RODATA_ATTR`` are placed in the RTC fast memory segment; otherwise, it goes to RTC slow memory (the default option). This option depends on the :ref:`CONFIG_FREERTOS_UNICORE` option because RTC fast memory can be accessed only by PRO_CPU.
.. only:: esp32
This option depends on the :ref:`CONFIG_FREERTOS_UNICORE` because RTC fast memory can be accessed only by PRO_CPU.
The attributes ``RTC_FAST_ATTR`` and ``RTC_SLOW_ATTR`` can be used to specify data that is forcefully placed into RTC fast memory and RTC slow memory, respectively. Any access to data marked with ``RTC_FAST_ATTR`` is allowed by PRO_CPU only.
.. only:: esp32s2 or esp32s3
The attributes ``RTC_FAST_ATTR`` and ``RTC_SLOW_ATTR`` can be used to specify data that is forcefully placed into RTC fast memory and RTC slow memory, respectively.
The attributes ``RTC_FAST_ATTR`` and ``RTC_SLOW_ATTR`` can be used to specify data that will be force placed into RTC_FAST and RTC_SLOW memory respectively. Any access to data marked with ``RTC_FAST_ATTR`` is allowed by PRO_CPU only and it is responsibility of user to make sure about it.
.. only:: not SOC_RTC_SLOW_MEM_SUPPORTED
The attributes ``RTC_FAST_ATTR`` and ``RTC_SLOW_ATTR`` can be used to specify data that will be force placed into RTC_FAST and RTC_SLOW memory respectively, but for {IDF_TARGET_NAME} there is only RTC fast memory, so both attributes will map to this region.
Load Wake Stub Data into RTC Fast memory
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Data used by wake stub code must be resident in RTC fast memory.
Unfortunately, any string constants used in this way must be declared as arrays and marked with RTC_RODATA_ATTR, as shown in the example above.
The data can be specified in the following two methods:
The second way is to place the data into any source file whose name starts with ``rtc_wake_stub``.
- Use the ``RTC_DATA_ATTR`` and ``RTC_RODATA_ATTR`` to specify writable or read-only data, respectively.
For example, the equivalent example in ``rtc_wake_stub_counter.c``::
.. code:: c
int wake_count;
RTC_DATA_ATTR int wake_count;
void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
esp_default_wake_deep_sleep();
static RTC_RODATA_ATTR const char fmt_str[] = "Wake count %d\n";
esp_rom_printf(fmt_str, wake_count++);
}
The attributes ``RTC_FAST_ATTR`` and ``RTC_SLOW_ATTR`` can be used to specify data that will be force placed into RTC fast memory and RTC slow memory respectively. However, {IDF_TARGET_NAME} includes RTC fast memory only, so both these two attributes will map to this region.
However, any string constants used in this way must be declared as arrays and marked with ``RTC_RODATA_ATTR``, as shown in the example above.
- Place the data into any source file with name starting with ``rtc_wake_stub``, as demonstrated in the example source file :example_file:`system/deep_sleep_wake_stub/main/rtc_wake_stub_example.c`.
.. code:: c
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();
esp_rom_printf("Wake count %d\n", wake_count++);
// Return from the wake stub function to continue
// booting the firmware.
return;
}
The second way is a better option if you need to use strings, or write other more complex code.
The second approach is advisable when incorporating strings or more complex code segments.
To reduce wake-up time use the `CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` Kconfig option, see more information in :doc:`Fast boot from Deep Sleep <bootloader>`.
CRC Check For Wake Stubs
------------------------
.. only:: SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
During deep sleep, only the wake stubs area of RTC Fast memory is validated with CRC. When {IDF_TARGET_NAME} wakes up from deep sleep, the wake stubs area is validated again. If the validation passes, the wake stubs code will be executed. Otherwise, the normal initialization, bootloader, and esp-idf codes will be executed.
.. only:: not SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
During deep sleep, all RTC Fast memory areas will be validated with CRC. When {IDF_TARGET_NAME} wakes up from deep sleep, the RTC fast memory will be validated with CRC again. If the validation passes, the wake stubs code will be executed. Otherwise, the normal initialization, bootloader and esp-idf codes will be executed.
.. 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.
You can enable the Kconfig option :ref:`CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` to reduce wake-up time. See more information in :doc:`Fast boot from Deep Sleep <bootloader>`.
All of the above functions are declared in :component_file:`esp_hw_support/include/esp_sleep.h`.
Example
-------
.. only:: SOC_RTC_FAST_MEM_SUPPORTED
ESP-IDF provides an example to show how to implement the Deep-sleep wake stub.
ESP-IDF provides an example to show how to implement the deep sleep wake stub.
- :example:`system/deep_sleep_wake_stub`