docs: update format issues for EN and CN files under api-reference/system and...

This commit is contained in:
Cai Xin Ying 2023-08-03 11:32:07 +08:00
parent 494c33e8d1
commit 03c15adc94
47 changed files with 903 additions and 656 deletions

View File

@ -67,11 +67,11 @@ You can also see the information on segments in the ESP-IDF logs while your appl
.. only:: esp32
For more details on the type of memory segments and their address ranges, see *{IDF_TARGET_NAME} Technical Reference Manual* > *System and Memory* > *Embedded Memory* [`PDF <{IDF_TARGET_TRM_EN_URL}#sysmem>`__].
For more details on the type of memory segments and their address ranges, see **{IDF_TARGET_NAME} Technical Reference Manual** > **System and Memory** > **Embedded Memory** [`PDF <{IDF_TARGET_TRM_EN_URL}#sysmem>`__].
.. only:: not esp32
For more details on the type of memory segments and their address ranges, see *{IDF_TARGET_NAME} Technical Reference Manual* > *System and Memory* > *Internal Memory* [`PDF <{IDF_TARGET_TRM_EN_URL}#sysmem>`__].
For more details on the type of memory segments and their address ranges, see **{IDF_TARGET_NAME} Technical Reference Manual** > **System and Memory** > **Internal Memory** [`PDF <{IDF_TARGET_TRM_EN_URL}#sysmem>`__].
3. The image has a single checksum byte after the last segment. This byte is written on a sixteen byte padded boundary, so the application image might need padding.
4. If the ``hash_appended`` field from :cpp:type:`esp_image_header_t` is set then a SHA256 checksum will be appended. The value of the SHA256 hash is calculated on the range from the first byte and up to this field. The length of this field is 32 bytes.
@ -110,9 +110,10 @@ Adding a Custom Structure to an Application
-------------------------------------------
Users also have the opportunity to have similar structure with a fixed offset relative to the beginning of the image.
The following pattern can be used to add a custom structure to your image:
.. code-block::
.. code-block:: c
const __attribute__((section(".rodata_custom_desc"))) esp_custom_app_desc_t custom_app_desc = { ... }

View File

@ -4,7 +4,8 @@ Application Level Tracing
Overview
--------
IDF provides a useful feature for program behavior analysis called **Application Level Tracing**. The feature can be enabled in menuconfig and allows transfer of arbitrary data between the host and {IDF_TARGET_NAME} via JTAG interface with minimal overhead on program execution.
ESP-IDF provides a useful feature for program behavior analysis called **Application Level Tracing**. The feature can be enabled in menuconfig and allows transfer of arbitrary data between the host and {IDF_TARGET_NAME} via JTAG interface with minimal overhead on program execution.
Developers can use this library to send application specific state of execution to the host and receive commands or other type of information in the opposite direction at runtime. The main use cases of this library are:
1. Collecting application specific data, see :ref:`app_trace-application-specific-tracing`

View File

@ -1,4 +1,4 @@
The Async memcpy API
The Async Memcpy API
====================
Overview
@ -8,14 +8,15 @@ Overview
The async memcpy API wraps all DMA configurations and operations, the signature of :cpp:func:`esp_async_memcpy` is almost the same to the standard libc one.
Thanks to the benefit of the DMA, we don't have to wait for each memory copy to be done before we issue another memcpy request. By the way, it's still possible to know when memcpy is finished by listening in the memcpy callback function.
Thanks to the benefit of the DMA, we do not have to wait for each memory copy to be done before we issue another memcpy request. By the way, it is still possible to know when memcpy is finished by listening in the memcpy callback function.
.. only:: esp32s2
.. note::
Memory copy from/to external PSRAM is not supported on ESP32-S2, :cpp:func:`esp_async_memcpy` will abort returning an error if buffer address is not in SRAM.
Configure and Install driver
Configure and Install Driver
----------------------------
:cpp:func:`esp_async_memcpy_install` is used to install the driver with user's configuration. Please note that async memcpy has to be called with the handle returned from :cpp:func:`esp_async_memcpy_install`.
@ -23,13 +24,13 @@ Configure and Install driver
Driver configuration is described in :cpp:type:`async_memcpy_config_t`:
* :cpp:member:`backlog`: This is used to configure the maximum number of DMA operations being processed at the same time.
* :cpp:member:`sram_trans_align`: Declare SRAM alignment for both data address and copy size, set to zero if the data has no restriction in alignment. If set to a quadruple value (i.e. 4X), the driver will enable the burst mode internally, which is helpful for some performance related application.
* :cpp:member:`psram_trans_align`: Declare PSRAM alignment for both data address and copy size. User has to give it a valid value (only 16, 32, 64 are supported) if the destination of memcpy is located in PSRAM. The default alignment (i.e. 16) will be applied if it's set to zero. Internally, the driver configures the size of block used by DMA to access PSRAM, according to the alignment.
* :cpp:member:`sram_trans_align`: Declare SRAM alignment for both data address and copy size, set to zero if the data has no restriction in alignment. If set to a quadruple value (i.e., 4X), the driver will enable the burst mode internally, which is helpful for some performance related application.
* :cpp:member:`psram_trans_align`: Declare PSRAM alignment for both data address and copy size. User has to give it a valid value (only 16, 32, 64 are supported) if the destination of memcpy is located in PSRAM. The default alignment (i.e., 16) will be applied if it is set to zero. Internally, the driver configures the size of block used by DMA to access PSRAM, according to the alignment.
* :cpp:member:`flags`: This is used to enable some special driver features.
:c:macro:`ASYNC_MEMCPY_DEFAULT_CONFIG` provides a default configuration, which specifies the backlog to 8.
.. highlight:: c
.. code-block:: c
::
@ -39,16 +40,16 @@ Driver configuration is described in :cpp:type:`async_memcpy_config_t`:
async_memcpy_t driver = NULL;
ESP_ERROR_CHECK(esp_async_memcpy_install(&config, &driver)); // install driver, return driver handle
Send memory copy request
Send Memory Copy Request
------------------------
:cpp:func:`esp_async_memcpy` is the API to send memory copy request to DMA engine. It must be called after driver is installed successfully. This API is thread safe, so it can be called from different tasks.
Different from the libc version of ``memcpy``, user should also pass a callback to :cpp:func:`esp_async_memcpy`, if it's necessary to be notified when the memory copy is done. The callback is executed in the ISR context, make sure you won't violate the restriction applied to ISR handler.
Different from the libc version of ``memcpy``, user should also pass a callback to :cpp:func:`esp_async_memcpy`, if it is necessary to be notified when the memory copy is done. The callback is executed in the ISR context, make sure you does not violate the restriction applied to ISR handler.
Besides that, the callback function should reside in IRAM space by applying ``IRAM_ATTR`` attribute. The prototype of the callback function is :cpp:type:`async_memcpy_isr_cb_t`, please note that, the callback function should return true if it wakes up a high priority task by some API like :cpp:func:`xSemaphoreGiveFromISR`.
.. highlight:: c
.. code-block:: c
::
@ -69,10 +70,10 @@ Besides that, the callback function should reside in IRAM space by applying ``IR
// Do something else here
xSemaphoreTake(my_semaphore, portMAX_DELAY); // Wait until the buffer copy is done
Uninstall driver (optional)
Uninstall Driver (Optional)
---------------------------
:cpp:func:`esp_async_memcpy_uninstall` is used to uninstall asynchronous memcpy driver. It's not necessary to uninstall the driver after each memcpy operation. If you know your application won't use this driver anymore, then this API can recycle the memory for you.
:cpp:func:`esp_async_memcpy_uninstall` is used to uninstall asynchronous memcpy driver. It is not necessary to uninstall the driver after each memcpy operation. If you know your application will not use this driver anymore, then this API can recycle the memory for you.
.. only:: SOC_ETM_SUPPORTED and SOC_GDMA_SUPPORT_ETM

View File

@ -12,7 +12,7 @@ A new chip versioning logic was introduced in new chips. Chips have several eFus
The new versioning logic is being introduced to distinguish changes in chips as breaking changes and non-breaking changes. Chips with non-breaking changes can run the same software as the previous chip. The previous chip means that the major version is the same.
If the newly released chip does not have breaking changes, that means it can run the same software as the previous chip, then in that chip we keep the same major version and increment the minor version by 1. Otherwise, if there is a breaking change in the newly released chip, meaning it can not run the same software as the previous chip, then in that chip we increase the major version and set the minor version to 0.
If the newly released chip does not have breaking changes, that means it can run the same software as the previous chip, then in that chip we keep the same major version and increment the minor version by 1. Otherwise, if there is a breaking change in the newly released chip, meaning it cannot run the same software as the previous chip, then in that chip we increase the major version and set the minor version to 0.
The software supports a number of revisions, from the minimum to the maximum (the min/max configs are defined in Kconfig). If the software is unaware of a new chip (when the chip version is out of range), it will refuse to run on it unless the Ignore maximum revision restrictions bit is set. This bit removes the upper revision limit.
@ -36,7 +36,7 @@ Chip Revision ``vX.Y``, where:
- ``X`` means Major wafer version. If it is changed, it means that the current software version is not compatible with this released chip and the software must be updated to use this chip.
- ``Y`` means Minor wafer version. If it is changed that means the current software version is compatible with the released chip, and there is no need to update the software.
The ``vX.Y`` chip version format will be used further instead of the ECO number.
The ``vX.Y`` chip version format is used further instead of the ECO number.
Representing Revision Requirement Of A Binary Image
---------------------------------------------------
@ -45,7 +45,7 @@ The 2nd stage bootloader and the application binary images have the :cpp:type:`e
- ``min_chip_rev`` - Minimal chip MAJOR revision required by image (but for ESP32-C3 it is MINOR revision). Its value is determined by :ref:`CONFIG_{IDF_TARGET_CFG_PREFIX}_REV_MIN`.
- ``min_chip_rev_full`` - Minimal chip MINOR revision required by image in format: ``major * 100 + minor``. Its value is determined by :ref:`CONFIG_{IDF_TARGET_CFG_PREFIX}_REV_MIN`.
- ``max_chip_rev_full`` - Maximal chip revision required by image in format: ``major * 100 + minor``. Its value is determined by ``CONFIG_{IDF_TARGET_CFG_PREFIX}_REV_MAX_FULL``. It can not be changed by user. Only Espressif can change it when a new version will be supported in IDF.
- ``max_chip_rev_full`` - Maximal chip revision required by image in format: ``major * 100 + minor``. Its value is determined by ``CONFIG_{IDF_TARGET_CFG_PREFIX}_REV_MAX_FULL``. It cannot be changed by user. Only Espressif can change it when a new version will be supported in ESP-IDF.
Chip Revision APIs
------------------
@ -96,30 +96,30 @@ To resolve this issue:
Image requires chip rev <= v2.99, but chip is v3.0
To resolve this issue, update the IDF to a newer version that supports the used chip (``CONFIG_{IDF_TARGET_CFG_PREFIX}_REV_MAX_FULL``). Another way to fix this is to set the ``Ignore maximal revision`` bit in eFuse or use a chip that is suitable for the software.
To resolve this issue, update the ESP-IDF to a newer version that supports the used chip (``CONFIG_{IDF_TARGET_CFG_PREFIX}_REV_MAX_FULL``). Another way to fix this is to set the ``Ignore maximal revision`` bit in eFuse or use a chip that is suitable for the software.
Backward Compatible With Bootloaders Built By Older ESP-IDF Versions
--------------------------------------------------------------------
.. only:: esp32 or esp32c3 or esp32s2 or esp32s3
The old bootloaders (IDF < 5.0) do not know about Major and Minor wafer version eFuses. They use one single eFuse for this - wafer version.
The old bootloaders (ESP-IDF < v5.0) do not know about Major and Minor wafer version eFuses. They use one single eFuse for this - wafer version.
.. only:: esp32
The old bootloaders did not read the minor wafer version eFuse, the major version can be only <= 3. So it means that the old bootloader can detect correctly only chip version in range v0.0 - v3.0, where the minor version is always 0.
The old bootloaders did not read the minor wafer version eFuse, the major version can be only <= v3. So it means that the old bootloader can detect correctly only chip version in range v0.0 - v3.0, where the minor version is always set to 0.
.. only:: esp32c2
{IDF_TARGET_NAME} chip support was added in IDF 5.0. The bootloader is able to detect any chip versions in range v0.0 - v3.15.
{IDF_TARGET_NAME} chip support was added in ESP-IDF v5.0. The bootloader is able to detect any chip versions in range v0.0 - v3.15.
.. only:: esp32c3
{IDF_TARGET_NAME} chip support was added in IDF 4.3. The old bootloaders can not read all bits of the wafer version eFuse, it can read only the first 3 low bits. So it means that the old bootloader can not detect chip version correctly. Chips v0.0 - v0.8 will be detected correctly, but other chip versions will be recognized as a version from this range.
{IDF_TARGET_NAME} chip support was added in ESP-IDF v4.3. The old bootloaders cannot read all bits of the wafer version eFuse, it can read only the first 3 low bits. So it means that the old bootloader cannot detect chip version correctly. Chips v0.0 - v0.8 are detected correctly, but other chip versions will be recognized as a version from this range.
.. only:: esp32s2 or esp32s3
{IDF_TARGET_NAME} chip support was added in IDF 4.2. {IDF_TARGET_NAME} chips have ``rev_min`` in :cpp:type:`esp_image_header_t` header = 0 because ``Minimum Supported ESP32-S2 Revision`` Kconfig option was not introduced, it means that the old bootloader does not check the chip revision. Any app can be loaded by such bootloader in range v0.0 - v3.15.
{IDF_TARGET_NAME} chip support was added in ESP-IDF v4.2. {IDF_TARGET_NAME} chips have ``rev_min`` in :cpp:type:`esp_image_header_t` header = 0 because ``Minimum Supported ESP32-S2 Revision`` Kconfig option was not introduced, which means that the old bootloader does not check the chip revision. Any app can be loaded by such bootloader in range v0.0 - v3.15.
Please check the chip version using ``esptool chip_id`` command.

View File

@ -1,5 +1,6 @@
Console
=======
:link_to_translation:`zh_CN:[中文]`
ESP-IDF provides ``console`` component, which includes building blocks needed to develop an interactive console over serial port. This component includes the following features:
@ -18,14 +19,14 @@ ESP-IDF provides ``console`` component, which includes building blocks needed to
When using a console application on a chip that supports a hardware USB serial interface, we suggest to disable the secondary serial console output. The secondary output will be output-only and consequently does not make sense in an interactive application.
Line editing
Line Editing
------------
Line editing feature lets users compose commands by typing them, erasing symbols using the 'backspace' key, navigating within the command using the left/right keys, navigating to previously typed commands using the up/down keys, and performing autocompletion using the 'tab' key.
Line editing feature lets users compose commands by typing them, erasing symbols using the ``backspace`` key, navigating within the command using the left/right keys, navigating to previously typed commands using the up/down keys, and performing autocompletion using the ``tab`` key.
.. note::
This feature relies on ANSI escape sequence support in the terminal application. As such, serial monitors which display raw UART data can not be used together with the line editing library. If you see ``[6n`` or similar escape sequence when running :example:`system/console` example instead of a command prompt (e.g. ``esp>`` ), it means that the serial monitor does not support escape sequences. Programs which are known to work are GNU screen, minicom, and esp-idf-monitor (which can be invoked using ``idf.py monitor`` from project directory).
This feature relies on ANSI escape sequence support in the terminal application. As such, serial monitors which display raw UART data can not be used together with the line editing library. If you see ``[6n`` or similar escape sequence when running :example:`system/console` example instead of a command prompt (e.g., ``esp>`` ), it means that the serial monitor does not support escape sequences. Programs which are known to work are GNU screen, minicom, and esp-idf-monitor (which can be invoked using ``idf.py monitor`` from project directory).
Here is an overview of functions provided by `linenoise <https://github.com/antirez/linenoise>`_ library.
@ -34,53 +35,53 @@ Configuration
Linenoise library does not need explicit initialization. However, some configuration defaults may need to be changed before invoking the main line editing function.
:cpp:func:`linenoiseClearScreen`
- :cpp:func:`linenoiseClearScreen`
Clear terminal screen using an escape sequence and position the cursor at the top left corner.
:cpp:func:`linenoiseSetMultiLine`
- :cpp:func:`linenoiseSetMultiLine`
Switch between single line and multi line editing modes. In single line mode, if the length of the command exceeds the width of the terminal, the command text is scrolled within the line to show the end of the text. In this case the beginning of the text is hidden. Single line mode needs less data to be sent to refresh screen on each key press, so exhibits less glitching compared to the multi line mode. On the flip side, editing commands and copying command text from terminal in single line mode is harder. Default is single line mode.
:cpp:func:`linenoiseAllowEmpty`
- :cpp:func:`linenoiseAllowEmpty`
Set whether linenoise library will return a zero-length string (if ``true``) or ``NULL`` (if ``false``) for empty lines. By default, zero-length strings are returned.
Set whether linenoise library returns a zero-length string (if ``true``) or ``NULL`` (if ``false``) for empty lines. By default, zero-length strings are returned.
:cpp:func:`linenoiseSetMaxLineLen`
- :cpp:func:`linenoiseSetMaxLineLen`
Set maximum length of the line for linenoise library. Default length is 4096 bytes. The default value can be updated to optimize RAM memory usage.
Main loop
Main Loop
^^^^^^^^^
:cpp:func:`linenoise`
- :cpp:func:`linenoise`
In most cases, console applications have some form of read/eval loop. :cpp:func:`linenoise` is the single function which handles user's key presses and returns the completed line once the 'enter' key is pressed. As such, it handles the 'read' part of the loop.
In most cases, console applications have some form of read/eval loop. :cpp:func:`linenoise` is the single function which handles user's key presses and returns the completed line once the ``enter`` key is pressed. As such, it handles the ``read`` part of the loop.
:cpp:func:`linenoiseFree`
- :cpp:func:`linenoiseFree`
This function must be called to release the command line buffer obtained from :cpp:func:`linenoise` function.
Hints and completions
Hints and Completions
^^^^^^^^^^^^^^^^^^^^^
:cpp:func:`linenoiseSetCompletionCallback`
- :cpp:func:`linenoiseSetCompletionCallback`
When the user presses the 'tab' key, linenoise library invokes the completion callback. The callback should inspect the contents of the command typed so far and provide a list of possible completions using calls to :cpp:func:`linenoiseAddCompletion` function. :cpp:func:`linenoiseSetCompletionCallback` function should be called to register this completion callback, if completion feature is desired.
When the user presses the ``tab`` key, linenoise library invokes the completion callback. The callback should inspect the contents of the command typed so far and provide a list of possible completions using calls to :cpp:func:`linenoiseAddCompletion` function. :cpp:func:`linenoiseSetCompletionCallback` function should be called to register this completion callback, if completion feature is desired.
``console`` component provides a ready made function to provide completions for registered commands, :cpp:func:`esp_console_get_completion` (see below).
:cpp:func:`linenoiseAddCompletion`
- :cpp:func:`linenoiseAddCompletion`
Function to be called by completion callback to inform the library about possible completions of the currently typed command.
:cpp:func:`linenoiseSetHintsCallback`
- :cpp:func:`linenoiseSetHintsCallback`
Whenever user input changes, linenoise invokes the hints callback. This callback can inspect the command line typed so far, and provide a string with hints (which can include list of command arguments, for example). The library then displays the hint text on the same line where editing happens, possibly with a different color.
:cpp:func:`linenoiseSetFreeHintsCallback`
- :cpp:func:`linenoiseSetFreeHintsCallback`
If the hint string returned by hints callback is dynamically allocated or needs to be otherwise recycled, the function which performs such cleanup should be registered via :cpp:func:`linenoiseSetFreeHintsCallback`.
@ -88,28 +89,28 @@ Hints and completions
History
^^^^^^^
:cpp:func:`linenoiseHistorySetMaxLen`
- :cpp:func:`linenoiseHistorySetMaxLen`
This function sets the number of most recently typed commands to be kept in memory. Users can navigate the history using the up/down arrows keys.
:cpp:func:`linenoiseHistoryAdd`
- :cpp:func:`linenoiseHistoryAdd`
Linenoise does not automatically add commands to history. Instead, applications need to call this function to add command strings to the history.
:cpp:func:`linenoiseHistorySave`
- :cpp:func:`linenoiseHistorySave`
Function saves command history from RAM to a text file, for example on an SD card or on a filesystem in flash memory.
:cpp:func:`linenoiseHistoryLoad`
- :cpp:func:`linenoiseHistoryLoad`
Counterpart to :cpp:func:`linenoiseHistorySave`, loads history from a file.
:cpp:func:`linenoiseHistoryFree`
- :cpp:func:`linenoiseHistoryFree`
Releases memory used to store command history. Call this function when done working with linenoise library.
Splitting of command line into arguments
Splitting of Command Line into Arguments
----------------------------------------
``console`` component provides :cpp:func:`esp_console_split_argv` function to split command line string into arguments. The function returns the number of arguments found (``argc``) and fills an array of pointers which can be passed as ``argv`` argument to any function which accepts arguments in ``argc, argv`` format.
@ -123,18 +124,18 @@ The command line is split into arguments according to the following rules:
Examples:
- ``abc def 1 20 .3`` [ ``abc``, ``def``, ``1``, ``20``, ``.3`` ]
- ``abc "123 456" def`` [ ``abc``, ``123 456``, ``def`` ]
- ```a\ b\\c\"`` [ ``a b\c"`` ]
- ``abc def 1 20 .3`` > [ ``abc``, ``def``, ``1``, ``20``, ``.3`` ]
- ``abc "123 456" def`` > [ ``abc``, ``123 456``, ``def`` ]
- ```a\ b\\c\"`` > [ ``a b\c"`` ]
Argument parsing
Argument Parsing
----------------
For argument parsing, ``console`` component includes `argtable3 <https://www.argtable.org/>`_ library. Please see `tutorial <https://www.argtable.org/tutorial/>`_ for an introduction to `argtable3 <https://www.argtable.org/>`_. Github repository also includes `examples <https://github.com/argtable/argtable3/tree/master/examples>`_.
Command registration and dispatching
Command Registration and Dispatching
------------------------------------
``console`` component includes utility functions which handle registration of commands, matching commands typed by the user to registered ones, and calling these commands with the arguments given on the command line.
@ -150,29 +151,29 @@ For each command, application provides the following information (in the form of
A few other functions are provided by the command registration module:
:cpp:func:`esp_console_run`
- :cpp:func:`esp_console_run`
This function takes the command line string, splits it into argc/argv argument list using :cpp:func:`esp_console_split_argv`, looks up the command in the list of registered components, and if it is found, executes its handler.
:cpp:func:`esp_console_register_help_command`
- :cpp:func:`esp_console_register_help_command`
Adds ``help`` command to the list of registered commands. This command prints the list of all the registered commands, along with their arguments and help texts.
:cpp:func:`esp_console_get_completion`
- :cpp:func:`esp_console_get_completion`
Callback function to be used with :cpp:func:`linenoiseSetCompletionCallback` from linenoise library. Provides completions to linenoise based on the list of registered commands.
:cpp:func:`esp_console_get_hint`
- :cpp:func:`esp_console_get_hint`
Callback function to be used with :cpp:func:`linenoiseSetHintsCallback` from linenoise library. Provides argument hints for registered commands to linenoise.
Initialize console REPL environment
Initialize Console REPL Environment
-----------------------------------
To establish a basic REPL environment, ``console`` component provides several useful APIs, combining those functions described above.
In a typical application, you only need to call :cpp:func:`esp_console_new_repl_uart` to initialize the REPL environment based on UART device, including driver install, basic console configuration, spawning a thread to do REPL task and register several useful commands (e.g. `help`).
In a typical application, you only need to call :cpp:func:`esp_console_new_repl_uart` to initialize the REPL environment based on UART device, including driver install, basic console configuration, spawning a thread to do REPL task and register several useful commands (e.g., `help`).
After that, you can register your own commands with :cpp:func:`esp_console_cmd_register`. The REPL environment keeps in init state until you call :cpp:func:`esp_console_start_repl`.
@ -185,7 +186,7 @@ Application Example
Example application illustrating usage of the ``console`` component is available in :example:`system/console` directory. This example shows how to initialize UART and VFS functions, set up linenoise library, read and handle commands from UART, and store command history in Flash. See README.md in the example directory for more details.
Besides that, ESP-IDF contains several useful examples which are based on the `console` component and can be treated as "tools" when developing applications. For example, :example:`peripherals/i2c/i2c_tools`, :example:`wifi/iperf`.
Besides that, ESP-IDF contains several useful examples which are based on the ``console`` component and can be treated as "tools" when developing applications. For example, :example:`peripherals/i2c/i2c_tools`, :example:`wifi/iperf`.
API Reference

View File

@ -10,13 +10,13 @@ Introduction
The eFuse Manager library is designed to structure access to eFuse bits and make using these easy. This library operates eFuse bits by a structure name which is assigned in eFuse table. This sections introduces some concepts used by eFuse Manager.
Hardware description
Hardware Description
--------------------
The {IDF_TARGET_NAME} has a number of eFuses which can store system and user parameters. Each eFuse is a one-bit field which can be programmed to 1 after which it cannot be reverted back to 0.
Some of system parameters are using these eFuse bits directly by hardware modules and have special place (for example EFUSE_BLK0).
For more details, see *{IDF_TARGET_NAME} Technical Reference Manual* > *eFuse Controller (eFuse)* [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. Some eFuse bits are available for user applications.
For more details, see **{IDF_TARGET_NAME} Technical Reference Manual** > **eFuse Controller (eFuse)** [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. Some eFuse bits are available for user applications.
.. only:: esp32
@ -25,7 +25,7 @@ For more details, see *{IDF_TARGET_NAME} Technical Reference Manual* > *eFuse Co
* EFUSE_BLK0 is used entirely for system purposes;
* EFUSE_BLK1 is used for flash encrypt key. If not using that Flash Encryption feature, they can be used for another purpose;
* EFUSE_BLK2 is used for security boot key. If not using that Secure Boot feature, they can be used for another purpose;
* EFUSE_BLK3 can be partially reserved for the custom MAC address, or used entirely for user application. Note that some bits are already used in IDF.
* EFUSE_BLK3 can be partially reserved for the custom MAC address, or used entirely for user application. Note that some bits are already used in ESP-IDF.
.. only:: not esp32 and not esp32c2
@ -59,18 +59,18 @@ For more details, see *{IDF_TARGET_NAME} Technical Reference Manual* > *eFuse Co
Each block is divided into 8 32-bits registers.
eFuse Manager component
eFuse Manager Component
-----------------------
The component has API functions for reading and writing fields. Access to the fields is carried out through the structures that describe the location of the eFuse bits in the blocks. The component provides the ability to form fields of any length and from any number of individual bits. The description of the fields is made in a CSV file in a table form. To generate from a tabular form (CSV file) in the C-source uses the tool `efuse_table_gen.py`. The tool checks the CSV file for uniqueness of field names and bit intersection, in case of using a `custom` file from the user's project directory, the utility will check with the `common` CSV file.
The component has API functions for reading and writing fields. Access to the fields is carried out through the structures that describe the location of the eFuse bits in the blocks. The component provides the ability to form fields of any length and from any number of individual bits. The description of the fields is made in a CSV file in a table form. To generate from a tabular form (CSV file) in the C-source uses the tool ``efuse_table_gen.py``. The tool checks the CSV file for uniqueness of field names and bit intersection, in case of using a `custom` file from the user's project directory, the utility checks with the `common` CSV file.
CSV files:
* common (`esp_efuse_table.csv`) - contains eFuse fields which are used inside the IDF. C-source generation should be done manually when changing this file (run command ``idf.py efuse-common-table``). Note that changes in this file can lead to incorrect operation.
* common (`esp_efuse_table.csv`) - contains eFuse fields which are used inside the ESP-IDF. C-source generation should be done manually when changing this file (run command ``idf.py efuse-common-table``). Note that changes in this file can lead to incorrect operation.
* custom - (optional and can be enabled by :ref:`CONFIG_EFUSE_CUSTOM_TABLE`) contains eFuse fields that are used by the user in their application. C-source generation should be done manually when changing this file and running ``idf.py efuse-custom-table``.
Description CSV file
Description CSV File
--------------------
The CSV file contains a description of the eFuse fields. In the simple case, one field has one line of description.
@ -85,28 +85,34 @@ Table header:
Individual params in CSV file the following meanings:
field_name
Name of field. The prefix `ESP_EFUSE_` will be added to the name, and this field name will be available in the code. This name will be used to access the fields. The name must be unique for all fields. If the line has an empty name, then this line is combined with the previous field. This allows you to set an arbitrary order of bits in the field, and expand the field as well (see ``MAC_FACTORY`` field in the common table). The field_name supports structured format using `.` to show that the field belongs to another field (see ``WR_DIS`` and ``RD_DIS`` in the common table).
Name of field. The prefix `ESP_EFUSE_` is added to the name, and this field name is available in the code. This name is used to access the fields. The name must be unique for all fields. If the line has an empty name, then this line is combined with the previous field. This allows you to set an arbitrary order of bits in the field, and expand the field as well (see ``MAC_FACTORY`` field in the common table). The field_name supports structured format using `.` to show that the field belongs to another field (see ``WR_DIS`` and ``RD_DIS`` in the common table).
efuse_block
Block number. It determines where the eFuse bits will be placed for this field. Available EFUSE_BLK0..{IDF_TARGET_MAX_EFUSE_BLK}.
Block number. It determines where the eFuse bits are placed for this field. Available EFUSE_BLK0..{IDF_TARGET_MAX_EFUSE_BLK}.
bit_start
Start bit number (0..255). The bit_start field can be omitted. In this case, it will be set to bit_start + bit_count from the previous record, if it has the same efuse_block. Otherwise (if efuse_block is different, or this is the first entry), an error will be generated.
Start bit number (0..255). The bit_start field can be omitted. In this case, it is set to bit_start + bit_count from the previous record, if it has the same efuse_block. Otherwise (if efuse_block is different, or this is the first entry), an error will be generated.
.. only:: esp32
bit_count
The number of bits to use in this field (1..-). This parameter can not be omitted. This field also may be ``MAX_BLK_LEN`` in this case, the field length will have the maximum block length, taking into account the coding scheme (applicable for ``ESP_EFUSE_SECURE_BOOT_KEY`` and ``ESP_EFUSE_ENCRYPT_FLASH_KEY`` fields). The value ``MAX_BLK_LEN`` depends on :ref:`CONFIG_EFUSE_CODE_SCHEME_SELECTOR`, will be replaced with "None" - 256, "3/4" - 192, "REPEAT" - 128.
The number of bits to use in this field (1..-). This parameter cannot be omitted. This field also may be ``MAX_BLK_LEN`` in this case, the field length has the maximum block length, taking into account the coding scheme (applicable for ``ESP_EFUSE_SECURE_BOOT_KEY`` and ``ESP_EFUSE_ENCRYPT_FLASH_KEY`` fields). The value ``MAX_BLK_LEN`` depends on :ref:`CONFIG_EFUSE_CODE_SCHEME_SELECTOR`, which will be replaced with "None" - 256, "3/4" - 192, "REPEAT" - 128.
.. only:: not esp32
bit_count
The number of bits to use in this field (1..-). This parameter can not be omitted. This field also may be ``MAX_BLK_LEN`` in this case, the field length will have the maximum block length.
The number of bits to use in this field (1..-). This parameter cannot be omitted. This field also may be ``MAX_BLK_LEN`` in this case, the field length has the maximum block length.
comment
This param is using for comment field, it also move to C-header file. The comment field can be omitted.
If a non-sequential bit order is required to describe a field, then the field description in the following lines should be continued without specifying a name, this will indicate that it belongs to one field. For example two fields MAC_FACTORY and MAC_FACTORY_CRC:
If a non-sequential bit order is required to describe a field, then the field description in the following lines should be continued without specifying a name, indicating that it belongs to one field. For example two fields ``MAC_FACTORY`` and ``MAC_FACTORY_CRC``:
.. code-block:: none
@ -120,11 +126,11 @@ If a non-sequential bit order is required to describe a field, then the field de
, EFUSE_BLK0, 32, 8, Factory MAC addr [5]
MAC_FACTORY_CRC, EFUSE_BLK0, 80, 8, CRC8 for factory MAC address
This field will available in code as ESP_EFUSE_MAC_FACTORY and ESP_EFUSE_MAC_FACTORY_CRC.
This field is available in code as ``ESP_EFUSE_MAC_FACTORY`` and ``ESP_EFUSE_MAC_FACTORY_CRC``.
.. _structured-efuse-fields:
Structured efuse fields
Structured eFuse Fields
-----------------------
.. code-block:: none
@ -139,13 +145,13 @@ Structured efuse fields
WR_DIS.FIELD_3.ALIAS, EFUSE_BLK0, 5, 1, Write protection for FIELD_3 (just a alias for WR_DIS.FIELD_3)
WR_DIS.FIELD_4, EFUSE_BLK0, 7, 1, Write protection for FIELD_4
The structured eFuse field looks like ``WR_DIS.RD_DIS`` where the dot points that this field belongs to the parent field - ``WR_DIS`` and can not be out of the parent's range.
The structured eFuse field looks like ``WR_DIS.RD_DIS`` where the dot points that this field belongs to the parent field - ``WR_DIS`` and cannot be out of the parent's range.
It is possible to use some levels of structured fields as WR_DIS.FIELD_2.B1 and B2. These fields should not be crossed each other and should be in the range of two fields: ``WR_DIS`` and ``WR_DIS.FIELD_2``.
It is possible to create aliases for fields with the same range, see ``WR_DIS.FIELD_3`` and ``WR_DIS.FIELD_3.ALIAS``.
The IDF names for structured efuse fields should be unique. The ``efuse_table_gen`` tool will generate the final names where the dot will be replaced by ``_``. The names for using in IDF are ESP_EFUSE_WR_DIS, ESP_EFUSE_WR_DIS_RD_DIS, ESP_EFUSE_WR_DIS_FIELD_2_B1, etc.
The ESP-IDF names for structured eFuse fields should be unique. The ``efuse_table_gen`` tool generates the final names where the dot is replaced by ``_``. The names for using in ESP-IDF are ESP_EFUSE_WR_DIS, ESP_EFUSE_WR_DIS_RD_DIS, ESP_EFUSE_WR_DIS_FIELD_2_B1, etc.
The ``efuse_table_gen`` tool checks that the fields do not overlap each other and must be within the range of a field if there is a violation, then throws the following error:
@ -161,8 +167,8 @@ Solution: Describe ``SERIAL_NUMBER`` to be included in ``USER_DATA``. (``USER_DA
Solution: Change ``bit_start`` for ``FIELD.MAJOR_NUMBER`` from 60 to 0, so ``MAJOR_NUMBER`` is in the ``FEILD`` range.
efuse_table_gen.py tool
-----------------------
``efuse_table_gen.py`` Tool
---------------------------
The tool is designed to generate C-source files from CSV file and validate fields. First of all, the check is carried out on the uniqueness of the names and overlaps of the field bits. If an additional `custom` file is used, it will be checked with the existing `common` file (esp_efuse_table.csv). In case of errors, a message will be displayed and the string that caused the error. C-source files contain structures of type `esp_efuse_desc_t`.
@ -198,7 +204,7 @@ To use the generated fields, you need to include two files:
#include "esp_efuse_table.h" // or "esp_efuse_custom_table.h"
Supported coding scheme
Supported Coding Scheme
-----------------------
.. only:: esp32
@ -231,7 +237,7 @@ Supported coding scheme
It turns out that only one field can be written into one coding unit. Repeated rewriting in one coding unit is prohibited. But if the record was made in advance or through a :cpp:func:`esp_efuse_write_block` function, then reading the fields belonging to one coding unit is possible.
In case ``3/4`` coding scheme, the writing process is divided into the coding units and we can not use the usual mode of writing some fields. We can prepare all the data for writing and burn it in one time. You can also use this mode for ``None`` coding scheme but it is not necessary. It is important for ``3/4`` coding scheme.
In case ``3/4`` coding scheme, the writing process is divided into the coding units and we cannot use the usual mode of writing some fields. We can prepare all the data for writing and burn it in one time. You can also use this mode for ``None`` coding scheme but it is not necessary. It is important for ``3/4`` coding scheme.
``The batch writing mode`` blocks ``esp_efuse_read_...`` operations.
After changing the coding scheme, run ``efuse_common_table`` and ``efuse_custom_table`` commands to check the tables of the new coding scheme.
@ -241,7 +247,7 @@ Supported coding scheme
Coding schemes are used to protect against data corruption. {IDF_TARGET_NAME} supports two coding schemes:
* ``None``. EFUSE_BLK0 is stored with four backups, meaning each bit is stored four times. This backup scheme is automatically applied by the hardware and is not visible to software. EFUSE_BLK0 can be written many times.
* ``RS``. EFUSE_BLK1 - {IDF_TARGET_MAX_EFUSE_BLK} use Reed-Solomon coding scheme that supports up to 5 bytes of automatic error correction. Software will encode the 32-byte EFUSE_BLKx using RS (44, 32) to generate a 12-byte check code, and then burn the EFUSE_BLKx and the check code into eFuse at the same time. The eFuse Controller automatically decodes the RS encoding and applies error correction when reading back the eFuse block. Because the RS check codes are generated across the entire 256-bit eFuse block, each block can only be written to one time.
* ``RS``. EFUSE_BLK1 - {IDF_TARGET_MAX_EFUSE_BLK} use Reed-Solomon coding scheme that supports up to 5 bytes of automatic error correction. Software encodes the 32-byte EFUSE_BLKx using RS (44, 32) to generate a 12-byte check code, and then burn the EFUSE_BLKx and the check code into eFuse at the same time. The eFuse Controller automatically decodes the RS encoding and applies error correction when reading back the eFuse block. Because the RS check codes are generated across the entire 256-bit eFuse block, each block can only be written to one time.
To write some fields into one block, or different blocks in one time, you need to use ``the batch writing mode``. Firstly set this mode through :cpp:func:`esp_efuse_batch_write_begin` function then write some fields as usual using the ``esp_efuse_write_...`` functions. At the end to burn them, call the :cpp:func:`esp_efuse_batch_write_commit` function. It burns prepared data to the eFuse blocks and disables the ``batch recording mode``.
@ -286,7 +292,7 @@ For frequently used fields, special functions are made, like this :cpp:func:`esp
.. only:: SOC_EFUSE_KEY_PURPOSE_FIELD or SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY
eFuse API for keys
eFuse API for Keys
------------------
.. only:: SOC_EFUSE_KEY_PURPOSE_FIELD
@ -314,7 +320,7 @@ For frequently used fields, special functions are made, like this :cpp:func:`esp
* :cpp:func:`esp_efuse_set_write_protect_of_digest_revoke` - Sets a write protection of the Secure Boot public key digest revocation bit.
How to add a new field
How to Add a New Field
----------------------
1. Find a free bits for field. Show `esp_efuse_table.csv` file or run ``idf.py show-efuse-table`` or the next command:
@ -394,7 +400,7 @@ Thus, reading the eFuse ``USER_DATA`` block written as above gives the following
uint8_t id = 0;
size_t id_size = esp_efuse_get_field_size(ESP_EFUSE_ID); // returns 6
// size_t id_size = ESP_EFUSE_USER_DATA[0]->bit_count; // can NOT be used because it consists of 3 entries. It returns 3 not 6.
// size_t id_size = ESP_EFUSE_USER_DATA[0]->bit_count; // cannot be used because it consists of 3 entries. It returns 3 not 6.
esp_efuse_read_field_blob(ESP_EFUSE_ID, &id, id_size);
// id = 0x91
// b'100 10 001
@ -452,13 +458,13 @@ The format of the ``value`` property is the same as shown in ``espefuse.py summa
There is an example test :example_file:`system/efuse/CMakeLists.txt` which adds a custom target ``efuse-summary``. This allows you to run the ``idf.py efuse-summary`` command to read the required eFuses (specified in the ``efuse_names`` list) at any time, not just at project build time.
Debug eFuse & Unit tests
Debug eFuse & Unit Tests
------------------------
Virtual eFuses
^^^^^^^^^^^^^^
The Kconfig option :ref:`CONFIG_EFUSE_VIRTUAL` will virtualize eFuse values inside the eFuse Manager, so writes are emulated and no eFuse values are permanently changed. This can be useful for debugging app and unit tests.
The Kconfig option :ref:`CONFIG_EFUSE_VIRTUAL` virtualizes eFuse values inside the eFuse Manager, so writes are emulated and no eFuse values are permanently changed. This can be useful for debugging app and unit tests.
During startup, the eFuses are copied to RAM. All eFuse operations (read and write) are performed with RAM instead of the real eFuse registers.
In addition to the :ref:`CONFIG_EFUSE_VIRTUAL` option there is :ref:`CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH` option that adds a feature to keep eFuses in flash memory. To use this mode the partition_table should have the `efuse` partition. partition.csv: ``"efuse_em, data, efuse, , 0x2000,"``.
@ -469,8 +475,8 @@ Flash Encryption Testing
Flash Encryption (FE) is a hardware feature that requires the physical burning of eFuses: key and FLASH_CRYPT_CNT. If FE is not actually enabled then enabling the :ref:`CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH` option just gives testing possibilities and does not encrypt anything in the flash, even though the logs say encryption happens. The :cpp:func:`bootloader_flash_write` is adapted for this purpose. But if FE is already enabled on the chip and you run an application or bootloader created with the :ref:`CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH` option then the flash encryption/decryption operations will work properly (data are encrypted as it is written into an encrypted flash partition and decrypted when they are read from an encrypted partition).
espefuse.py
^^^^^^^^^^^
``espefuse.py``
^^^^^^^^^^^^^^^
esptool includes a useful tool for reading/writing {IDF_TARGET_NAME} eFuse bits - `espefuse.py <https://docs.espressif.com/projects/esptool/en/latest/{IDF_TARGET_PATH_NAME}/espefuse/index.html>`_.

View File

@ -6,7 +6,7 @@ Event Loop Library
Overview
--------
The event loop library allows components to declare events so that other components can register handlers -- codes that will execute when those events occur. This allows loosely-coupled components to attach desired behavior to state changes of other components without application involvement. This also simplifies event processing by serializing and deferring code execution to another context.
The event loop library allows components to declare events so that other components can register handlers -- codes that executes when those events occur. This allows loosely-coupled components to attach desired behavior to state changes of other components without application involvement. This also simplifies event processing by serializing and deferring code execution to another context.
.. only:: SOC_WIFI_SUPPORTED
@ -182,7 +182,7 @@ If the hypothetical event ``MY_OTHER_EVENT_BASE``, ``MY_OTHER_EVENT_ID`` is post
Handler Un-Registering Itself
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In general, an event handler run by an event loop is *not allowed to do any (un)registering activity on that event loop*. There is one exception, though: un-registering itself is allowed for the handler. E.g., it is possible to do the following:
In general, an event handler run by an event loop is **not allowed to do any (un)registering activity on that event loop**. There is one exception, though: un-registering itself is allowed for the handler. E.g., it is possible to do the following:
.. code-block:: c
@ -204,7 +204,7 @@ In general, an event handler run by an event loop is *not allowed to do any (un)
Handler Registration and Handler Dispatch Order
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The general rule is that, for handlers that match a certain posted event during dispatch, those which are registered first also get executed first. The user can then control which handlers get executed first by registering them before other handlers, provided that all registrations are performed using a single task. If the user plans to take advantage of this behavior, caution must be exercised if there are multiple tasks registering handlers. While the 'first registered, first executed' behavior still holds true, the task which gets executed first will also get its handlers registered first. Handlers registered one after the other by a single task will still be dispatched in the order relative to each other, but if that task gets pre-empted in between registration by another task that also registers handlers; then during dispatch those handlers will also get executed in between.
The general rule is that, for handlers that match a certain posted event during dispatch, those which are registered first also get executed first. The user can then control which handlers get executed first by registering them before other handlers, provided that all registrations are performed using a single task. If the user plans to take advantage of this behavior, caution must be exercised if there are multiple tasks registering handlers. While the 'first registered, first executed' behavior still holds true, the task which gets executed first also gets its handlers registered first. Handlers registered one after the other by a single task are still dispatched in the order relative to each other, but if that task gets pre-empted in between registration by another task that also registers handlers; then during dispatch those handlers also get executed in between.
Event Loop Profiling
@ -219,7 +219,7 @@ Examples of using the ``esp_event`` library can be found in :example:`system/esp
Other examples which also adopt ``esp_event`` library:
* :example:`NMEA Parser <peripherals/uart/nmea0183_parser>`, which will decode the statements received from GPS.
* :example:`NMEA Parser <peripherals/uart/nmea0183_parser>`, which decodes the statements received from GPS.
API Reference
-------------

View File

@ -1,10 +1,10 @@
Call function with external stack
Call Function with External Stack
=================================
Overview
--------
A given function can be executed with a user allocated stack space which is independent of current task stack, this mechanism can be used to save stack space wasted by tasks which call a common function with intensive stack usage such as `printf`. The given function can be called inside the shared stack space which is a callback function deferred by calling :cpp:func:`esp_execute_shared_stack_function`, passing that function as parameter.
A given function can be executed with a user-allocated stack space which is independent of current task stack, this mechanism can be used to save stack space wasted by tasks which call a common function with intensive stack usage such as ``printf``. The given function can be called inside the shared stack space which is a callback function deferred by calling :cpp:func:`esp_execute_shared_stack_function`, passing that function as a parameter.
Usage
-----
@ -16,7 +16,7 @@ Usage
- the size of stack in bytes
- a pointer to the shared stack function
The user defined function will be deferred as a callback and can be called using the user allocated space without taking space from current task stack.
The user-defined function is deferred as a callback and can be called using the user-allocated space without taking space from current task stack.
The usage may look like the code below:
@ -27,7 +27,7 @@ The usage may look like the code below:
printf("Executing this printf from external stack! \n");
}
//Let's suppose we want to call printf using a separated stack space
//Let us suppose we want to call printf using a separated stack space
//allowing the app to reduce its stack size.
void app_main()
{

View File

@ -4,12 +4,12 @@ ESP HTTPS OTA
Overview
--------
``esp_https_ota`` provides simplified APIs to perform firmware upgrades over HTTPS. It's an abstraction layer over existing OTA APIs.
``esp_https_ota`` provides simplified APIs to perform firmware upgrades over HTTPS. It is an abstraction layer over existing OTA APIs.
Application Example
-------------------
.. highlight:: c
.. code-block:: c
::
@ -37,7 +37,9 @@ Server Verification
Please refer to :ref:`ESP-TLS: TLS Server Verification <esp_tls_server_verification>` for more information on server verification. The root certificate (in PEM format) needs to be provided to the :cpp:member:`esp_http_client_config_t::cert_pem` member.
.. note:: The server-endpoint **root** certificate should be used for verification instead of any intermediate ones from the certificate chain. The reason being that the root certificate has the maximum validity and usually remains the same for a long period of time. Users can also use the ``ESP x509 Certificate Bundle`` feature for verification, which covers most of the trusted root certificates (using the :cpp:member:`esp_http_client_config_t::crt_bundle_attach` member).
.. note::
The server-endpoint **root** certificate should be used for verification instead of any intermediate ones from the certificate chain. The reason is that the root certificate has the maximum validity and usually remains the same for a long period of time. Users can also use the ``ESP x509 Certificate Bundle`` feature for verification, which covers most of the trusted root certificates (using the :cpp:member:`esp_http_client_config_t::crt_bundle_attach` member).
Partial Image Download over HTTPS
---------------------------------
@ -79,7 +81,7 @@ ESP HTTPS OTA has various events for which a handler can be triggered by :doc:`t
Event Handler Example
^^^^^^^^^^^^^^^^^^^^^
.. highlight:: c
.. code-block:: c
::

View File

@ -25,7 +25,7 @@ Although hardware timers are not subject to the limitations mentioned, they may
``esp_timer`` set of APIs provides one-shot and periodic timers, microsecond time resolution, and {IDF_TARGET_HR_TIMER_Resolution}-bit range.
Internally, ``esp_timer`` uses a {IDF_TARGET_HR_TIMER_Resolution}-bit hardware timer. The exact hardware timer implementation used will depend on the target, where {IDF_TARGET_HR_TIMER} is used for {IDF_TARGET_NAME}.
Internally, ``esp_timer`` uses a {IDF_TARGET_HR_TIMER_Resolution}-bit hardware timer. The exact hardware timer implementation used depends on the target, where {IDF_TARGET_HR_TIMER} is used for {IDF_TARGET_NAME}.
Timer callbacks can be dispatched by two methods:
@ -70,18 +70,18 @@ Timer callbacks that are processed by the ``ESP_TIMER_ISR`` method should not ca
ETM Event
---------
The ``esp_timer`` is constructed based on a hardware timer called *systimer*, which is able to generate the alarm event and interact with the :doc:`ETM </api-reference/peripherals/etm>` module. You can call :cpp:func:`esp_timer_new_etm_alarm_event` to get the corresponding ETM event handle.
The ``esp_timer`` is constructed based on a hardware timer called **systimer**, which is able to generate the alarm event and interact with the :doc:`ETM </api-reference/peripherals/etm>` module. You can call :cpp:func:`esp_timer_new_etm_alarm_event` to get the corresponding ETM event handle.
To know more about how to connect the event to an ETM channel, please refer to the :doc:`ETM </api-reference/peripherals/etm>` documentation.
``esp_timer`` During Light-sleep
--------------------------------
During Light-sleep, the ``esp_timer`` counter stops and no callback functions are called. Instead, the time is counted by the RTC counter. Upon waking up, the system gets the difference between the counters and calls a function that advances the ``esp_timer`` counter. Since the counter has been advanced, the system starts calling callbacks that were not called during sleep. The number of callbacks depends on the duration of the sleep and the period of the timers. It can lead to the overflow of some queues. This only applies to periodic timers, since one-shot timers will be called once.
During Light-sleep, the ``esp_timer`` counter stops and no callback functions are called. Instead, the time is counted by the RTC counter. Upon waking up, the system gets the difference between the counters and calls a function that advances the ``esp_timer`` counter. Since the counter has been advanced, the system starts calling callbacks that were not called during sleep. The number of callbacks depends on the duration of the sleep and the period of the timers. It can lead to the overflow of some queues. This only applies to periodic timers, since one-shot timers are only called once.
This behavior can be changed by calling :cpp:func:`esp_timer_stop` before sleeping. In some cases, this can be inconvenient, and instead of the stop function, you can use the ``skip_unhandled_events`` option during :cpp:func:`esp_timer_create`. When the ``skip_unhandled_events`` is true, if a periodic timer expires one or more times during Light-sleep, then only one callback is called on wake.
Using the ``skip_unhandled_events`` option with automatic Light-sleep (see :doc:`Power Management APIs <power_management>`) helps to reduce the power consumption of the system when it is in Light-sleep. The duration of Light-sleep is also in part determined by the next event occurs. Timers with ``skip_unhandled_events`` option will not wake up the system.
Using the ``skip_unhandled_events`` option with automatic Light-sleep (see :doc:`Power Management APIs <power_management>`) helps to reduce the power consumption of the system when it is in Light-sleep. The duration of Light-sleep is also in part determined by the next event occurs. Timers with ``skip_unhandled_events`` option does not wake up the system.
Handling Callbacks
------------------

View File

@ -17,6 +17,7 @@ ESP-IDF FreeRTOS
ESP-IDF FreeRTOS is a FreeRTOS implementation based on Vanilla FreeRTOS v10.4.3, but contains significant modifications to support SMP. ESP-IDF FreeRTOS only supports two cores at most (i.e., dual core SMP), but is more optimized for this scenario by design. For more details regarding ESP-IDF FreeRTOS and its modifications, please refer to the :doc:`freertos_idf` document.
.. note::
ESP-IDF FreeRTOS is currently the default FreeRTOS implementation for ESP-IDF.
.. _amazon_smp_freertos:
@ -27,6 +28,7 @@ Amazon SMP FreeRTOS
Amazon SMP FreeRTOS is an SMP implementation of FreeRTOS that is officially supported by Amazon. Amazon SMP FreeRTOS is able to support N-cores (i.e., more than two cores). Amazon SMP FreeRTOS can be enabled via the :ref:`CONFIG_FREERTOS_SMP` option. For more details regarding Amazon SMP FreeRTOS, please refer to the `official Amazon SMP FreeRTOS documentation <https://freertos.org/symmetric-multiprocessing-introduction.html>`_.
.. warning::
The Amazon SMP FreeRTOS implementation (and its port in ESP-IDF) are currently in experimental/beta state. Therefore, significant behavioral changes and breaking API changes can occur.
Configuration
@ -37,11 +39,11 @@ Kernel Configuration
Vanilla FreeRTOS requires that ports and applications configure the kernel by adding various ``#define config...`` macros to ``FreeRTOSConfig.h``. Vanilla FreeRTOS supports a list of kernel configuration options which allow various kernel behaviors and features to be enabled or disabled.
**However, for all FreeRTOS ports in ESP-IDF, the ``FreeRTOSConfig.h`` file is considered private and must not be modified by users**. A large number of kernel configuration options in ``FreeRTOSConfig.h`` are hard coded as they are either required or not supported in ESP-IDF. All kernel configuration options that are configurable by the user will be exposed via menuconfig under ``Component Config/FreeRTOS/Kernel``.
**However, for all FreeRTOS ports in ESP-IDF, the ``FreeRTOSConfig.h`` file is considered private and must not be modified by users**. A large number of kernel configuration options in ``FreeRTOSConfig.h`` are hard coded as they are either required or not supported in ESP-IDF. All kernel configuration options that are configurable by the user are exposed via menuconfig under ``Component Config/FreeRTOS/Kernel``.
For the full list of user configurable kernel options, see :doc:`/api-reference/kconfig`. The list below highlights some commonly used kernel configuration options:
- :ref:`CONFIG_FREERTOS_UNICORE` will run FreeRTOS only on CPU0. Note that this is **not equivalent to running Vanilla FreeRTOS**. Furthermore, this option may affect behavior of components other than :component:`freertos`. For more details regarding the effects of running FreeRTOS on a single core, refer to :ref:`freertos-smp-single-core` (if using ESP-IDF FreeRTOS) or the official Amazon SMP FreeRTOS documentation. Alternatively, users can also search for occurrences of ``CONFIG_FREERTOS_UNICORE`` in the ESP-IDF components.
- :ref:`CONFIG_FREERTOS_UNICORE` runs FreeRTOS only on CPU0. Note that this is **not equivalent to running Vanilla FreeRTOS**. Furthermore, this option may affect behavior of components other than :component:`freertos`. For more details regarding the effects of running FreeRTOS on a single core, refer to :ref:`freertos-smp-single-core` (if using ESP-IDF FreeRTOS) or the official Amazon SMP FreeRTOS documentation. Alternatively, users can also search for occurrences of ``CONFIG_FREERTOS_UNICORE`` in the ESP-IDF components.
.. only:: CONFIG_FREERTOS_UNICORE
@ -64,7 +66,7 @@ Using FreeRTOS
Application Entry Point
^^^^^^^^^^^^^^^^^^^^^^^
Unlike Vanilla FreeRTOS, users of FreeRTOS in ESP-IDF **must never call** :cpp:func:`vTaskStartScheduler` and :cpp:func:`vTaskEndScheduler`. Instead, ESP-IDF will start FreeRTOS automatically. Users must define a ``void app_main(void)`` function which acts as the entry point for user's application and is automatically called on ESP-IDF startup.
Unlike Vanilla FreeRTOS, users of FreeRTOS in ESP-IDF **must never call** :cpp:func:`vTaskStartScheduler` and :cpp:func:`vTaskEndScheduler`. Instead, ESP-IDF starts FreeRTOS automatically. Users must define a ``void app_main(void)`` function which acts as the entry point for user's application and is automatically called on ESP-IDF startup.
- Typically, users would spawn the rest of their application's task from ``app_main``.
- The ``app_main`` function is allowed to return at any point (i.e., before the application terminates).
@ -75,7 +77,7 @@ Unlike Vanilla FreeRTOS, users of FreeRTOS in ESP-IDF **must never call** :cpp:f
Background Tasks
^^^^^^^^^^^^^^^^
During startup, ESP-IDF and FreeRTOS will automatically create multiple tasks that run in the background (listed in the the table below).
During startup, ESP-IDF and FreeRTOS automatically creates multiple tasks that run in the background (listed in the the table below).
.. list-table:: List of Tasks Created During Startup
:widths: 10 75 5 5 5
@ -107,7 +109,7 @@ During startup, ESP-IDF and FreeRTOS will automatically create multiple tasks th
- CPUx
- ``24``
* - ESP Timer Task (``esp_timer``)
- ESP-IDF will create the ESP Timer Task used to process ESP Timer callbacks.
- ESP-IDF creates the ESP Timer Task used to process ESP Timer callbacks.
- :ref:`CONFIG_ESP_TIMER_TASK_STACK_SIZE`
- CPU0
- ``22``

View File

@ -30,19 +30,21 @@ FreeRTOS provides stream buffers and message buffers as the primary mechanisms t
- Data is passed by copy
- Unable to reserve buffer space for a deferred send (i.e., send acquire)
Therefore, ESP-IDF provides a separate ring buffer implementation to address the issues above. ESP-IDF ring buffers are strictly FIFO buffers that supports arbitrarily sized items. Ring buffers are a more memory efficient alternative to FreeRTOS queues in situations where the size of items is variable. The capacity of a ring buffer is not measured by the number of items it can store, but rather by the amount of memory used for storing items. The ring buffer provides APIs to send an item, or to allocate space for an item in the ring buffer to be filled manually by the user. For efficiency reasons, **items are always retrieved from the ring buffer by reference**. As a result, all retrieved items *must also be returned* to the ring buffer by using :cpp:func:`vRingbufferReturnItem` or :cpp:func:`vRingbufferReturnItemFromISR`, in order for them to be removed from the ring buffer completely. The ring buffers are split into the three following types:
Therefore, ESP-IDF provides a separate ring buffer implementation to address the issues above. ESP-IDF ring buffers are strictly FIFO buffers that supports arbitrarily sized items. Ring buffers are a more memory efficient alternative to FreeRTOS queues in situations where the size of items is variable. The capacity of a ring buffer is not measured by the number of items it can store, but rather by the amount of memory used for storing items. The ring buffer provides APIs to send an item, or to allocate space for an item in the ring buffer to be filled manually by the user. For efficiency reasons, **items are always retrieved from the ring buffer by reference**. As a result, all retrieved items **must also be returned** to the ring buffer by using :cpp:func:`vRingbufferReturnItem` or :cpp:func:`vRingbufferReturnItemFromISR`, in order for them to be removed from the ring buffer completely. The ring buffers are split into the three following types:
**No-Split buffers** will guarantee that an item is stored in contiguous memory and will not attempt to split an item under any circumstances. Use No-Split buffers when items must occupy contiguous memory. *Only this buffer type allows you to get the data item address and write to the item by yourself.* Refer the documentation of the functions :cpp:func:`xRingbufferSendAcquire` and :cpp:func:`xRingbufferSendComplete` for more details.
**No-Split buffers** guarantee that an item is stored in contiguous memory and does not attempt to split an item under any circumstances. Use No-Split buffers when items must occupy contiguous memory. **Only this buffer type allows you to get the data item address and write to the item by yourself.** Refer to the documentation of the functions :cpp:func:`xRingbufferSendAcquire` and :cpp:func:`xRingbufferSendComplete` for more details.
**Allow-Split buffers** will allow an item to be split in two parts when wrapping around the end of the buffer if there is enough space at the tail and the head of the buffer combined to store the item. Allow-Split buffers are more memory efficient than No-Split buffers but can return an item in two parts when retrieving.
**Allow-Split buffers** allow an item to be split in two parts when wrapping around the end of the buffer if there is enough space at the tail and the head of the buffer combined to store the item. Allow-Split buffers are more memory efficient than No-Split buffers but can return an item in two parts when retrieving.
**Byte buffers** do not store data as separate items. All data is stored as a sequence of bytes, and any number of bytes can be sent or retrieved each time. Use byte buffers when separate items do not need to be maintained (e.g. a byte stream).
**Byte buffers** do not store data as separate items. All data is stored as a sequence of bytes, and any number of bytes can be sent or retrieved each time. Use byte buffers when separate items do not need to be maintained (e.g., a byte stream).
.. note::
No-Split buffers and Allow-Split buffers will always store items at 32-bit aligned addresses. Therefore, when retrieving an item, the item pointer is guaranteed to be 32-bit aligned. This is useful especially when you need to send some data to the DMA.
No-Split buffers and Allow-Split buffers always store items at 32-bit aligned addresses. Therefore, when retrieving an item, the item pointer is guaranteed to be 32-bit aligned. This is useful especially when you need to send some data to the DMA.
.. note::
Each item stored in No-Split or Allow-Split buffers will **require an additional 8 bytes for a header**. Item sizes will also be rounded up to a 32-bit aligned size (multiple of 4 bytes), however the true item size is recorded within the header. The sizes of No-Split and Allow-Split buffers will also be rounded up when created.
Each item stored in No-Split or Allow-Split buffers **requires an additional 8 bytes for a header**. Item sizes are also rounded up to a 32-bit aligned size (multiple of 4 bytes), however the true item size is recorded within the header. The sizes of No-Split and Allow-Split buffers will also be rounded up when created.
Usage
^^^^^
@ -217,9 +219,9 @@ Referring to the diagram above, the 18, 3, and 27 byte items are sequentially wr
Using SendAcquire and SendComplete
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Items in No-Split buffers are acquired (by ``SendAcquire``) in strict FIFO order and must be sent to the buffer by ``SendComplete`` for the data to be accessible by the consumer. Multiple items can be sent or acquired without calling ``SendComplete``, and the items do not necessarily need to be completed in the order they were acquired. However, the receiving of data items must occur in FIFO order, therefore not calling ``SendComplete`` for the earliest acquired item will prevent the subsequent items from being received.
Items in No-Split buffers are acquired (by ``SendAcquire``) in strict FIFO order and must be sent to the buffer by ``SendComplete`` for the data to be accessible by the consumer. Multiple items can be sent or acquired without calling ``SendComplete``, and the items do not necessarily need to be completed in the order they were acquired. However, the receiving of data items must occur in FIFO order, therefore not calling ``SendComplete`` for the earliest acquired item prevents the subsequent items from being received.
The following diagrams illustrate what will happen when ``SendAcquire`` and ``SendComplete`` don't happen in the same order. At the beginning, there is already a data item of 16 bytes sent to the ring buffer. Then ``SendAcquire`` is called to acquire space of 20, 8, 24 bytes on the ring buffer.
The following diagrams illustrate what will happen when ``SendAcquire`` and ``SendComplete`` do not happen in the same order. At the beginning, there is already a data item of 16 bytes sent to the ring buffer. Then ``SendAcquire`` is called to acquire space of 20, 8, 24 bytes on the ring buffer.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_send_acquire_complete.diag
:caption: SendAcquire/SendComplete items in No-Split ring buffers
@ -232,7 +234,7 @@ When the 20 bytes item is finally completed, all the 3 data items can be receive
Allow-Split buffers and byte buffers do not allow using ``SendAcquire`` or ``SendComplete`` since acquired buffers are required to be complete (not wrapped).
Wrap around
Wrap Around
^^^^^^^^^^^
The following diagrams illustrate the differences between No-Split, Allow-Split, and byte buffers when a sent item requires a wrap around. The diagrams assume a buffer of **128 bytes** with **56 bytes of free space that wraps around** and a sent item of **28 bytes**.
@ -241,7 +243,7 @@ The following diagrams illustrate the differences between No-Split, Allow-Split,
:caption: Wrap around in No-Split buffers
:align: center
No-Split buffers will **only store an item in continuous free space and will not split an item under any circumstances**. When the free space at the tail of the buffer is insufficient to completely store the item and its header, the free space at the tail will be **marked as dummy data**. The buffer will then wrap around and store the item in the free space at the head of the buffer.
No-Split buffers **only store an item in continuous free space and do not split an item under any circumstances**. When the free space at the tail of the buffer is insufficient to completely store the item and its header, the free space at the tail will be **marked as dummy data**. The buffer will then wrap around and store the item in the free space at the head of the buffer.
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is insufficient to store the 28 byte item. Therefore, the 16 bytes is marked as dummy data and the item is written to the free space at the head of the buffer instead.
@ -254,15 +256,16 @@ Allow-Split buffers will attempt to **split the item into two parts** when the f
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is insufficient to store the 28 byte item. Therefore, the item is split into two parts (8 and 20 bytes) and written as two parts to the buffer.
.. note::
Allow-Split buffers treat both parts of the split item as two separate items, therefore call :cpp:func:`xRingbufferReceiveSplit` instead of :cpp:func:`xRingbufferReceive` to receive both parts of a split item in a thread safe manner.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_byte_buf.diag
:caption: Wrap around in byte buffers
:align: center
Byte buffers will **store as much data as possible into the free space at the tail of buffer**. The remaining data will then be stored in the free space at the head of the buffer. No overhead is incurred when wrapping around in byte buffers.
Byte buffers **store as much data as possible into the free space at the tail of buffer**. The remaining data will then be stored in the free space at the head of the buffer. No overhead is incurred when wrapping around in byte buffers.
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is insufficient to completely store the 28 bytes of data. Therefore, the 16 bytes of free space is filled with data, and the remaining 12 bytes are written to the free space at the head of the buffer. The buffer now contains data in two separate continuous parts, and each continuous part will be treated as a separate item by the byte buffer.
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is insufficient to completely store the 28 bytes of data. Therefore, the 16 bytes of free space is filled with data, and the remaining 12 bytes are written to the free space at the head of the buffer. The buffer now contains data in two separate continuous parts, and each continuous part is treated as a separate item by the byte buffer.
Retrieving/Returning
^^^^^^^^^^^^^^^^^^^^
@ -273,7 +276,7 @@ The following diagrams illustrate the differences between No-Split and Allow-Spl
:caption: Retrieving/Returning items in No-Split and Allow-Split ring buffers
:align: center
Items in No-Split buffers and Allow-Split buffers are **retrieved in strict FIFO order** and **must be returned** for the occupied space to be freed. Multiple items can be retrieved before returning, and the items do not necessarily need to be returned in the order they were retrieved. However, the freeing of space must occur in FIFO order, therefore not returning the earliest retrieved item will prevent the space of subsequent items from being freed.
Items in No-Split buffers and Allow-Split buffers are **retrieved in strict FIFO order** and **must be returned** for the occupied space to be freed. Multiple items can be retrieved before returning, and the items do not necessarily need to be returned in the order they were retrieved. However, the freeing of space must occur in FIFO order, therefore not returning the earliest retrieved item prevents the space of subsequent items from being freed.
Referring to the diagram above, the **16, 20, and 8 byte items are retrieved in FIFO order**. However, the items are not returned in the order they were retrieved. First, the 20 byte item is returned followed by the 8 byte and the 16 byte items. The space is not freed until the first item, i.e., the 16 byte item is returned.
@ -281,7 +284,7 @@ Referring to the diagram above, the **16, 20, and 8 byte items are retrieved in
:caption: Retrieving/Returning data in byte buffers
:align: center
Byte buffers **do not allow multiple retrievals before returning** (every retrieval must be followed by a return before another retrieval is permitted). When using :cpp:func:`xRingbufferReceive` or :cpp:func:`xRingbufferReceiveFromISR`, all continuous stored data will be retrieved. :cpp:func:`xRingbufferReceiveUpTo` or :cpp:func:`xRingbufferReceiveUpToFromISR` can be used to restrict the maximum number of bytes retrieved. Since every retrieval must be followed by a return, the space will be freed as soon as the data is returned.
Byte buffers **do not allow multiple retrievals before returning** (every retrieval must be followed by a return before another retrieval is permitted). When using :cpp:func:`xRingbufferReceive` or :cpp:func:`xRingbufferReceiveFromISR`, all continuous stored data will be retrieved. :cpp:func:`xRingbufferReceiveUpTo` or :cpp:func:`xRingbufferReceiveUpToFromISR` can be used to restrict the maximum number of bytes retrieved. Since every retrieval must be followed by a return, the space is freed as soon as the data is returned.
Referring to the diagram above, the 38 bytes of continuous stored data at the tail of the buffer is retrieved, returned, and freed. The next call to :cpp:func:`xRingbufferReceive` or :cpp:func:`xRingbufferReceiveFromISR` then wraps around and does the same to the 30 bytes of continuous stored data at the head of the buffer.
@ -334,9 +337,10 @@ The :cpp:func:`xRingbufferCreateStatic` can be used to create ring buffers with
- The ring buffer's data structure of type :cpp:type:`StaticRingbuffer_t`
- The ring buffer's storage area of size ``xBufferSize``. Note that ``xBufferSize`` must be 32-bit aligned for No-Split and Allow-Split buffers.
The manner in which these blocks are allocated will depend on the users requirements (e.g. all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM).
The manner in which these blocks are allocated depends on the users requirements (e.g., all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM).
.. note::
When deleting a ring buffer created via :cpp:func:`xRingbufferCreateStatic`,
the function :cpp:func:`vRingbufferDelete` will not free any of the memory blocks. This must be done manually by the user after :cpp:func:`vRingbufferDelete` is called.
@ -423,14 +427,14 @@ However, there can be instances where users may want the freeing of TLSP memory
The TLSP deletion callbacks are set in a similar fashion to the TLSPs themselves.
- :cpp:func:`vTaskSetThreadLocalStoragePointerAndDelCallback` sets both a particular TLSP and its associated callback.
- Calling the Vanilla FreeRTOS function :cpp:func:`vTaskSetThreadLocalStoragePointer` will simply set the TLSP's associated Deletion Callback to `NULL` meaning that no callback will be called for that TLSP during task deletion.
- Calling the Vanilla FreeRTOS function :cpp:func:`vTaskSetThreadLocalStoragePointer` simply sets the TLSP's associated Deletion Callback to `NULL`, meaning that no callback is called for that TLSP during task deletion.
When implementing TLSP callbacks, users should note the following:
- The callback **must never attempt to block or yield** and critical sections should be kept as short as possible
- The callback is called shortly before a deleted task's memory is freed. Thus, the callback can either be called from :cpp:func:`vTaskDelete` itself, or from the idle task.
.. ----------------------------------------------- IDF Additional API --------------------------------------------------
.. ----------------------------------------------- ESP-IDF Additional API --------------------------------------------------
.. _freertos-idf-additional-api:

View File

@ -11,10 +11,12 @@ The original FreeRTOS (hereinafter referred to as Vanilla FreeRTOS) is a small a
ESP-IDF FreeRTOS is based on Vanilla FreeRTOS v10.4.3, but contains significant modifications to both API and kernel behavior in order to support dual core SMP. This document describes the API and behavioral differences between Vanilla FreeRTOS and ESP-IDF FreeRTOS.
.. note::
This document assumes that the reader has a requisite understanding of Vanilla FreeRTOS (its features, behavior, and API usage). Refer to the `Vanilla FreeRTOS documentation <https://www.freertos.org/index.html>`_ for more details.
.. note::
ESP-IDF FreeRTOS can be built for single core by enabling the :ref:`CONFIG_FREERTOS_UNICORE` configuration option. ESP targets that are single core will always have the :ref:`CONFIG_FREERTOS_UNICORE` option enabled. However, note that building with :ref:`CONFIG_FREERTOS_UNICORE` enabled does not equate to building with Vanilla FreeRTOS (i.e., some of the behavioral and API changes of ESP-IDF will still be present). For more details, see :ref:`freertos-smp-single-core` for more details.
ESP-IDF FreeRTOS can be built for a single core by enabling the :ref:`CONFIG_FREERTOS_UNICORE` configuration option. ESP targets that are single core always have the :ref:`CONFIG_FREERTOS_UNICORE` option enabled. However, note that building with :ref:`CONFIG_FREERTOS_UNICORE` enabled does not equate to building with Vanilla FreeRTOS (i.e., some of the behavioral and API changes of ESP-IDF are still present). For more details, see :ref:`freertos-smp-single-core`.
This document is split into the following parts.
@ -33,16 +35,16 @@ Basic Concepts
SMP (Symmetric Multiprocessing) is a computing architecture where two or more identical CPUs (cores) are connected to a single shared main memory and controlled by a single operating system. In general, an SMP system...
- has multiple cores running independently. Each core has its own register file, interrupts, and interrupt handling.
- presents an identical view of memory to each core. Thus a piece of code that accesses a particular memory address will have the same effect regardless of which core it runs on.
- presents an identical view of memory to each core. Thus a piece of code that accesses a particular memory address has the same effect regardless of which core it runs on.
The main advantages of an SMP system compared to single core or Asymmetric Multiprocessing systems are that...
- the presence of multiple CPUs allows for multiple hardware threads, thus increases overall processing throughput.
- having symmetric memory means that threads can switch cores during execution. This in general can lead to better CPU utilization.
Although an SMP system allows threads to switch cores, there are scenarios where a thread must/should only run on a particular core. Therefore, threads in an SMP systems will also have a core affinity that specifies which particular core the thread is allowed to run on.
Although an SMP system allows threads to switch cores, there are scenarios where a thread must/should only run on a particular core. Therefore, threads in an SMP system also have a core affinity that specifies which particular core the thread is allowed to run on.
- A thread that is pinned to a particular core will only be able to run on that core
- A thread that is pinned to a particular core is only be able to run on that core
- A thread that is unpinned will be allowed to switch between cores during execution instead of being pinned to a particular core.
SMP on an ESP Target
@ -59,7 +61,8 @@ ESP targets (such as the ESP32, ESP32-S3) are dual core SMP SoCs. These targets
- Cross-core interrupts that allow one CPU to trigger and interrupt on another CPU. This allows cores to signal each other.
.. note::
The "PRO_CPU" and "APP_CPU" aliases for CPU0 and CPU1 exist in ESP-IDF as they reflect how typical IDF applications will utilize the two CPUs. Typically, the tasks responsible for handling wireless networking (e.g., WiFi or Bluetooth) will be pinned to CPU0 (thus the name PRO_CPU), whereas the tasks handling the remainder of the application will be pinned to CPU1 (thus the name APP_CPU).
The ``PRO_CPU`` and ``APP_CPU`` aliases for CPU0 and CPU1 exist in ESP-IDF as they reflect how typical ESP-IDF applications utilize the two CPUs. Typically, the tasks responsible for handling wireless networking (e.g., Wi-Fi or Bluetooth) are pinned to CPU0 (thus the name PRO_CPU), whereas the tasks handling the remainder of the application are pinned to CPU1 (thus the name APP_CPU).
.. ------------------------------------------------------ Tasks --------------------------------------------------------
@ -89,6 +92,7 @@ The ``PinnedToCore`` versions of the task creation functions API differ from the
Note that ESP-IDF FreeRTOS still supports the vanilla versions of the task creation functions. However, they have been modified to simply call their ``PinnedToCore`` counterparts with ``tskNO_AFFINITY``.
.. note::
ESP-IDF FreeRTOS also changes the units of ``ulStackDepth`` in the task creation functions. Task stack sizes in Vanilla FreeRTOS are specified in number of words, whereas in ESP-IDF FreeRTOS, the task stack sizes are specified in bytes.
Execution
@ -134,14 +138,14 @@ The Vanilla FreeRTOS scheduler is best described as a **Fixed Priority Preemptiv
- Each tasks is given a constant priority upon creation. The scheduler executes highest priority ready state task
- The scheduler can switch execution to another task without the cooperation of the currently running task
- The scheduler will periodically switch execution between ready state tasks of the same priority (in a round robin fashion). Time slicing is governed by a tick interrupt.
- The scheduler periodically switches execution between ready state tasks of the same priority (in a round robin fashion). Time slicing is governed by a tick interrupt.
The ESP-IDF FreeRTOS scheduler supports the same scheduling features (i.e., Fixed Priority, Preemption, and Time Slicing) albeit with some small behavioral differences.
Fixed Priority
^^^^^^^^^^^^^^
In Vanilla FreeRTOS, when scheduler selects a new task to run, it will always select the current highest priority ready state task. In ESP-IDF FreeRTOS, each core will independently schedule tasks to run. When a particular core selects a task, the core will select the highest priority ready state task that can be run by the core. A task can be run by the core if:
In Vanilla FreeRTOS, when scheduler selects a new task to run, it always selects the current highest priority ready state task. In ESP-IDF FreeRTOS, each core independently schedules tasks to run. When a particular core selects a task, the core will select the highest priority ready state task that can be run by the core. A task can be run by the core if:
- The task has a compatible affinity (i.e., is either pinned to that core or is unpinned)
- The task is not currently being run by another core
@ -159,7 +163,7 @@ Preemption
In Vanilla FreeRTOS, the scheduler can preempt the currently running task if a higher priority task becomes ready to execute. Likewise in ESP-IDF FreeRTOS, each core can be individually preempted by the scheduler if the scheduler determines that a higher priority task can run on that core.
However, there are some instances where a higher priority task that becomes ready can be run on multiple cores. In this case, the scheduler will only preempt one core. The scheduler always gives preference to the current core when multiple cores can be preempted. In other words, if the higher priority ready task is unpinned and has a higher priority than the current priority of both cores, the scheduler will always choose to preempt the current core. For example, given the following tasks:
However, there are some instances where a higher priority task that becomes ready can be run on multiple cores. In this case, the scheduler only preempts one core. The scheduler always gives preference to the current core when multiple cores can be preempted. In other words, if the higher priority ready task is unpinned and has a higher priority than the current priority of both cores, the scheduler will always choose to preempt the current core. For example, given the following tasks:
- Task A of priority 8 currently running on CPU0
- Task B of priority 9 currently running on CPU1
@ -179,7 +183,7 @@ However, in ESP-IDF FreeRTOS, it is not possible to implement perfect Round Robi
Therefore, when a core searches the ready state task list for a task to run, the core may need to skip over a few tasks in the same priority list or drop to a lower priority in order to find a ready state task that the core can run.
The ESP-IDF FreeRTOS scheduler implements a Best Effort Round Robin time slicing for ready state tasks of the same priority by ensuring that tasks that have been selected to run will be placed at the back of the list, thus giving unselected tasks a higher priority on the next scheduling iteration (i.e., the next tick interrupt or yield)
The ESP-IDF FreeRTOS scheduler implements a Best Effort Round Robin time slicing for ready state tasks of the same priority by ensuring that tasks that have been selected to run are placed at the back of the list, thus giving unselected tasks a higher priority on the next scheduling iteration (i.e., the next tick interrupt or yield)
The following example demonstrates the Best Effort Round Robin time slicing in action. Assume that:
@ -199,7 +203,7 @@ The following example demonstrates the Best Effort Round Robin time slicing in a
--------------------------------------------------------------------------------
2. Core 0 has tick interrupt and searches for a task to run.
1. Core 0 has tick interrupt and searches for a task to run.
Task A is selected and is moved to the back of the list
Core0--|
@ -210,7 +214,7 @@ The following example demonstrates the Best Effort Round Robin time slicing in a
--------------------------------------------------------------------------------
3. Core 1 has a tick interrupt and searches for a task to run.
1. Core 1 has a tick interrupt and searches for a task to run.
Task B cannot be run due to incompatible affinity, so core 1 skips to Task C.
Task C is selected and is moved to the back of the list
@ -222,7 +226,7 @@ The following example demonstrates the Best Effort Round Robin time slicing in a
--------------------------------------------------------------------------------
4. Core 0 has another tick interrupt and searches for a task to run.
1. Core 0 has another tick interrupt and searches for a task to run.
Task B is selected and moved to the back of the list
@ -234,7 +238,7 @@ The following example demonstrates the Best Effort Round Robin time slicing in a
--------------------------------------------------------------------------------
5. Core 1 has another tick and searches for a task to run.
1. Core 1 has another tick and searches for a task to run.
Task D cannot be run due to incompatible affinity, so core 1 skips to Task A
Task A is selected and moved to the back of the list
@ -262,13 +266,14 @@ Vanilla FreeRTOS requires that a periodic tick interrupt occurs. The tick interr
- Checking if time slicing is required (i.e., triggering a context switch)
- Executing the application tick hook
In ESP-IDF FreeRTOS, each core will receive a periodic interrupt and independently run the tick interrupt. The tick interrupts on each core are of the same period but can be out of phase. However, the tick responsibilities listed above are not run by all cores:
In ESP-IDF FreeRTOS, each core receives a periodic interrupt and independently run the tick interrupt. The tick interrupts on each core are of the same period but can be out of phase. However, the tick responsibilities listed above are not run by all cores:
- CPU0 will execute all of the tick interrupt responsibilities listed above
- CPU1 will only check for time slicing and execute the application tick hook
- CPU0 executes all of the tick interrupt responsibilities listed above
- CPU1 only checks for time slicing and execute the application tick hook
.. note::
CPU0 is solely responsible for keeping time in ESP-IDF FreeRTOS. Therefore anything that prevents CPU0 from incrementing the tick count (such as suspending the scheduler on CPU0) will cause the entire schedulers time keeping to lag behind.
CPU0 is solely responsible for keeping time in ESP-IDF FreeRTOS. Therefore anything that prevents CPU0 from incrementing the tick count (such as suspending the scheduler on CPU0) causes the entire schedulers time keeping to lag behind.
Idle Tasks
^^^^^^^^^^
@ -287,9 +292,9 @@ Vanilla FreeRTOS allows the scheduler to be suspended/resumed by calling :cpp:fu
- Task switching is disabled but interrupts are left enabled.
- Calling any blocking/yielding function is forbidden, and time slicing is disabled.
- The tick count is frozen (but the tick interrupt will still occur to execute the application tick hook)
- The tick count is frozen (but the tick interrupt still occurs to execute the application tick hook)
On scheduler resumption, :cpp:func:`xTaskResumeAll` will catch up all of the lost ticks and unblock any timed out tasks.
On scheduler resumption, :cpp:func:`xTaskResumeAll` catches up all of the lost ticks and unblock any timed out tasks.
In ESP-IDF FreeRTOS, suspending the scheduler across multiple cores is not possible. Therefore when :cpp:func:`vTaskSuspendAll` is called on a particular core (e.g., core A):
@ -305,16 +310,18 @@ When :cpp:func:`xTaskResumeAll` is called on a particular core (e.g., core A):
- If core A is CPU0, the pended tick count is unwound to catch up the lost ticks.
.. warning::
Given that scheduler suspension on ESP-IDF FreeRTOS will only suspend scheduling on a particular core, scheduler suspension is **NOT** a valid method ensuring mutual exclusion between tasks when accessing shared data. Users should use proper locking primitives such as mutexes or spinlocks if they require mutual exclusion.
Given that scheduler suspension on ESP-IDF FreeRTOS only suspends scheduling on a particular core, scheduler suspension is **NOT** a valid method ensuring mutual exclusion between tasks when accessing shared data. Users should use proper locking primitives such as mutexes or spinlocks if they require mutual exclusion.
Disabling Interrupts
^^^^^^^^^^^^^^^^^^^^
Vanilla FreeRTOS allows interrupts to be disabled and enabled by calling :c:macro:`taskDISABLE_INTERRUPTS` and :c:macro:`taskENABLE_INTERRUPTS` respectively.
ESP-IDF FreeRTOS provides the same API, however interrupts will only disabled or enabled on the current core.
ESP-IDF FreeRTOS provides the same API, however interrupts are only disabled or enabled on the current core.
.. warning::
Disabling interrupts is a valid method of achieve mutual exclusion in Vanilla FreeRTOS (and single core systems in general). However, in an SMP system, disabling interrupts is **NOT** a valid method ensuring mutual exclusion. Refer to Critical Sections for more details.
@ -342,6 +349,7 @@ However, in an SMP system, merely disabling interrupts does not constitute a cri
- ``taskEXIT_CRITICAL_ISR(&spinlock)`` exits a critical section from an interrupt context
.. note::
The critical section API can be called recursively (i.e., nested critical sections). Entering a critical section multiple times recursively is valid so long as the critical section is exited the same number of times it was entered. However, given that critical sections can target different spinlocks, users should take care to avoid dead locking when entering critical sections recursively.
Spinlocks can be allocated statically or dynamically. As such, macros are provided for both static and dynamic initialization of spinlocks, as demonstrated by the following code snippets.
@ -421,7 +429,7 @@ Usually, when a context switch occurs:
However, ESP-IDF FreeRTOS implements Lazy Context Switching for the FPU (Floating Point Unit) registers of a CPU. In other words, when a context switch occurs on a particular core (e.g., CPU0), the state of the core's FPU registers are not immediately saved to the stack of the task getting switched out (e.g., Task A). The FPU's registers are left untouched until:
- A different task (e.g., Task B) runs on the same core and uses the FPU. This will trigger an exception that will save the FPU registers to Task A's stack.
- A different task (e.g., Task B) runs on the same core and uses the FPU. This will trigger an exception that saves the FPU registers to Task A's stack.
- Task A get's scheduled to the same core and continues execution. Saving and restoring the FPU's registers is not necessary in this case.
However, given that tasks can be unpinned thus can be scheduled on different cores (e.g., Task A switches to CPU1), it is unfeasible to copy and restore the FPU's registers across cores. Therefore, when a task utilizes the FPU (by using a ``float`` type in its call flow), ESP-IDF FreeRTOS will automatically pin the task to the current core it is running on. This ensures that all tasks that uses the FPU are always pinned to a particular core.
@ -431,9 +439,11 @@ Furthermore, ESP-IDF FreeRTOS by default does not support the usage of the FPU w
.. only: esp32
.. note::
Users that require the use of the ``float`` type in an ISR routine should refer to the :ref:`CONFIG_FREERTOS_FPU_IN_ISR` configuration option.
.. note::
ESP targets that contain an FPU do not support hardware acceleration for double precision floating point arithmetic (``double``). Instead ``double`` is implemented via software hence the behavioral restrictions regarding the ``float`` type do not apply to ``double``. Note that due to the lack of hardware acceleration, ``double`` operations may consume significantly more CPU time in comparison to ``float``.
@ -444,12 +454,13 @@ Furthermore, ESP-IDF FreeRTOS by default does not support the usage of the FPU w
ESP-IDF FreeRTOS Single Core
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Although ESP-IDF FreeRTOS is an SMP scheduler, some ESP targets are single core (such as the ESP32-S2 and ESP32-C3). When building ESP-IDF applications for these targets, ESP-IDF FreeRTOS is still used but the number of cores will be set to `1` (i.e., the :ref:`CONFIG_FREERTOS_UNICORE` will always be enabled for single core targets).
Although ESP-IDF FreeRTOS is an SMP scheduler, some ESP targets are single core (such as the ESP32-S2 and ESP32-C3). When building ESP-IDF applications for these targets, ESP-IDF FreeRTOS is still used but the number of cores will be set to ``1`` (i.e., the :ref:`CONFIG_FREERTOS_UNICORE` will always be enabled for single core targets).
For multicore targets (such as the ESP32 and ESP32-S3), :ref:`CONFIG_FREERTOS_UNICORE` can also be set. This will result in ESP-IDF FreeRTOS only running on CPU0, and all other cores will be inactive.
For multicore targets (such as the ESP32 and ESP32-S3), :ref:`CONFIG_FREERTOS_UNICORE` can also be set. This results in ESP-IDF FreeRTOS only running on CPU0, and all other cores will be inactive.
.. note::
Users should bear in mind that enabling :ref:`CONFIG_FREERTOS_UNICORE` **is NOT equivalent to running Vanilla FreeRTOS**. The additional API of ESP-IDF FreeRTOS can still be called, and the behavior changes of ESP-IDF FreeRTOS will incur a small amount of overhead even when compiled for only a single core.
Users should bear in mind that enabling :ref:`CONFIG_FREERTOS_UNICORE` **is NOT equivalent to running Vanilla FreeRTOS**. The additional API of ESP-IDF FreeRTOS can still be called, and the behavior changes of ESP-IDF FreeRTOS incurs a small amount of overhead even when compiled for only a single core.
.. ------------------------------------------------- API References ----------------------------------------------------

View File

@ -22,7 +22,7 @@ To obtain information about the state of the heap, call the following functions:
- :cpp:func:`heap_caps_get_minimum_free_size` can be used to track the heap "low watermark" since boot.
- :cpp:func:`heap_caps_get_info` returns a :cpp:class:`multi_heap_info_t` structure, which contains the information from the above functions, plus some additional heap-specific data (number of allocations, etc.).
- :cpp:func:`heap_caps_print_heap_info` prints a summary of the information returned by :cpp:func:`heap_caps_get_info` to stdout.
- :cpp:func:`heap_caps_dump` and :cpp:func:`heap_caps_dump_all` will output detailed information about the structure of each block in the heap. Note that this can be a large amount of output.
- :cpp:func:`heap_caps_dump` and :cpp:func:`heap_caps_dump_all` output detailed information about the structure of each block in the heap. Note that this can be a large amount of output.
.. _heap-allocation-free:
@ -82,7 +82,7 @@ It is also possible to manually check heap integrity by calling :cpp:func:`heap_
Memory Allocation Failed Hook
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Users can use :cpp:func:`heap_caps_register_failed_alloc_callback` to register a callback that will be invoked every time an allocation operation fails.
Users can use :cpp:func:`heap_caps_register_failed_alloc_callback` to register a callback that is invoked every time an allocation operation fails.
Additionally, users can enable the :ref:`CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS`, which will automatically trigger a system abort if any allocation operation fails.
@ -133,7 +133,7 @@ This is the default level. By default, no special heap corruption features are e
If assertions are enabled, an assertion will also trigger if a double-free occurs (the same memory is freed twice).
Calling :cpp:func:`heap_caps_check_integrity` in Basic mode will check the integrity of all heap structures, and print errors if any appear to be corrupted.
Calling :cpp:func:`heap_caps_check_integrity` in Basic mode checks the integrity of all heap structures, and print errors if any appear to be corrupted.
Light Impact
++++++++++++
@ -212,7 +212,7 @@ If you suspect a memory leak, the first step is to figure out which part of the
Standalone Mode
+++++++++++++++
Once you've identified the code which you think is leaking:
Once you have identified the code which you think is leaking:
- Enable the :ref:`CONFIG_HEAP_TRACING_DEST` option.
- Call the function :cpp:func:`heap_trace_init_standalone` early in the program, to register a buffer that can be used to record the memory trace.
@ -249,7 +249,7 @@ The following code snippet demonstrates how application code would typically ini
...
}
The output from the heap trace will have a similar format to the following example:
The output from the heap trace has a similar format to the following example:
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
@ -308,7 +308,7 @@ A warning will be printed if the trace buffer was not large enough to hold all t
Host-Based Mode
+++++++++++++++
Once you've identified the code which you think is leaking:
Once you have identified the code which you think is leaking:
- In the project configuration menu, navigate to ``Component settings`` > ``Heap Memory Debugging`` > :ref:`CONFIG_HEAP_TRACING_DEST` and select ``Host-Based``.
- In the project configuration menu, navigate to ``Component settings`` > ``Application Level Tracing`` > :ref:`CONFIG_APPTRACE_DESTINATION1` and select ``Trace memory``.
@ -377,7 +377,7 @@ To gather and analyze heap trace, do the following on the host:
c
Using this file GDB will connect to the target, reset it, and start tracing when the program hits breakpoint at :cpp:func:`heap_trace_start`. Tracing will be stopped when the program hits breakpoint at :cpp:func:`heap_trace_stop`. Traced data will be saved to ``/tmp/heap_log.svdat``.
Using this file GDB can connect to the target, reset it, and start tracing when the program hits breakpoint at :cpp:func:`heap_trace_start`. Tracing will be stopped when the program hits breakpoint at :cpp:func:`heap_trace_stop`. Traced data will be saved to ``/tmp/heap_log.svdat``.
4. Run GDB using ``{IDF_TARGET_TOOLCHAIN_PREFIX}-gdb -x gdbinit </path/to/program/elf>``.
@ -385,7 +385,7 @@ Using this file GDB will connect to the target, reset it, and start tracing when
6. Run processing script ``$IDF_PATH/tools/esp_app_trace/sysviewtrace_proc.py -p -b </path/to/program/elf> /tmp/heap_log.svdat``.
The output from the heap trace will have a similar format to the following example:
The output from the heap trace has a similar format to the following example:
.. code-block::
@ -501,12 +501,12 @@ False-Positive Memory Leaks
Not everything printed by :cpp:func:`heap_trace_dump` is necessarily a memory leak. The following cases may also be printed:
- Any memory that is allocated after :cpp:func:`heap_trace_start` but freed after :cpp:func:`heap_trace_stop` will appear in the leaked dump.
- Any memory that is allocated after :cpp:func:`heap_trace_start` but freed after :cpp:func:`heap_trace_stop` appears in the leaked dump.
- Allocations may be made by other tasks in the system. Depending on the timing of these tasks, it is quite possible that this memory is freed after :cpp:func:`heap_trace_stop` is called.
- The first time a task uses stdio - e.g., when it calls :cpp:func:`heap_caps_printf` - a lock, i.e., RTOS mutex semaphore, is allocated by the libc. This allocation lasts until the task is deleted.
- Certain uses of :cpp:func:`heap_caps_printf` , such as printing floating point numbers, will allocate some memory from the heap on demand. These allocations last until the task is deleted.
- The Bluetooth, Wi-Fi, and TCP/IP libraries will allocate heap memory buffers to handle incoming or outgoing data. These memory buffers are usually short-lived, but some may be shown in the heap leak trace if the data has been received or transmitted by the lower levels of the network during the heap tracing.
- TCP connections will retain some memory even after they are closed due to the ``TIME_WAIT`` state. Once the ``TIME_WAIT`` period is completed, this memory will be freed.
- Certain uses of :cpp:func:`heap_caps_printf`, such as printing floating point numbers and allocating some memory from the heap on demand. These allocations last until the task is deleted.
- The Bluetooth, Wi-Fi, and TCP/IP libraries allocate heap memory buffers to handle incoming or outgoing data. These memory buffers are usually short-lived, but some may be shown in the heap leak trace if the data has been received or transmitted by the lower levels of the network during the heap tracing.
- TCP connections retain some memory even after they are closed due to the ``TIME_WAIT`` state. Once the ``TIME_WAIT`` period is completed, this memory will be freed.
One way to differentiate between "real" and "false positive" memory leaks is to call the suspect code multiple times while tracing is running, and look for patterns (multiple matching allocations) in the heap trace output.

View File

@ -1,30 +1,21 @@
The himem allocation API
The Himem Allocation API
========================
Overview
--------
The ESP32 can access external SPI RAM transparently, so you can use it as normal memory in your program code. However, because the address
space for external memory is limited in size, only the first 4MiB can be used as such. Access to the remaining memory is still possible,
however this needs to go through a bankswitching scheme controlled by the himem API.
The ESP32 can access external SPI RAM transparently, so you can use it as normal memory in your program code. However, because the address space for external memory is limited in size, only the first 4 MiB can be used as such. Access to the remaining memory is still possible, however this needs to go through a bankswitching scheme controlled by the himem API.
Specifically, what is implemented by the himem API is a bankswitching scheme. Hardware-wise, the 4MiB region for external SPI RAM is
mapped into the CPU address space by a MMU, which maps a configurable 32K bank/page of external SPI RAM into each of the 32K pages in the
4MiB region accessed by the CPU. For external memories that are <=4MiB, this MMU is configured to unity mapping, effectively mapping each
CPU address 1-to-1 to the external SPI RAM address.
Specifically, what is implemented by the himem API is a bankswitching scheme. Hardware-wise, the 4 MiB region for external SPI RAM is mapped into the CPU address space by a MMU, which maps a configurable 32 K bank/page of external SPI RAM into each of the 32 K pages in the 4 MiB region accessed by the CPU. For external memories that are <= 4 MiB, this MMU is configured to unity mapping, effectively mapping each CPU address 1-to-1 to the external SPI RAM address.
In order to use the himem API, you have to enable it in the menuconfig using :ref:`CONFIG_SPIRAM_BANKSWITCH_ENABLE`, as well as set the amount
of banks reserved for this in :ref:`CONFIG_SPIRAM_BANKSWITCH_RESERVE`. This decreases
the amount of external memory allocated by functions like ``malloc()``, but it allows you to use the himem api to map any of the remaining memory
into the reserved banks.
In order to use the himem API, you have to enable it in the menuconfig using :ref:`CONFIG_SPIRAM_BANKSWITCH_ENABLE`, as well as set the amount of banks reserved for this in :ref:`CONFIG_SPIRAM_BANKSWITCH_RESERVE`. This decreases the amount of external memory allocated by functions like ``malloc()``, but it allows you to use the himem api to map any of the remaining memory into the reserved banks.
The himem API is more-or-less an abstraction of the bankswitching scheme: it allows you to claim one or more banks of address space
(called 'regions' in the API) as well as one or more of banks of memory to map into the ranges.
The himem API is more-or-less an abstraction of the bankswitching scheme: it allows you to claim one or more banks of address space (called 'regions' in the API) as well as one or more of banks of memory to map into the ranges.
Example
-------
An example doing a simple memory test of the high memory range is available in esp-idf: :example:`system/himem`
An example doing a simple memory test of the high memory range is available in ESP-IDF: :example:`system/himem`
API Reference

View File

@ -1,4 +1,4 @@
Interrupt allocation
Interrupt Allocation
====================
Overview
@ -22,7 +22,7 @@ Overview
.. only:: esp32c6 or esp32h2
The {IDF_TARGET_NAME} has one core, with 28 external asynchronous interrupts. Each interrupt has a programmable priority level. In addition, there are also 4 core local interrupt sources (CLINT). See *{IDF_TARGET_NAME} Technical Reference Manual* [`PDF <{IDF_TARGET_TRM_EN_URL}#riscvcpu>`__] for more details.
The {IDF_TARGET_NAME} has one core, with 28 external asynchronous interrupts. Each interrupt has a programmable priority level. In addition, there are also 4 core local interrupt sources (CLINT). See **{IDF_TARGET_NAME} Technical Reference Manual** [`PDF <{IDF_TARGET_TRM_EN_URL}#riscvcpu>`__] for more details.
Because there are more interrupt sources than interrupts, sometimes it makes sense to share an interrupt in multiple drivers. The :cpp:func:`esp_intr_alloc` abstraction exists to hide all these implementation details.
@ -32,12 +32,12 @@ This code presents two different types of interrupts, handled differently: share
Non-shared interrupts can be either level- or edge-triggered. Shared interrupts can only be level interrupts due to the chance of missed interrupts when edge interrupts are used.
For example, let's say DevA and DevB share an interrupt. DevB signals an interrupt, so INT line goes high. The ISR handler calls code for DevA but does nothing. Then, ISR handler calls code for DevB, but while doing that, DevA signals an interrupt. DevB's ISR is done, it clears interrupt status for DevB and exits interrupt code. Now, an interrupt for DevA is still pending, but because the INT line never went low, as DevA kept it high even when the interrupt for DevB was cleared, the interrupt is never serviced.
For example, let us say DevA and DevB share an interrupt. DevB signals an interrupt, so INT line goes high. The ISR handler calls code for DevA but does nothing. Then, ISR handler calls code for DevB, but while doing that, DevA signals an interrupt. DevB's ISR is done, it clears interrupt status for DevB and exits interrupt code. Now, an interrupt for DevA is still pending, but because the INT line never went low, as DevA kept it high even when the interrupt for DevB was cleared, the interrupt is never serviced.
.. only:: esp32 or esp32s3
Multicore issues
Multicore Issues
----------------
Peripherals that can generate interrupts can be divided in two types:
@ -47,7 +47,7 @@ For example, let's say DevA and DevB share an interrupt. DevB signals an interru
Interrupt handling differs slightly between these two types of peripherals.
Internal peripheral interrupts
Internal Peripheral Interrupts
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Each Xtensa CPU core has its own set of six internal peripherals:
@ -56,14 +56,14 @@ For example, let's say DevA and DevB share an interrupt. DevB signals an interru
- A performance monitor
- Two software interrupts.
Internal interrupt sources are defined in esp_intr_alloc.h as ``ETS_INTERNAL_*_INTR_SOURCE``.
Internal interrupt sources are defined in ``esp_intr_alloc.h`` as ``ETS_INTERNAL_*_INTR_SOURCE``.
These peripherals can only be configured from the core they are associated with. When generating an interrupt, the interrupt they generate is hard-wired to their associated core; it's not possible to have, for example, an internal timer comparator of one core generate an interrupt on another core. That is why these sources can only be managed using a task running on that specific core. Internal interrupt sources are still allocatable using :cpp:func:`esp_intr_alloc` as normal, but they cannot be shared and will always have a fixed interrupt level (namely, the one associated in hardware with the peripheral).
These peripherals can only be configured from the core they are associated with. When generating an interrupt, the interrupt they generate is hard-wired to their associated core; it is not possible to have, for example, an internal timer comparator of one core generate an interrupt on another core. That is why these sources can only be managed using a task running on that specific core. Internal interrupt sources are still allocatable using :cpp:func:`esp_intr_alloc` as normal, but they cannot be shared and will always have a fixed interrupt level (namely, the one associated in hardware with the peripheral).
External Peripheral Interrupts
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The remaining interrupt sources are from external peripherals. These are defined in soc/soc.h as ``ETS_*_INTR_SOURCE``.
The remaining interrupt sources are from external peripherals. These are defined in ``soc/soc.h`` as ``ETS_*_INTR_SOURCE``.
Non-internal interrupt slots in both CPU cores are wired to an interrupt multiplexer, which can be used to route any external interrupt source to any of these interrupt slots.
@ -72,7 +72,7 @@ For example, let's say DevA and DevB share an interrupt. DevB signals an interru
- Disabling and enabling external interrupts from another core is allowed.
- Multiple external interrupt sources can share an interrupt slot by passing ``ESP_INTR_FLAG_SHARED`` as a flag to :cpp:func:`esp_intr_alloc`.
Care should be taken when calling :cpp:func:`esp_intr_alloc` from a task which is not pinned to a core. During task switching, these tasks can migrate between cores. Therefore it is impossible to tell which CPU the interrupt is allocated on, which makes it difficult to free the interrupt handle and may also cause debugging difficulties. It is advised to use :cpp:func:`xTaskCreatePinnedToCore` with a specific CoreID argument to create tasks that will allocate interrupts. In the case of internal interrupt sources, this is required.
Care should be taken when calling :cpp:func:`esp_intr_alloc` from a task which is not pinned to a core. During task switching, these tasks can migrate between cores. Therefore it is impossible to tell which CPU the interrupt is allocated on, which makes it difficult to free the interrupt handle and may also cause debugging difficulties. It is advised to use :cpp:func:`xTaskCreatePinnedToCore` with a specific CoreID argument to create tasks that allocate interrupts. In the case of internal interrupt sources, this is required.
IRAM-Safe Interrupt Handlers
----------------------------
@ -98,14 +98,18 @@ Sources attached to non-shared interrupt do not support this feature.
By default, when ``ESP_INTR_FLAG_SHARED`` flag is specified, the interrupt allocator will allocate only Level 1 interrupts. Use ``ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED`` to also allow allocating shared interrupts at Level 2 and Level 3.
Though the framework supports this feature, you have to use it *very carefully*. There usually exist two ways to stop an interrupt from being triggered: *disable the source* or *mask peripheral interrupt status*. IDF only handles enabling and disabling of the source itself, leaving status and mask bits to be handled by users.
Though the framework supports this feature, you have to use it **very carefully**. There usually exist two ways to stop an interrupt from being triggered: **disable the source** or **mask peripheral interrupt status**. ESP-IDF only handles enabling and disabling of the source itself, leaving status and mask bits to be handled by users.
**Status bits shall either be masked before the handler responsible for it is disabled, either be masked and then properly handled in another enabled interrupt**.
Please note that leaving some status bits unhandled without masking them, while disabling the handlers for them, will cause the interrupt(s) to be triggered indefinitely, resulting therefore in a system crash.
.. note::
Leaving some status bits unhandled without masking them, while disabling the handlers for them, will cause the interrupt(s) to be triggered indefinitely, resulting therefore in a system crash.
Troubleshooting Interrupt Allocation
------------------------------------
On most Espressif SoCs CPU interrupts are a limited resource. Therefore it is possible to run a program which runs out of CPU interrupts, for example by initializing several peripheral drivers. Typically this will result in the driver initialization function returning ``ESP_ERR_NOT_FOUND`` error code.
On most Espressif SoCs, CPU interrupts are a limited resource. Therefore it is possible to run a program which runs out of CPU interrupts, for example by initializing several peripheral drivers. Typically, this will result in the driver initialization function returning ``ESP_ERR_NOT_FOUND`` error code.
If this happens, you can use :cpp:func:`esp_intr_dump` function to print the list of interrupts along with their status. The output of this function typically looks like this::
@ -139,7 +143,7 @@ If you have confirmed that the application is indeed running out of interrupts,
:not CONFIG_FREERTOS_UNICORE: - On multi-core SoCs, try initializing some of the peripheral drivers from a task pinned to the second core. Interrupts are typically allocated on the same core where the peripheral driver initialization function runs. Therefore by running the initialization function on the second core, more interrupt inputs can be used.
- Determine the interrupts which can tolerate higher latency, and allocate them using ``ESP_INTR_FLAG_SHARED`` flag (optionally ORed with ``ESP_INTR_FLAG_LOWMED``). Using this flag for two or more peripherals will let them use a single interrupt input, and therefore save interrupt inputs for other peripherals. See :ref:`intr-alloc-shared-interrupts` above.
:not SOC_CPU_HAS_FLEXIBLE_INTC: - Some peripheral driver may default to allocating interrupts with ``ESP_INTR_FLAG_LEVEL1`` flag, so level 2 and 3 interrupts won't get used by default. If :cpp:func:`esp_intr_dump` shows that some level 2 or 3 interrupts are available, try changing the interrupt allocation flags when initializing the driver to ``ESP_INTR_FLAG_LEVEL2`` or ``ESP_INTR_FLAG_LEVEL3``.
:not SOC_CPU_HAS_FLEXIBLE_INTC: - Some peripheral driver may default to allocating interrupts with ``ESP_INTR_FLAG_LEVEL1`` flag, so level 2 and 3 interrupts do not get used by default. If :cpp:func:`esp_intr_dump` shows that some level 2 or 3 interrupts are available, try changing the interrupt allocation flags when initializing the driver to ``ESP_INTR_FLAG_LEVEL2`` or ``ESP_INTR_FLAG_LEVEL3``.
- Check if some of the peripheral drivers do not need to be used all the time, and initialize/deinitialize them on demand. This can reduce the number of simultaneously allocated interrupts.

View File

@ -2,6 +2,7 @@ Inter-Processor Call
====================
.. note::
The IPC is an **Inter-Processor Call** and **NOT Inter-Process Communication** as found on other operating systems.
Overview
@ -23,9 +24,9 @@ The IPC feature implements callback execution in a task context by creating an I
When using IPCs in a task context, users need to consider the following:
- IPC callbacks should ideally be simple and short. **An IPC callback should avoid attempting to block or yield**.
- The IPC tasks are created at the highest possible priority (i.e., ``configMAX_PRIORITIES - 1``) thus the callback should also run at that priority as a result. However, :ref:`CONFIG_ESP_IPC_USES_CALLERS_PRIORITY` is enabled by default which will temporarily lower the priority of the target CPU's IPC task to the calling CPU before executing the callback.
- The IPC tasks are created at the highest possible priority (i.e., ``configMAX_PRIORITIES - 1``) thus the callback should also run at that priority as a result. However, :ref:`CONFIG_ESP_IPC_USES_CALLERS_PRIORITY` is enabled by default which temporarily lowers the priority of the target CPU's IPC task to the calling CPU before executing the callback.
- Depending on the complexity of the callback, users may need to configure the stack size of the IPC task via :ref:`CONFIG_ESP_IPC_TASK_STACK_SIZE`.
- The IPC feature is internally protected by a mutex. Therefore, simultaneous IPC calls from two or more calling CPUs will be handled on a first come first serve basis.
- The IPC feature is internally protected by a mutex. Therefore, simultaneous IPC calls from two or more calling CPUs are handled on a first come first serve basis.
API Usage
^^^^^^^^^
@ -38,8 +39,8 @@ Task Context IPC callbacks have the following restrictions:
The IPC feature offers the API listed below to execute a callback in a task context on a target CPU. The API allows the calling CPU to block until the callback's execution has completed, or return immediately once the callback's execution has started.
- :cpp:func:`esp_ipc_call` will trigger an IPC call on the target CPU. This function will block until the target CPU's IPC task **begins** execution of the callback.
- :cpp:func:`esp_ipc_call_blocking` will trigger an IPC on the target CPU. This function will block until the target CPU's IPC task **completes** execution of the callback.
- :cpp:func:`esp_ipc_call` triggers an IPC call on the target CPU. This function will block until the target CPU's IPC task **begins** execution of the callback.
- :cpp:func:`esp_ipc_call_blocking` triggers an IPC on the target CPU. This function will block until the target CPU's IPC task **completes** execution of the callback.
IPC in ISR Context
------------------
@ -51,6 +52,7 @@ When using IPCs in High Priority Interrupt context, users need to consider the f
- Since the callback is executed in a High Priority Interrupt context, the callback must be written entirely in assembly. See the API Usage below for more details regarding writing assembly callbacks.
- The priority of the reserved High Priority Interrupt is dependent on the :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` option
- When the callback executes:
- The calling CPU will disable interrupts of level 3 and lower
- Although the priority of the reserved interrupt depends on :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`, during the execution IPC ISR callback, the target CPU will disable interrupts of level 5 and lower regardless of what :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` is set to.
@ -65,13 +67,13 @@ High Priority Interrupt IPC callbacks have the following restrictions:
- Must not call other C functions as register windowing is disabled
- The callback should be placed in IRAM at a 4-byte aligned address
- (On invocation of/after returning from) the callback, the registers ``a2, a3, a4`` are (saved/restored) automatically thus can be used in the callback. The callback should **ONLY** use those registers.
- ``a2`` will contain the ``void *arg`` of the callback
- ``a2`` contains the ``void *arg`` of the callback
- ``a3/a4`` are free to use as scratch registers
The IPC feature offers the API listed below to execute a callback in a High Priority Interrupt context.
- :cpp:func:`esp_ipc_isr_asm_call` will trigger an IPC call on the target CPU. This function will busy-wait until the target CPU begins execution of the callback.
- :cpp:func:`esp_ipc_isr_asm_call_blocking` will trigger an IPC call on the target CPU. This function will busy-wait until the target CPU completes execution of the callback.
- :cpp:func:`esp_ipc_isr_asm_call` triggers an IPC call on the target CPU. This function will busy-wait until the target CPU begins execution of the callback.
- :cpp:func:`esp_ipc_isr_asm_call_blocking` triggers an IPC call on the target CPU. This function will busy-wait until the target CPU completes execution of the callback.
The following code-blocks demonstrates a High Priority Interrupt IPC callback written in assembly that simply reads the target CPU's cycle count.
@ -97,9 +99,11 @@ The following code-blocks demonstrates a High Priority Interrupt IPC callback wr
esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)cycle_count);
.. note::
The number of scratch registers available for use is sufficient for most simple use cases. But if your callback requires more scratch registers, ``void *arg`` can point to a buffer that is used as a register save area. The callback can then save and restore more registers. See the :example:`system/ipc/ipc_isr`.
.. note::
For more examples of High Priority Interrupt IPC callbacks, see :idf_file:`components/esp_system/port/arch/xtensa/esp_ipc_isr_routines.S` and :`components/esp_system/test/test_ipc_isr.S`
The High Priority Interrupt IPC API also provides the following convenience functions that can stall/resume the target CPU. These API utilize the High Priority Interrupt IPC, but supply their own internal callbacks:

View File

@ -3,8 +3,8 @@
Application Example
-------------------
The logging library is commonly used by most esp-idf components and examples. For demonstration of log functionality, check ESP-IDF's :idf:`examples` directory. The most relevant examples that deal with logging are the following:
The logging library is commonly used by most ESP-IDF components and examples. For demonstration of log functionality, check ESP-IDF's :idf:`examples` directory. The most relevant examples that deal with logging are the following:
* :example:`system/ota`
* :example:`storage/sd_card`
* :example:`protocols/https_request`

View File

@ -27,7 +27,7 @@ For more details on these internal memory types, see :ref:`memory-layout`.
.. only:: SOC_SPIRAM_SUPPORTED
It's also possible to connect external SPI RAM to the {IDF_TARGET_NAME}. The :doc:`external RAM </api-guides/external-ram>` is integrated into the {IDF_TARGET_NAME}'s memory map via the cache, and accessed similarly to DRAM.
It is also possible to connect external SPI RAM to the {IDF_TARGET_NAME}. The :doc:`external RAM </api-guides/external-ram>` is integrated into the {IDF_TARGET_NAME}'s memory map via the cache, and accessed similarly to DRAM.
All DRAM memory is single-byte accessible, thus all DRAM heaps possess the ``MALLOC_CAP_8BIT`` capability. Users can call ``heap_caps_get_free_size(MALLOC_CAP_8BIT)`` to get the free size of all DRAM heaps.
@ -45,15 +45,19 @@ Available Heap
DRAM
^^^^
At startup, the DRAM heap contains all data memory that is not statically allocated by the app. Reducing statically allocated buffers will increase the amount of available free heap.
At startup, the DRAM heap contains all data memory that is not statically allocated by the app. Reducing statically-allocated buffers increases the amount of available free heap.
To find the amount of statically allocated memory, use the :ref:`idf.py size <idf.py-size>` command.
.. only:: esp32
.. note:: See the :ref:`dram` section for more details about the DRAM usage limitations.
.. note::
See the :ref:`dram` section for more details about the DRAM usage limitations.
.. note:: At runtime, the available heap DRAM may be less than calculated at compile time, because, at startup, some memory is allocated from the heap before the FreeRTOS scheduler is started (including memory for the stacks of initial FreeRTOS tasks).
.. note::
At runtime, the available heap DRAM may be less than calculated at compile time, because, at startup, some memory is allocated from the heap before the FreeRTOS scheduler is started (including memory for the stacks of initial FreeRTOS tasks).
IRAM
^^^^
@ -105,13 +109,13 @@ Use the ``MALLOC_CAP_DMA`` flag to allocate memory which is suitable for use wit
32-Bit Accessible Memory
^^^^^^^^^^^^^^^^^^^^^^^^
If a certain memory structure is only addressed in 32-bit units, for example, an array of ints or pointers, it can be useful to allocate it with the ``MALLOC_CAP_32BIT`` flag. This also allows the allocator to give out IRAM memory, which is sometimes unavailable for a normal malloc() call. This can help to use all the available memory in the {IDF_TARGET_NAME}.
If a certain memory structure is only addressed in 32-bit units, for example, an array of ints or pointers, it can be useful to allocate it with the ``MALLOC_CAP_32BIT`` flag. This also allows the allocator to give out IRAM memory, which is sometimes unavailable for a normal ``malloc()`` call. This can help to use all the available memory in the {IDF_TARGET_NAME}.
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA and SOC_CPU_HAS_FPU
Please note that on {IDF_TARGET_NAME} series chips, ``MALLOC_CAP_32BIT`` cannot be used for storing floating-point variables. This is because ``MALLOC_CAP_32BIT`` may return instruction RAM and the floating-point assembly instructions on {IDF_TARGET_NAME} cannot access instruction RAM.
Memory allocated with ``MALLOC_CAP_32BIT`` can *only* be accessed via 32-bit reads and writes, any other type of access will generate a fatal LoadStoreError exception.
Memory allocated with ``MALLOC_CAP_32BIT`` can **only** be accessed via 32-bit reads and writes, any other type of access will generate a fatal LoadStoreError exception.
.. only:: SOC_SPIRAM_SUPPORTED
@ -150,7 +154,9 @@ The following functions from the heap component can be called from the interrupt
* :cpp:func:`heap_caps_aligned_alloc`
* :cpp:func:`heap_caps_aligned_free`
Note: however, this practice is strongly discouraged.
.. note::
However, this practice is strongly discouraged.
Heap Tracing & Debugging
------------------------
@ -165,7 +171,7 @@ The following features are documented on the :doc:`Heap Memory Debugging </api-r
Implementation Notes
--------------------
Knowledge about the regions of memory in the chip comes from the "SoC" component, which contains memory layout information for the chip, and the different capabilities of each region. Each region's capabilities are prioritized, so that (for example) dedicated DRAM and IRAM regions will be used for allocations ahead of the more versatile D/IRAM regions.
Knowledge about the regions of memory in the chip comes from the "SoC" component, which contains memory layout information for the chip, and the different capabilities of each region. Each region's capabilities are prioritized, so that (for example) dedicated DRAM and IRAM regions are used for allocations ahead of the more versatile D/IRAM regions.
Each contiguous region of memory contains its own memory heap. The heaps are created using the :ref:`multi_heap <multi-heap>` functionality. ``multi_heap`` allows any contiguous region of memory to be used as a heap.
@ -190,6 +196,6 @@ API Reference - Initialisation
API Reference - Multi-Heap API
------------------------------
(Note: The multi-heap API is used internally by the heap capabilities allocator. Most IDF programs will never need to call this API directly.)
(Note: The multi-heap API is used internally by the heap capabilities allocator. Most ESP-IDF programs never need to call this API directly.)
.. include-build-file:: inc/multi_heap.inc

View File

@ -1,5 +1,6 @@
Miscellaneous System APIs
=========================
:link_to_translation:`zh_CN:[中文]`
{IDF_TARGET_BASE_MAC_BLOCK: default="BLK1", esp32="BLK0"}
@ -36,7 +37,7 @@ These APIs allow querying and customizing MAC addresses for different supported
To fetch the MAC address for a specific network interface (e.g., Wi-Fi, Bluetooth, Ethernet), call the function :cpp:func:`esp_read_mac`.
In ESP-IDF, the MAC addresses for the various network interfaces are calculated from a single *base MAC address*. By default, the Espressif base MAC address is used. This base MAC address is pre-programmed into the {IDF_TARGET_NAME} eFuse in the factory during production.
In ESP-IDF, the MAC addresses for the various network interfaces are calculated from a single **base MAC address**. By default, the Espressif base MAC address is used. This base MAC address is pre-programmed into the {IDF_TARGET_NAME} eFuse in the factory during production.
.. only:: not esp32s2
@ -89,7 +90,9 @@ In ESP-IDF, the MAC addresses for the various network interfaces are calculated
.. only:: not SOC_EMAC_SUPPORTED
.. note:: Although {IDF_TARGET_NAME} has no integrated Ethernet MAC, it is still possible to calculate an Ethernet MAC address. However, this MAC address can only be used with an external ethernet interface such as an SPI-Ethernet device. See :doc:`/api-reference/network/esp_eth`.
.. note::
Although {IDF_TARGET_NAME} has no integrated Ethernet MAC, it is still possible to calculate an Ethernet MAC address. However, this MAC address can only be used with an external ethernet interface such as an SPI-Ethernet device. See :doc:`/api-reference/network/esp_eth`.
Custom Interface MAC
^^^^^^^^^^^^^^^^^^^^

View File

@ -12,7 +12,7 @@ Introduction
ESP-IDF provides a memory mapping driver that manages the relation between these physical memory addresses and virtual memory addresses, so as to achieve some features such as reading from SPI Flash via a pointer.
Memory mapping driver is actually a capabilities-based virtual memory address allocator that allows apps to make virtual memory address allocations for different purposes. In the following chapters, we call this driver `esp_mmap` driver.
Memory mapping driver is actually a capabilities-based virtual memory address allocator that allows apps to make virtual memory address allocations for different purposes. In the following chapters, we call this driver ``esp_mmap`` driver.
ESP-IDF also provides a memory synchronisation driver which can be used for potential memory desychronisation scenarios.
@ -75,10 +75,10 @@ The virtual memory pool is made up with one or multiple virtual memory regions,
- A virtual memory block is a piece of virtual address range that is dynamically mapped.
- A slot is the virtual address range between two virtual memory blocks.
- A physical memory block is a piece of physical address range that is to-be-mapped or already mapped to a virtual memory block.
- Dynamical mapping is done by calling `esp_mmap` driver API :cpp:func:`esp_mmu_map`, this API will map the given physical memory block to a virtual memory block which is allocated by the `esp_mmap` driver.
- Dynamical mapping is done by calling ``esp_mmap`` driver API :cpp:func:`esp_mmu_map`, this API will map the given physical memory block to a virtual memory block which is allocated by the ``esp_mmap`` driver.
Relation between Memory Blocks
Relation Between Memory Blocks
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When mapping a physical memory block A, block A can have one of the following relations with another previously mapped physical memory block B:
@ -91,7 +91,7 @@ When mapping a physical memory block A, block A can have one of the following re
.. image:: /../_static/diagrams/mmu/identical.png
Note `esp_mmap` driver will consider the identical scenario **the same as the enclosed scenario**.
Note ``esp_mmap`` driver considers the identical scenario **the same as the enclosed scenario**.
- Overlapped: block A is overlapped with block B, see figure below:
@ -101,7 +101,7 @@ When mapping a physical memory block A, block A can have one of the following re
.. image:: /../_static/diagrams/mmu/inversed_enclosed.png
`esp_mmap` driver will consider this scenario **the same as the overlapped scenario**.
``esp_mmap`` driver considers this scenario **the same as the overlapped scenario**.
Driver Behaviour
@ -110,29 +110,29 @@ Driver Behaviour
Memory Map
^^^^^^^^^^
You can call :cpp:func:`esp_mmu_map` to do a dynamical mapping. This API will allocate a certain size of virtual memory block according to the virtual memory capabilities you selected, then map this virtual memory block to the physical memory block as you requested. The `esp_mmap` driver supports mapping to one or more types of physical memory, so you should specify the physical memory target when mapping.
You can call :cpp:func:`esp_mmu_map` to do a dynamical mapping. This API can allocate a certain size of virtual memory block according to the virtual memory capabilities you selected, then map this virtual memory block to the physical memory block as you requested. The ``esp_mmap`` driver supports mapping to one or more types of physical memory, so you should specify the physical memory target when mapping.
By default, physical memory blocks and virtual memory blocks are one-to-one mapped. This means, when calling :cpp:func:`esp_mmu_map`:
* If it's the enclosed scenario, this API will return an :c:macro:`ESP_ERR_INVALID_STATE`. The `out_ptr` will be assigned to the start virtual memory address of the previously mapped one which encloses the to-be-mapped one.
* If it's the identical scenario, this API will behaves exactly the same as the enclosed scenario.
* If it's the overlapped scenario, this API will by default return an :c:macro:`ESP_ERR_INVALID_ARG`. This means, `esp_mmap` driver by default doesn't allow mapping a physical memory address to multiple virtual memory addresses.
* If it is the enclosed scenario, this API will return an :c:macro:`ESP_ERR_INVALID_STATE`. The ``out_ptr`` will be assigned to the start virtual memory address of the previously mapped one which encloses the to-be-mapped one.
* If it is the identical scenario, this API will behaves exactly the same as the enclosed scenario.
* If it is the overlapped scenario, this API will by default return an :c:macro:`ESP_ERR_INVALID_ARG`. This means, ``esp_mmap`` driver by default does not allow mapping a physical memory address to multiple virtual memory addresses.
Specially, you can use :c:macro:`ESP_MMU_MMAP_FLAG_PADDR_SHARED`. This flags stands for one-to-multiple mapping between a physical address and multiple virtual addresses:
* If it's the overlapped scenario, this API will allocate a new virtual memory block as requested, then map to the given physical memory block.
* If it is the overlapped scenario, this API will allocate a new virtual memory block as requested, then map to the given physical memory block.
Memory Unmap
^^^^^^^^^^^^
You can call :cpp:func:`esp_mmu_unmap` to unmap a previously mapped memory block. This API will return an :c:macro:`ESP_ERR_NOT_FOUND` if you are trying to unmap a virtual memory block that isn't mapped to any physical memory block yet.
You can call :cpp:func:`esp_mmu_unmap` to unmap a previously mapped memory block. This API returns an :c:macro:`ESP_ERR_NOT_FOUND` if you are trying to unmap a virtual memory block that is not mapped to any physical memory block yet.
Memory Address Conversion
^^^^^^^^^^^^^^^^^^^^^^^^^
The `esp_mmap` driver provides two helper APIs to do the conversion between virtual memory address and physical memory address.
The ``esp_mmap`` driver provides two helper APIs to do the conversion between virtual memory address and physical memory address.
* :cpp:func:`esp_mmu_vaddr_to_paddr`, convert virtual address to physical address.
* :cpp:func:`esp_mmu_paddr_to_vaddr`, convert physical address to virtual address.
@ -143,7 +143,7 @@ Memory Synchronisation
MMU supported physical memories can be accessed by one or multiple methods.
SPI Flash can be accessed by SPI1 (ESP-IDF `esp_flash` driver APIs), or by pointers. ESP-IDF `esp_flash` driver APIs have already considered the memory synchronisation, so users don't need to worry about this.
SPI Flash can be accessed by SPI1 (ESP-IDF ``esp_flash`` driver APIs), or by pointers. ESP-IDF ``esp_flash`` driver APIs have already considered the memory synchronisation, so users do not need to worry about this.
.. only:: SOC_SPIRAM_SUPPORTED
@ -155,16 +155,16 @@ SPI Flash can be accessed by SPI1 (ESP-IDF `esp_flash` driver APIs), or by point
:cpp:func:`esp_cache_msync` has two synchronization directions,
* c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_C2M`: from cache to memory. By default (if you don't specify a direction), the synchronization is in this direction. Content in the address you specified will be written back to the memory.
* c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_M2C`: from memory to cache. By default, content in the address you specified will be invalidated from the cache.
* :c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_C2M`: from cache to memory. By default (if you do not specify a direction), the synchronization is in this direction. Content in the address you specified is written back to the memory.
* :c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_M2C`: from memory to cache. By default, content in the address you specified is invalidated from the cache.
Thread Safety
=============
APIs in `esp_mmu_map.h` are not guaranteed to be thread-safe.
APIs in ``esp_mmu_map.h`` are not guaranteed to be thread-safe.
APIs in `esp_cache.h` are guaranteed to be thread-safe.
APIs in ``esp_cache.h`` are guaranteed to be thread-safe.
API Reference

View File

@ -1,5 +1,6 @@
Over The Air Updates (OTA)
==========================
:link_to_translation:`zh_CN:[中文]`
OTA Process Overview
@ -7,7 +8,7 @@ OTA Process Overview
The OTA update mechanism allows a device to update itself based on data received while the normal firmware is running (for example, over Wi-Fi or Bluetooth.)
OTA requires configuring the :doc:`Partition Table <../../api-guides/partition-tables>` of the device with at least two "OTA app slot" partitions (i.e. `ota_0` and `ota_1`) and an "OTA Data Partition".
OTA requires configuring the :doc:`Partition Table <../../api-guides/partition-tables>` of the device with at least two OTA app slot partitions (i.e., ``ota_0`` and ``ota_1``) and an OTA Data Partition.
The OTA operation functions write a new app firmware image to whichever OTA app slot that is currently not selected for booting. Once the image is verified, the OTA Data partition is updated to specify that this image should be used for the next boot.
@ -18,7 +19,7 @@ OTA Data Partition
An OTA data partition (type ``data``, subtype ``ota``) must be included in the :doc:`Partition Table <../../api-guides/partition-tables>` of any project which uses the OTA functions.
For factory boot settings, the OTA data partition should contain no data (all bytes erased to 0xFF). In this case the esp-idf software bootloader will boot the factory app if it is present in the partition table. If no factory app is included in the partition table, the first available OTA slot (usually ``ota_0``) is booted.
For factory boot settings, the OTA data partition should contain no data (all bytes erased to 0xFF). In this case, the ESP-IDF software bootloader will boot the factory app if it is present in the partition table. If no factory app is included in the partition table, the first available OTA slot (usually ``ota_0``) is booted.
After the first OTA update, the OTA data partition is updated to specify which OTA app slot partition should be booted next.
@ -26,7 +27,7 @@ The OTA data partition is two flash sectors (0x2000 bytes) in size, to prevent p
.. _app_rollback:
App rollback
App Rollback
------------
The main purpose of the application rollback is to keep the device working after the update. This feature allows you to roll back to the previous working application in case a new application has critical errors. When the rollback process is enabled and an OTA update provides a new version of the app, one of three things can happen:
@ -35,7 +36,9 @@ The main purpose of the application rollback is to keep the device working after
* The application has critical errors and further work is not possible, a rollback to the previous application is required, :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot` marks the running application with the state ``ESP_OTA_IMG_INVALID`` and reset. This application will not be selected by the bootloader for boot and will boot the previously working application.
* If the :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` option is set, and a reset occurs without calling either function then the application is rolled back.
.. note:: The state is not written to the binary image of the application but rather to the ``otadata`` partition. The partition contains a ``ota_seq`` counter which is a pointer to the slot (ota_0, ota_1, ...) from which the application will be selected for boot.
.. note::
The state is not written to the binary image of the application but rather to the ``otadata`` partition. The partition contains a ``ota_seq`` counter, which is a pointer to the slot (``ota_0``, ``ota_1``, ...) from which the application will be selected for boot.
App OTA State
^^^^^^^^^^^^^
@ -71,11 +74,11 @@ The description of the rollback process when :ref:`CONFIG_BOOTLOADER_APP_ROLLBAC
* Reboot :cpp:func:`esp_restart`.
* The bootloader checks for the ``ESP_OTA_IMG_PENDING_VERIFY`` state if it is set, then it will be written to ``ESP_OTA_IMG_ABORTED``.
* The bootloader selects a new application to boot so that the state is not set as ``ESP_OTA_IMG_INVALID`` or ``ESP_OTA_IMG_ABORTED``.
* The bootloader checks the selected application for ``ESP_OTA_IMG_NEW`` state if it is set, then it will be written to ``ESP_OTA_IMG_PENDING_VERIFY``. This state means that the application requires confirmation of its operability, if this does not happen and a reboot occurs, this state will be overwritten to ``ESP_OTA_IMG_ABORTED`` (see above) and this application will no longer be able to start, i.e. there will be a rollback to the previous working application.
* The bootloader checks the selected application for ``ESP_OTA_IMG_NEW`` state if it is set, then it will be written to ``ESP_OTA_IMG_PENDING_VERIFY``. This state means that the application requires confirmation of its operability, if this does not happen and a reboot occurs, this state will be overwritten to ``ESP_OTA_IMG_ABORTED`` (see above) and this application will no longer be able to start, i.e., there will be a rollback to the previous working application.
* A new application has started and should make a self-test.
* If the self-test has completed successfully, then you must call the function :cpp:func:`esp_ota_mark_app_valid_cancel_rollback` because the application is awaiting confirmation of operability (``ESP_OTA_IMG_PENDING_VERIFY`` state).
* If the self-test fails then call :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot` function to roll back to the previous working application, while the invalid application is set ``ESP_OTA_IMG_INVALID`` state.
* If the application has not been confirmed, the state remains ``ESP_OTA_IMG_PENDING_VERIFY``, and the next boot it will be changed to ``ESP_OTA_IMG_ABORTED``. That will prevent re-boot of this application. There will be a rollback to the previous working application.
* If the self-test fails, then call :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot` function to roll back to the previous working application, while the invalid application is set ``ESP_OTA_IMG_INVALID`` state.
* If the application has not been confirmed, the state remains ``ESP_OTA_IMG_PENDING_VERIFY``, and the next boot it will be changed to ``ESP_OTA_IMG_ABORTED``, which prevents re-boot of this application. There will be a rollback to the previous working application.
Unexpected Reset
^^^^^^^^^^^^^^^^
@ -86,7 +89,7 @@ Recommendation: Perform the self-test procedure as quickly as possible, to preve
Only ``OTA`` partitions can be rolled back. Factory partition is not rolled back.
Booting invalid/aborted apps
Booting Invalid/aborted Apps
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Booting an application which was previously set to ``ESP_OTA_IMG_INVALID`` or ``ESP_OTA_IMG_ABORTED`` is possible:
@ -97,7 +100,7 @@ Booting an application which was previously set to ``ESP_OTA_IMG_INVALID`` or ``
To determine if self-tests should be run during startup of an application, call the :cpp:func:`esp_ota_get_state_partition` function. If result is ``ESP_OTA_IMG_PENDING_VERIFY`` then self-testing and subsequent confirmation of operability is required.
Where the states are set
Where the States Are Set
^^^^^^^^^^^^^^^^^^^^^^^^
A brief description of where the states are set:
@ -121,7 +124,7 @@ This function works if set :ref:`CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK` option. In
:ref:`CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK` and :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` options are used together. In this case, rollback is possible only on the security version which is equal or higher than the version in the chip.
A typical anti-rollback scheme is
A Typical Anti-rollback Scheme Is
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- New firmware released with the elimination of vulnerabilities with the previous version of security.
@ -185,7 +188,7 @@ Restrictions:
.. _secure-ota-updates:
Secure OTA Updates Without Secure boot
Secure OTA Updates Without Secure Boot
--------------------------------------
The verification of signed OTA updates can be performed even without enabling hardware secure boot. This can be achieved by setting :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT` and :ref:`CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT`
@ -195,10 +198,10 @@ The verification of signed OTA updates can be performed even without enabling ha
For more information refer to :ref:`signed-app-verify`
OTA Tool (otatool.py)
---------------------
OTA Tool ``otatool.py``
-----------------------
The component `app_update` provides a tool :component_file:`otatool.py<app_update/otatool.py>` for performing OTA partition-related operations on a target device. The following operations can be performed using the tool:
The component ``app_update`` provides a tool :component_file:`otatool.py<app_update/otatool.py>` for performing OTA partition-related operations on a target device. The following operations can be performed using the tool:
- read contents of otadata partition (read_otadata)
- erase otadata partition, effectively resetting device to factory app (erase_otadata)
@ -212,7 +215,7 @@ The tool can either be imported and used from another Python script or invoked f
Python API
^^^^^^^^^^
Before anything else, make sure that the `otatool` module is imported.
Before anything else, make sure that the ``otatool`` module is imported.
.. code-block:: python
@ -225,7 +228,7 @@ Before anything else, make sure that the `otatool` module is imported.
sys.path.append(otatool_dir) # this enables Python to find otatool module
from otatool import * # import all names inside otatool module
The starting point for using the tool's Python API to do is create a `OtatoolTarget` object:
The starting point for using the tool's Python API to do is create a ``OtatoolTarget`` object:
.. code-block:: python
@ -255,7 +258,7 @@ More information on the Python API is available in the docstrings for the tool.
Command-line Interface
^^^^^^^^^^^^^^^^^^^^^^
The command-line interface of `otatool.py` has the following structure:
The command-line interface of ``otatool.py`` has the following structure:
.. code-block:: bash
@ -280,7 +283,7 @@ The command-line interface of `otatool.py` has the following structure:
otatool.py --port "/dev/ttyUSB1" read_ota_partition --name=ota_3 --output=ota_3.bin
More information can be obtained by specifying `--help` as argument:
More information can be obtained by specifying ``--help`` as argument:
.. code-block:: bash
@ -291,7 +294,7 @@ More information can be obtained by specifying `--help` as argument:
otatool.py [subcommand] --help
See also
See Also
--------
* :doc:`Partition Table documentation <../../api-guides/partition-tables>`

View File

@ -7,9 +7,10 @@ Application Example
-------------------
An example which combines performance monitor is provided in ``examples/system/perfmon`` directory.
This example initializes the performance monitor structure and execute them with printing the statistics.
High level API Reference
High-Level API Reference
------------------------
Header Files

View File

@ -6,7 +6,7 @@ Power Management
Overview
--------
Power management algorithm included in ESP-IDF can adjust the advanced peripheral bus (APB) frequency, CPU frequency, and put the chip into light sleep mode to run an application at smallest possible power consumption, given the requirements of application components.
Power management algorithm included in ESP-IDF can adjust the advanced peripheral bus (APB) frequency, CPU frequency, and put the chip into Light-sleep mode to run an application at smallest possible power consumption, given the requirements of application components.
Application components can express their requirements by creating and acquiring power management locks.
@ -14,9 +14,9 @@ For example:
- Driver for a peripheral clocked from APB can request the APB frequency to be set to 80 MHz while the peripheral is used.
- RTOS can request the CPU to run at the highest configured frequency while there are tasks ready to run.
- A peripheral driver may need interrupts to be enabled, which means it will have to request disabling light sleep.
- A peripheral driver may need interrupts to be enabled, which means it has to request disabling Light-sleep.
Since requesting higher APB or CPU frequencies or disabling light sleep causes higher current consumption, please keep the usage of power management locks by components to a minimum.
Since requesting higher APB or CPU frequencies or disabling Light-sleep causes higher current consumption, please keep the usage of power management locks by components to a minimum.
Configuration
-------------
@ -25,22 +25,22 @@ Power management can be enabled at compile time, using the option :ref:`CONFIG_P
Enabling power management features comes at the cost of increased interrupt latency. Extra latency depends on a number of factors, such as the CPU frequency, single/dual core mode, whether or not frequency switch needs to be done. Minimum extra latency is 0.2 us (when the CPU frequency is 240 MHz and frequency scaling is not enabled). Maximum extra latency is 40 us (when frequency scaling is enabled, and a switch from 40 MHz to 80 MHz is performed on interrupt entry).
Dynamic frequency scaling (DFS) and automatic light sleep can be enabled in an application by calling the function :cpp:func:`esp_pm_configure`. Its argument is a structure defining the frequency scaling settings, :cpp:class:`esp_pm_config_t`. In this structure, three fields need to be initialized:
Dynamic frequency scaling (DFS) and automatic Light-sleep can be enabled in an application by calling the function :cpp:func:`esp_pm_configure`. Its argument is a structure defining the frequency scaling settings, :cpp:class:`esp_pm_config_t`. In this structure, three fields need to be initialized:
- ``max_freq_mhz``: Maximum CPU frequency in MHz, i.e., the frequency used when the ``ESP_PM_CPU_FREQ_MAX`` lock is acquired. This field will usually be set to the default CPU frequency.
- ``max_freq_mhz``: Maximum CPU frequency in MHz, i.e., the frequency used when the ``ESP_PM_CPU_FREQ_MAX`` lock is acquired. This field is usually set to the default CPU frequency.
- ``min_freq_mhz``: Minimum CPU frequency in MHz, i.e., the frequency used when only the ``ESP_PM_APB_FREQ_MAX`` lock is acquired. This field can be set to the XTAL frequency value, or the XTAL frequency divided by an integer. Note that 10 MHz is the lowest frequency at which the default REF_TICK clock of 1 MHz can be generated.
- ``light_sleep_enable``: Whether the system should automatically enter light sleep when no locks are acquired (``true``/``false``).
- ``light_sleep_enable``: Whether the system should automatically enter Light-sleep when no locks are acquired (``true``/``false``).
Alternatively, if you enable the option :ref:`CONFIG_PM_DFS_INIT_AUTO` in menuconfig, the maximum CPU frequency will be determined by the :ref:`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ` setting, and the minimum CPU frequency will be locked to the XTAL frequency.
.. note::
Automatic light sleep is based on FreeRTOS Tickless Idle functionality. If automatic light sleep is requested while the option :ref:`CONFIG_FREERTOS_USE_TICKLESS_IDLE` is not enabled in menuconfig, :cpp:func:`esp_pm_configure` will return the error `ESP_ERR_NOT_SUPPORTED`.
Automatic Light-sleep is based on FreeRTOS Tickless Idle functionality. If automatic Light-sleep is requested while the option :ref:`CONFIG_FREERTOS_USE_TICKLESS_IDLE` is not enabled in menuconfig, :cpp:func:`esp_pm_configure` will return the error `ESP_ERR_NOT_SUPPORTED`.
.. note::
In light sleep, peripherals are clock gated, and interrupts (from GPIOs and internal peripherals) will not be generated. A wakeup source described in the :doc:`sleep_modes` documentation can be used to trigger wakeup from the light sleep state.
In Light-sleep, peripherals are clock gated, and interrupts (from GPIOs and internal peripherals) will not be generated. A wakeup source described in the :doc:`sleep_modes` documentation can be used to trigger wakeup from the Light-sleep state.
.. only:: SOC_PM_SUPPORT_EXT0_WAKEUP or SOC_PM_SUPPORT_EXT1_WAKEUP
@ -64,11 +64,11 @@ Power management locks have acquire/release counters. If the lock has been acqui
* - Lock
- Description
* - ``ESP_PM_CPU_FREQ_MAX``
- Requests CPU frequency to be at the maximum value set with :cpp:func:`esp_pm_configure`. For {IDF_TARGET_NAME}, this value can be set to {IDF_TARGET_MAX_CPU_FREQ}.
- Requests CPU frequency to be at the maximum value set with :cpp:func:`esp_pm_configure`. For {IDF_TARGET_NAME}, this value can be set to {IDF_TARGET_MAX_CPU_FREQ}.
* - ``ESP_PM_APB_FREQ_MAX``
- Requests the APB frequency to be at the maximum supported value. For {IDF_TARGET_NAME}, this is 80 MHz.
* - ``ESP_PM_NO_LIGHT_SLEEP``
- Disables automatic switching to light sleep.
- Disables automatic switching to Light-sleep.
{IDF_TARGET_NAME} Power Management Algorithm
---------------------------------------
@ -77,37 +77,37 @@ The table below shows how CPU and APB frequencies will be switched if dynamic fr
.. include:: inc/power_management_{IDF_TARGET_PATH_NAME}.rst
If none of the locks are acquired, and light sleep is enabled in a call to :cpp:func:`esp_pm_configure`, the system will go into light sleep mode. The duration of light sleep will be determined by:
If none of the locks are acquired, and Light-sleep is enabled in a call to :cpp:func:`esp_pm_configure`, the system will go into Light-sleep mode. The duration of Light-sleep will be determined by:
- FreeRTOS tasks blocked with finite timeouts
- Timers registered with :doc:`High resolution timer <esp_timer>` APIs
Light sleep duration will be chosen to wake up the chip before the nearest event (task being unblocked, or timer elapses).
Light-sleep duration is chosen to wake up the chip before the nearest event (task being unblocked, or timer elapses).
To skip unnecessary wake-up, you can consider initializing an esp_timer with the `skip_unhandled_events` option as true. Timers with this flag will not wake up the system and it helps to reduce consumption.
To skip unnecessary wake-up, you can consider initializing an ``esp_timer`` with the ``skip_unhandled_events`` option as ``true``. Timers with this flag will not wake up the system and it helps to reduce consumption.
Dynamic Frequency Scaling and Peripheral Drivers
------------------------------------------------
When DFS is enabled, the APB frequency can be changed multiple times within a single RTOS tick. The APB frequency change does not affect the operation of some peripherals, while other peripherals may have issues. For example, Timer Group peripheral timers will keep counting, however, the speed at which they count will change proportionally to the APB frequency.
When DFS is enabled, the APB frequency can be changed multiple times within a single RTOS tick. The APB frequency change does not affect the operation of some peripherals, while other peripherals may have issues. For example, Timer Group peripheral timers keeps counting, however, the speed at which they count changes proportionally to the APB frequency.
The following peripherals work normally even when the APB frequency is changing:
- **UART**: if REF_TICK or XTAL is used as a clock source. See :cpp:member:`uart_config_t::source_clk`.
- **LEDC**: if REF_TICK is used as a clock source. See :cpp:func:`ledc_timer_config` function.
- **RMT**: if REF_TICK or XTAL is used as a clock source. See :cpp:member:`rmt_config_t::flags` and macro `RMT_CHANNEL_FLAGS_AWARE_DFS`.
- **UART**: if ``REF_TICK`` or XTAL is used as a clock source. See :cpp:member:`uart_config_t::source_clk`.
- **LEDC**: if ``REF_TICK`` is used as a clock source. See :cpp:func:`ledc_timer_config` function.
- **RMT**: if ``REF_TICK`` or XTAL is used as a clock source. See :cpp:member:`rmt_config_t::flags` and macro `RMT_CHANNEL_FLAGS_AWARE_DFS`.
- **GPTimer**: if APB is used as the clock source. See :cpp:member:`gptimer_config_t::clk_src`.
- **TSENS**: XTAL or RTC_8M is used as a clock source. So, APB frequency changing will not influence it.
- **TSENS**: if XTAL or ``RTC_8M`` is used as a clock source. So, APB frequency changing will not influence it.
Currently, the following peripheral drivers are aware of DFS and will use the ``ESP_PM_APB_FREQ_MAX`` lock for the duration of the transaction:
Currently, the following peripheral drivers are aware of DFS and use the ``ESP_PM_APB_FREQ_MAX`` lock for the duration of the transaction:
- SPI master
- I2C
- I2S (If the APLL clock is used, then it will use the ``ESP_PM_NO_LIGHT_SLEEP`` lock)
- SDMMC
The following drivers will hold the ``ESP_PM_APB_FREQ_MAX`` lock while the driver is enabled:
The following drivers hold the ``ESP_PM_APB_FREQ_MAX`` lock while the driver is enabled:
.. list::
@ -115,8 +115,8 @@ The following drivers will hold the ``ESP_PM_APB_FREQ_MAX`` lock while the drive
- **Ethernet**: between calls to :cpp:func:`esp_eth_driver_install` and :cpp:func:`esp_eth_driver_uninstall`.
- **WiFi**: between calls to :cpp:func:`esp_wifi_start` and :cpp:func:`esp_wifi_stop`. If modem sleep is enabled, the lock will be released for the periods of time when radio is disabled.
:SOC_TWAI_SUPPORTED: - **TWAI**: between calls to :cpp:func:`twai_driver_install` and :cpp:func:`twai_driver_uninstall` (only when the clock source is set to :cpp:enumerator:`TWAI_CLK_SRC_APB`).
:SOC_BT_SUPPORTED and esp32: - **Bluetooth**: between calls to :cpp:func:`esp_bt_controller_enable` and :cpp:func:`esp_bt_controller_disable`. If Bluetooth modem sleep is enabled, the ``ESP_PM_APB_FREQ_MAX`` lock will be released for the periods of time when radio is disabled. However the ``ESP_PM_NO_LIGHT_SLEEP`` lock will still be held, unless :ref:`CONFIG_BTDM_CTRL_LOW_POWER_CLOCK` option is set to "External 32kHz crystal".
:SOC_BT_SUPPORTED and not esp32: - **Bluetooth**: between calls to :cpp:func:`esp_bt_controller_enable` and :cpp:func:`esp_bt_controller_disable`. If Bluetooth modem sleep is enabled, the ``ESP_PM_APB_FREQ_MAX`` lock will be released for the periods of time when radio is disabled. However the ``ESP_PM_NO_LIGHT_SLEEP`` lock will still be held.
:SOC_BT_SUPPORTED and esp32: - **Bluetooth**: between calls to :cpp:func:`esp_bt_controller_enable` and :cpp:func:`esp_bt_controller_disable`. If Bluetooth Modem-sleep is enabled, the ``ESP_PM_APB_FREQ_MAX`` lock will be released for the periods of time when radio is disabled. However the ``ESP_PM_NO_LIGHT_SLEEP`` lock will still be held, unless :ref:`CONFIG_BTDM_CTRL_LOW_POWER_CLOCK` option is set to "External 32kHz crystal".
:SOC_BT_SUPPORTED and not esp32: - **Bluetooth**: between calls to :cpp:func:`esp_bt_controller_enable` and :cpp:func:`esp_bt_controller_disable`. If Bluetooth Modem-sleep is enabled, the ``ESP_PM_APB_FREQ_MAX`` lock will be released for the periods of time when radio is disabled. However the ``ESP_PM_NO_LIGHT_SLEEP`` lock will still be held.
The following peripheral drivers are not aware of DFS yet. Applications need to acquire/release locks themselves, when necessary:
@ -135,9 +135,9 @@ Light-sleep Peripheral Power Down
{IDF_TARGET_NAME} supports power-down peripherals during Light-sleep.
If :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP` is enabled, when the driver initializes the peripheral, the driver will register the working register context of the peripheral to the sleep retention link. Before entering sleep, the REG_DMA peripheral will read the configuration in the sleep retention link, and back up the register context to memory according to the configuration. REG_DMA will also restore context from memory to peripheral registers on wakeup.
If :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP` is enabled, when the driver initializes the peripheral, the driver will register the working register context of the peripheral to the sleep retention link. Before entering sleep, the ``REG_DMA`` peripheral reads the configuration in the sleep retention link, and back up the register context to memory according to the configuration. ``REG_DMA`` also restores context from memory to peripheral registers on wakeup.
Currently IDF supports Light-sleep context retention for the following peripherals:
Currently ESP-IDF supports Light-sleep context retention for the following peripherals:
- INT_MTX
- TEE/APM
- IO_MUX / GPIO
@ -167,7 +167,7 @@ Light-sleep Peripheral Power Down
- PARL_IO
- UART1
For peripherals that do not support Light-sleep context retention, if the Power management is enabled, the `ESP_PM_NO_LIGHT_SLEEP` lock should be held when the peripheral is working to avoid losing the working context of the peripheral when entering sleep.
For peripherals that do not support Light-sleep context retention, if the Power management is enabled, the ``ESP_PM_NO_LIGHT_SLEEP`` lock should be held when the peripheral is working to avoid losing the working context of the peripheral when entering sleep.
API Reference

View File

@ -23,7 +23,7 @@ Unlike many operating systems using POSIX Threads, ESP-IDF is a real-time operat
By default, all POSIX Threads have the same RTOS priority, but it is possible to change this by calling a :ref:`custom API <esp-pthread>`.
Standard features
Standard Features
-----------------
The following standard APIs are implemented in ESP-IDF.
@ -51,7 +51,7 @@ Thread Attributes
* ``pthread_attr_init()``
* ``pthread_attr_destroy()``
- This function doesn't need to free any resources and instead resets the ``attr`` structure to defaults (implementation is same as ``pthread_attr_init()``).
- This function does not need to free any resources and instead resets the ``attr`` structure to defaults (implementation is same as ``pthread_attr_init()``).
* ``pthread_attr_getstacksize()`` / ``pthread_attr_setstacksize()``
* ``pthread_attr_getdetachstate()`` / ``pthread_attr_setdetachstate()``
@ -62,7 +62,9 @@ Once
Static initializer constant ``PTHREAD_ONCE_INIT`` is supported.
.. note:: This function can be called from tasks created using either pthread or FreeRTOS APIs
.. note::
This function can be called from tasks created using either pthread or FreeRTOS APIs
Mutexes
^^^^^^^
@ -81,7 +83,9 @@ POSIX Mutexes are implemented as FreeRTOS Mutex Semaphores (normal type for "fas
Static initializer constant ``PTHREAD_MUTEX_INITIALIZER`` is supported, but the non-standard static initializer constants for other mutex types are not supported.
.. note:: These functions can be called from tasks created using either pthread or FreeRTOS APIs
.. note::
These functions can be called from tasks created using either pthread or FreeRTOS APIs
Condition Variables
^^^^^^^^^^^^^^^^^^^
@ -98,12 +102,14 @@ Static initializer constant ``PTHREAD_COND_INITIALIZER`` is supported.
* The resolution of ``pthread_cond_timedwait()`` timeouts is the RTOS tick period (see :ref:`CONFIG_FREERTOS_HZ`). Timeouts may be delayed up to one tick period after the requested timeout.
.. note:: These functions can be called from tasks created using either pthread or FreeRTOS APIs
.. note::
These functions can be called from tasks created using either pthread or FreeRTOS APIs
Semaphores
^^^^^^^^^^
In IDF, POSIX *unnamed* semaphores are implemented. The accessible API is described below. It implements `semaphores as specified in the POSIX standard <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/semaphore.h.html>`_, unless specified otherwise.
In ESP-IDF, POSIX **unnamed** semaphores are implemented. The accessible API is described below. It implements `semaphores as specified in the POSIX standard <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/semaphore.h.html>`_, unless specified otherwise.
* `sem_init() <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_init.html>`_
* `sem_destroy() <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_destroy.html>`_
@ -112,14 +118,14 @@ In IDF, POSIX *unnamed* semaphores are implemented. The accessible API is descri
* `sem_post() <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_post.html>`_
- If the semaphore has a value of ``SEM_VALUE_MAX`` already, -1 is returned and ``errno`` is set to ``EAGAIN``.
- If the semaphore has a value of ``SEM_VALUE_MAX`` already, ``-1`` is returned and ``errno`` is set to ``EAGAIN``.
* `sem_wait() <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_wait.html>`_
* `sem_trywait() <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_trywait.html>`_
* `sem_timedwait() <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_timedwait.html>`_
- The time value passed by abstime will be rounded up to the next FreeRTOS tick.
- The actual timeout will happen after the tick the time was rounded to and before the following tick.
- The actual timeout happens after the tick the time was rounded to and before the following tick.
- It is possible, though unlikely, that the task is preempted directly after the timeout calculation, delaying the timeout of the following blocking operating system call by the duration of the preemption.
* `sem_getvalue() <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_getvalue.html>`_
@ -151,9 +157,13 @@ Thread-Specific Data
* ``pthread_key_delete()``
* ``pthread_setspecific()`` / ``pthread_getspecific()``
.. note:: These functions can be called from tasks created using either pthread or FreeRTOS APIs. When calling these functions from tasks created using FreeRTOS APIs, :ref:`CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS` config option must be enabled to ensure the thread-specific data is cleaned up before the task is deleted.
.. note::
These functions can be called from tasks created using either pthread or FreeRTOS APIs. When calling these functions from tasks created using FreeRTOS APIs, :ref:`CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS` config option must be enabled to ensure the thread-specific data is cleaned up before the task is deleted.
.. note:: There are other options for thread local storage in ESP-IDF, including options with higher performance. See :doc:`/api-guides/thread-local-storage`.
.. note::
There are other options for thread local storage in ESP-IDF, including options with higher performance. See :doc:`/api-guides/thread-local-storage`.
Not Implemented
---------------
@ -170,7 +180,7 @@ Other POSIX Threads functions (not listed here) are not implemented and will pro
ESP-IDF Extensions
------------------
The API :cpp:func:`esp_pthread_set_cfg` defined in the ``esp_pthreads.h`` header offers custom extensions to control how subsequent calls to ``pthread_create()`` will behave. Currently, the following configuration can be set:
The API :cpp:func:`esp_pthread_set_cfg` defined in the ``esp_pthreads.h`` header offers custom extensions to control how subsequent calls to ``pthread_create()`` behaves. Currently, the following configuration can be set:
.. list::
- Default stack size of new threads, if not specified when calling ``pthread_create()`` (overrides :ref:`CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT`).

View File

@ -9,11 +9,11 @@ Random Number Generation
The hardware RNG produces true random numbers under any of the following conditions:
- RF subsystem is enabled (i.e. {IDF_TARGET_RF_NAME} {IDF_TARGET_RF_IS} enabled).
- RF subsystem is enabled (i.e., {IDF_TARGET_RF_NAME} {IDF_TARGET_RF_IS} enabled).
- An internal entropy source has been enabled by calling :cpp:func:`bootloader_random_enable` and not yet disabled by calling :cpp:func:`bootloader_random_disable`.
- While the ESP-IDF :ref:`second-stage-bootloader` is running. This is because the default ESP-IDF bootloader implementation calls :cpp:func:`bootloader_random_enable` when the bootloader starts, and :cpp:func:`bootloader_random_disable` before executing the app.
When any of these conditions are true, samples of physical noise are continuously mixed into the internal hardware RNG state to provide entropy. Consult the *{IDF_TARGET_NAME} Technical Reference Manual* > *Random Number Generator (RNG)* [`PDF <{IDF_TARGET_TRM_EN_URL}#rng>`__] chapter for more details.
When any of these conditions are true, samples of physical noise are continuously mixed into the internal hardware RNG state to provide entropy. Consult the **{IDF_TARGET_NAME} Technical Reference Manual** > **Random Number Generator (RNG)** [`PDF <{IDF_TARGET_TRM_EN_URL}#rng>`__] chapter for more details.
If none of the above conditions are true, the output of the RNG should be considered pseudo-random only.
@ -26,7 +26,7 @@ To re-enable the entropy source temporarily during app startup, or for an applic
.. note::
The entropy source enabled during the boot process by the ESP-IDF Second Stage Bootloader will seed the internal RNG state with some entropy. However, the internal hardware RNG state is not large enough to provide a continuous stream of true random numbers. This is why a continuous entropy source must be enabled whenever true random numbers are required.
The entropy source enabled during the boot process by the ESP-IDF Second Stage Bootloader seeds the internal RNG state with some entropy. However, the internal hardware RNG state is not large enough to provide a continuous stream of true random numbers. This is why a continuous entropy source must be enabled whenever true random numbers are required.
.. note::
@ -37,7 +37,7 @@ To re-enable the entropy source temporarily during app startup, or for an applic
Secondary Entropy
-----------------
{IDF_TARGET_NAME} RNG contains a secondary entropy source, based on sampling an asynchronous 8MHz internal oscillator (see the Technical Reference Manual for details). This entropy source is always enabled in ESP-IDF and continuously mixed into the RNG state by hardware. In testing, this secondary entropy source was sufficient to pass the `Dieharder`_ random number test suite without the main entropy source enabled (test input was created by concatenating short samples from a continuously resetting {IDF_TARGET_NAME}). However, it is currently only guaranteed that true random numbers will be produced when the main entropy source is also enabled as described above.
{IDF_TARGET_NAME} RNG contains a secondary entropy source, based on sampling an asynchronous 8MHz internal oscillator (see the Technical Reference Manual for details). This entropy source is always enabled in ESP-IDF and continuously mixed into the RNG state by hardware. In testing, this secondary entropy source was sufficient to pass the `Dieharder`_ random number test suite without the main entropy source enabled (test input was created by concatenating short samples from a continuously resetting {IDF_TARGET_NAME}). However, it is currently only guaranteed that true random numbers are produced when the main entropy source is also enabled as described above.
API Reference
-------------
@ -45,7 +45,7 @@ API Reference
.. include-build-file:: inc/esp_random.inc
.. include-build-file:: inc/bootloader_random.inc
getrandom
Getrandom
---------
A compatible version of the Linux ``getrandom()`` function is also provided for ease of porting:

View File

@ -1,5 +1,6 @@
Sleep Modes
===========
:link_to_translation:`zh_CN:[中文]`
{IDF_TARGET_SPI_POWER_DOMAIN:default="VDD_SPI", esp32="VDD_SDIO"}
@ -36,16 +37,16 @@ In Deep-sleep mode, the CPUs, most of the RAM, and all digital peripherals that
Wi-Fi/Bluetooth and Sleep Modes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In Deep-sleep and Light-sleep modes, the wireless peripherals are powered down. Before entering Deep-sleep or Light-sleep modes, the application must disable Wi-Fi and Bluetooth using the appropriate calls (i.e., :cpp:func:`esp_bluedroid_disable`, :cpp:func:`esp_bt_controller_disable`, :cpp:func:`esp_wifi_stop`). Wi-Fi and Bluetooth connections will not be maintained in Deep-sleep or Light-sleep mode, even if these functions are not called.
In Deep-sleep and Light-sleep modes, the wireless peripherals are powered down. Before entering Deep-sleep or Light-sleep modes, the application must disable Wi-Fi and Bluetooth using the appropriate calls (i.e., :cpp:func:`esp_bluedroid_disable`, :cpp:func:`esp_bt_controller_disable`, :cpp:func:`esp_wifi_stop`). Wi-Fi and Bluetooth connections are not maintained in Deep-sleep or Light-sleep mode, even if these functions are not called.
If Wi-Fi/Bluetooth connections need to be maintained, enable Wi-Fi/Bluetooth Modem-sleep mode and automatic Light-sleep feature (see :doc:`Power Management APIs <power_management>`). This will allow the system to wake up from sleep automatically when required by the Wi-Fi/Bluetooth driver, thereby maintaining the connection.
If Wi-Fi/Bluetooth connections need to be maintained, enable Wi-Fi/Bluetooth Modem-sleep mode and automatic Light-sleep feature (see :doc:`Power Management APIs <power_management>`). This allows the system to wake up from sleep automatically when required by the Wi-Fi/Bluetooth driver, thereby maintaining the connection.
.. only:: not SOC_BT_SUPPORTED
Wi-Fi and Sleep Modes
^^^^^^^^^^^^^^^^^^^^^^^
In Deep-sleep and Light-sleep modes, the wireless peripherals are powered down. Before entering Deep-sleep or Light-sleep modes, applications must disable Wi-Fi using the appropriate calls (:cpp:func:`esp_wifi_stop`). Wi-Fi connections will not be maintained in Deep-sleep or Light-sleep mode, even if these functions are not called.
In Deep-sleep and Light-sleep modes, the wireless peripherals are powered down. Before entering Deep-sleep or Light-sleep modes, applications must disable Wi-Fi using the appropriate calls (:cpp:func:`esp_wifi_stop`). Wi-Fi connections are not maintained in Deep-sleep or Light-sleep mode, even if these functions are not called.
If Wi-Fi connections need to be maintained, enable Wi-Fi Modem-sleep mode and automatic Light-sleep feature (see :doc:`Power Management APIs <power_management>`). This will allow the system to wake up from sleep automatically when required by the Wi-Fi driver, thereby maintaining a connection to the AP.
@ -54,7 +55,7 @@ In Deep-sleep mode, the CPUs, most of the RAM, and all digital peripherals that
Wakeup Sources
--------------
Wakeup sources can be enabled using ``esp_sleep_enable_X_wakeup`` APIs. Wakeup sources are not disabled after wakeup, you can disable them using :cpp:func:`esp_sleep_disable_wakeup_source` API if you don't need them any more. See :ref:`disable_sleep_wakeup_source`.
Wakeup sources can be enabled using ``esp_sleep_enable_X_wakeup`` APIs. Wakeup sources are not disabled after wakeup, you can disable them using :cpp:func:`esp_sleep_disable_wakeup_source` API if you do not need them any more. See :ref:`disable_sleep_wakeup_source`.
Following are the wakeup sources supported on {IDF_TARGET_NAME}.
@ -65,9 +66,9 @@ The RTC controller has a built-in timer which can be used to wake up the chip af
.. only:: SOC_ULP_SUPPORTED
For details on RTC clock options, see *{IDF_TARGET_NAME} Technical Reference Manual* > *ULP Coprocessor* [`PDF <{IDF_TARGET_TRM_EN_URL}#ulp>`__].
For details on RTC clock options, see **{IDF_TARGET_NAME} Technical Reference Manual** > **ULP Coprocessor** [`PDF <{IDF_TARGET_TRM_EN_URL}#ulp>`__].
RTC peripherals or RTC memories don't need to be powered on during sleep in this wakeup mode.
RTC peripherals or RTC memories do not need to be powered on during sleep in this wakeup mode.
:cpp:func:`esp_sleep_enable_timer_wakeup` function can be used to enable sleep wakeup using a timer.
@ -86,8 +87,8 @@ RTC peripherals or RTC memories don't need to be powered on during sleep in this
.. only:: SOC_PM_SUPPORT_EXT0_WAKEUP
External Wakeup (ext0)
^^^^^^^^^^^^^^^^^^^^^^
External Wakeup (``ext0``)
^^^^^^^^^^^^^^^^^^^^^^^^^^
The RTC IO module contains the logic to trigger wakeup when one of RTC GPIOs is set to a predefined logic level. RTC IO is part of the RTC peripherals power domain, so RTC peripherals will be kept powered on during Deep-sleep if this wakeup source is requested.
@ -99,7 +100,9 @@ RTC peripherals or RTC memories don't need to be powered on during sleep in this
:cpp:func:`esp_sleep_enable_ext0_wakeup` function can be used to enable this wakeup source.
.. warning:: After waking up from sleep, the IO pad used for wakeup will be configured as RTC IO. Therefore, before using this pad as digital GPIO, users need to reconfigure it using :cpp:func:`rtc_gpio_deinit` function.
.. warning::
After waking up from sleep, the IO pad used for wakeup will be configured as RTC IO. Therefore, before using this pad as digital GPIO, users need to reconfigure it using :cpp:func:`rtc_gpio_deinit` function.
.. only:: SOC_PM_SUPPORT_EXT1_WAKEUP
@ -135,9 +138,10 @@ RTC peripherals or RTC memories don't need to be powered on during sleep in this
gpio_pulldown_en(gpio_num);
.. warning::
- To use the EXT1 wakeup, the IO pad(s) are configured as RTC IO. Therefore, before using these pads as digital GPIOs, users need to reconfigure them by calling the :cpp:func:`rtc_gpio_deinit` function.
- If the RTC peripherals are configured to be powered down (which is by default), the wakeup IOs will be set to the holding state before entering sleep. Therefore, after the chip wakes up from Light-sleep, please call `rtc_gpio_hold_dis` to disable the hold function to perform any pin re-configuration. For Deep-sleep wakeup, this is already being handled at the application startup stage.
- If the RTC peripherals are configured to be powered down (which is by default), the wakeup IOs will be set to the holding state before entering sleep. Therefore, after the chip wakes up from Light-sleep, please call ``rtc_gpio_hold_dis`` to disable the hold function to perform any pin re-configuration. For Deep-sleep wakeup, this is already being handled at the application startup stage.
:cpp:func:`esp_sleep_enable_ext1_wakeup` function can be used to enable this wakeup source.
@ -170,6 +174,7 @@ RTC peripherals or RTC memories don't need to be powered on during sleep in this
:cpp:func:`esp_sleep_enable_gpio_wakeup` function can be used to enable this wakeup source.
.. warning::
Before entering Light-sleep mode, check if any GPIO pin to be driven is part of the {IDF_TARGET_SPI_POWER_DOMAIN} power domain. If so, this power domain must be configured to remain ON during sleep.
For example, on ESP32-WROOM-32 board, GPIO16 and GPIO17 are linked to {IDF_TARGET_SPI_POWER_DOMAIN} power domain. If they are configured to remain high during Light-sleep, the power domain should be configured to remain powered ON. This can be done with :cpp:func:`esp_sleep_pd_config()`::
@ -209,11 +214,11 @@ The application can force specific powerdown modes for RTC peripherals and RTC m
Power-down of RTC Peripherals and Memories
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
By default, :cpp:func:`esp_deep_sleep_start` and :cpp:func:`esp_light_sleep_start` functions will power down all RTC power domains which are not needed by the enabled wakeup sources. To override this behaviour, :cpp:func:`esp_sleep_pd_config` function is provided.
By default, :cpp:func:`esp_deep_sleep_start` and :cpp:func:`esp_light_sleep_start` functions power down all RTC power domains which are not needed by the enabled wakeup sources. To override this behaviour, :cpp:func:`esp_sleep_pd_config` function is provided.
.. only:: esp32
Note: in revision 0 of ESP32, RTC fast memory will always be kept enabled in Deep-sleep, so that the Deep-sleep stub can run after reset. This can be overridden, if the application doesn't need clean reset behaviour after Deep-sleep.
Note: in revision 0 of ESP32, RTC fast memory is always kept enabled in Deep-sleep, so that the Deep-sleep stub can run after reset. This can be overridden, if the application does not need clean reset behaviour after Deep-sleep.
.. only:: SOC_RTC_SLOW_MEM_SUPPORTED
@ -226,14 +231,15 @@ By default, :cpp:func:`esp_deep_sleep_start` and :cpp:func:`esp_light_sleep_star
Power-down of Flash
^^^^^^^^^^^^^^^^^^^
By default, to avoid potential issues, :cpp:func:`esp_light_sleep_start` function will **not** power down flash. To be more specific, it takes time to power down the flash and during this period the system may be woken up, which then actually powers up the flash before this flash could be powered down completely. As a result, there is a chance that the flash may not work properly.
By default, to avoid potential issues, :cpp:func:`esp_light_sleep_start` function does **not** power down flash. To be more specific, it takes time to power down the flash and during this period the system may be woken up, which then actually powers up the flash before this flash could be powered down completely. As a result, there is a chance that the flash may not work properly.
So, in theory, it's ok if you only wake up the system after the flash is completely powered down. However, in reality, the flash power-down period can be hard to predict (for example, this period can be much longer when you add filter capacitors to the flash's power supply circuit) and uncontrollable (for example, the asynchronous wake-up signals make the actual sleep time uncontrollable).
So, in theory, it is ok if you only wake up the system after the flash is completely powered down. However, in reality, the flash power-down period can be hard to predict (for example, this period can be much longer when you add filter capacitors to the flash's power supply circuit) and uncontrollable (for example, the asynchronous wake-up signals make the actual sleep time uncontrollable).
.. warning::
If a filter capacitor is added to your flash power supply circuit, please do everything possible to avoid powering down flash.
Therefore, it's recommended not to power down flash when using ESP-IDF. For power-sensitive applications, it's recommended to use Kconfig option :ref:`CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND` to reduce the power consumption of the flash during light sleep, instead of powering down the flash.
Therefore, it is recommended not to power down flash when using ESP-IDF. For power-sensitive applications, it is recommended to use Kconfig option :ref:`CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND` to reduce the power consumption of the flash during Light-sleep, instead of powering down the flash.
.. only:: SOC_SPIRAM_SUPPORTED
@ -250,10 +256,10 @@ However, for those who have fully understood the risk and are still willing to p
.. list::
- ESP-IDF does not provide any mechanism that can power down the flash in all conditions when light sleep.
- :cpp:func:`esp_deep_sleep_start` function will force power down flash regardless of user configuration.
- ESP-IDF does not provide any mechanism that can power down the flash in all conditions when Light-sleep.
- :cpp:func:`esp_deep_sleep_start` function forces power down flash regardless of user configuration.
Configuring IOs (Deep-sleep only)
Configuring IOs (Deep-sleep Only)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Some {IDF_TARGET_NAME} IOs have internal pullups or pulldowns, which are enabled by default. If an external circuit drives this pin in Deep-sleep mode, current consumption may increase due to current flowing through these pullups and pulldowns.
@ -262,7 +268,7 @@ Some {IDF_TARGET_NAME} IOs have internal pullups or pulldowns, which are enabled
To isolate a pin to prevent extra current draw, call :cpp:func:`rtc_gpio_isolate` function.
For example, on ESP32-WROVER module, GPIO12 is pulled up externally, and it also has an internal pulldown in the ESP32 chip. This means that in Deep-sleep, some current will flow through these external and internal resistors, increasing Deep-sleep current above the minimal possible value.
For example, on ESP32-WROVER module, GPIO12 is pulled up externally, and it also has an internal pulldown in the ESP32 chip. This means that in Deep-sleep, some current flows through these external and internal resistors, increasing Deep-sleep current above the minimal possible value.
Add the following code before :cpp:func:`esp_deep_sleep_start` to remove such extra current::
@ -281,7 +287,7 @@ Some {IDF_TARGET_NAME} IOs have internal pullups or pulldowns, which are enabled
Entering Sleep
--------------
:cpp:func:`esp_light_sleep_start` or :cpp:func:`esp_deep_sleep_start` functions can be used to enter Light-sleep or Deep-sleep modes correspondingly. After that, the system will configure the parameters of RTC controller according to the requested wakeup sources and power-down options.
:cpp:func:`esp_light_sleep_start` or :cpp:func:`esp_deep_sleep_start` functions can be used to enter Light-sleep or Deep-sleep modes correspondingly. After that, the system configures the parameters of RTC controller according to the requested wakeup sources and power-down options.
It is also possible to enter sleep modes with no wakeup sources configured. In this case, the chip will be in sleep modes indefinitely until external reset is applied.

View File

@ -1,7 +1,7 @@
SoC Capabilities
================
This section lists definitions of the {IDF_TARGET_NAME}'s SoC hardware capabilities. These definitions are commonly used in IDF to control which hardware dependent features are supported and thus compiled into the binary.
This section lists definitions of the {IDF_TARGET_NAME}'s SoC hardware capabilities. These definitions are commonly used in ESP-IDF to control which hardware dependent features are supported and thus compiled into the binary.
.. note::

View File

@ -134,13 +134,13 @@ If you want to choose the :cpp:enumerator:`SNTP_SYNC_MODE_SMOOTH` mode, please s
For setting a callback function that is called when time gets synchronized, use the :cpp:member:`esp_sntp_config::sync_cb` field in the configuration struct.
An application with this initialization code will periodically synchronize the time. The time synchronization period is determined by :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` (the default value is one hour). To modify the variable, set :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` in project configuration.
An application with this initialization code periodically synchronizes the time. The time synchronization period is determined by :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` (the default value is one hour). To modify the variable, set :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` in project configuration.
A code example that demonstrates the implementation of time synchronization based on the lwIP SNTP library is provided in the :example:`protocols/sntp` directory.
Note that it's also possible to use lwIP API directly, but care must be taken to thread safety. Here we list the thread-safe APIs:
Note that it is also possible to use lwIP API directly, but care must be taken to thread safety. Here we list the thread-safe APIs:
- :cpp:func:`sntp_set_time_sync_notification_cb` can be used to set a callback function that will notify of the time synchronization process.
- :cpp:func:`sntp_set_time_sync_notification_cb` can be used to set a callback function that notifies of the time synchronization process.
- :cpp:func:`sntp_get_sync_status` and :cpp:func:`sntp_set_sync_status` can be used to get/set time synchronization status.
- :cpp:func:`sntp_set_sync_mode` can be used to set the synchronization mode.
- :cpp:func:`esp_sntp_setoperatingmode` sets the preferred operating mode.:cpp:enumerator:`ESP_SNTP_OPMODE_POLL` and :cpp:func:`esp_sntp_init` initializes SNTP module.
@ -155,7 +155,7 @@ To set the local timezone, use the following POSIX functions:
1. Call ``setenv()`` to set the ``TZ`` environment variable to the correct value based on the device location. The format of the time string is the same as described in the `GNU libc documentation <https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html>`_ (although the implementation is different).
2. Call ``tzset()`` to update C library runtime data for the new timezone.
Once these steps are completed, call the standard C library function ``localtime()``, and it will return the correct local time taking into account the timezone offset and daylight saving time.
Once these steps are completed, call the standard C library function ``localtime()``, and it returns the correct local time taking into account the timezone offset and daylight saving time.
Year 2036 and 2038 Overflow Issues

View File

@ -1,5 +1,6 @@
ULP LP-Core Coprocessor Programming
===================================
:link_to_translation:`zh_CN:[中文]`
The ULP LP-Core (Low-power core) coprocessor is a variant of the ULP present in {IDF_TARGET_NAME}. It features ultra-low power consumption while also being able to stay powered on while the main CPU stays in low-power modes. This enables the LP-Core coprocessor to handle tasks like GPIO or sensor readings while the main CPU is in sleep mode, resulting in significant overall power savings for the entire system.
@ -16,11 +17,11 @@ The ULP LP-Core coprocessor has the following features:
Compiling Code for the ULP LP-Core
----------------------------------
The ULP LP-Core code is compiled together with your IDF project as a separate binary and automatically embedded into the main project binary. To acheive this do the following:
The ULP LP-Core code is compiled together with your ESP-IDF project as a separate binary and automatically embedded into the main project binary. To acheive this do the following:
1. Place the ULP LP-Core code, written in C or assembly (with the ``.S`` extension), in a dedicated directory within the component directory, such as ``ulp/``.
2. After registering the component in the CMakeLists.txt file, call the ``ulp_embed_binary`` function. Here's an example:
2. After registering the component in the CMakeLists.txt file, call the ``ulp_embed_binary`` function. Here is an example:
idf_component_register()
@ -31,16 +32,16 @@ The ULP LP-Core code is compiled together with your IDF project as a separate bi
ulp_embed_binary(${ulp_app_name} "${ulp_sources}" "${ulp_exp_dep_srcs}")
The first argument to ``ulp_embed_binary`` specifies the ULP binary name. The name specified here will also be used by other generated artifacts such as the ELF file, map file, header file, and linker export file. The second argument specifies the ULP source files. Finally, the third argument specifies the list of component source files which include the header file to be generated. This list is needed to build the dependencies correctly and ensure that the generated header file will be created before any of these files are compiled. See the section below for the concept of generated header files for ULP applications.
The first argument to ``ulp_embed_binary`` specifies the ULP binary name. The name specified here is also used by other generated artifacts such as the ELF file, map file, header file, and linker export file. The second argument specifies the ULP source files. Finally, the third argument specifies the list of component source files which include the header file to be generated. This list is needed to build the dependencies correctly and ensure that the generated header file is created before any of these files are compiled. See the section below for the concept of generated header files for ULP applications.
3. Enable both :ref:`CONFIG_ULP_COPROC_ENABLED` and :ref:`CONFIG_ULP_COPROC_TYPE` to ``CONFIG_ULP_COPROC_TYPE_LP_CORE`` options in menuconfig. The :ref:`CONFIG_ULP_COPROC_RESERVE_MEM` option will reserve RTC memory for the ULP and must be set to a value big enough to store both the ULP LP-Core code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one.
3. Enable both :ref:`CONFIG_ULP_COPROC_ENABLED` and :ref:`CONFIG_ULP_COPROC_TYPE` to ``CONFIG_ULP_COPROC_TYPE_LP_CORE`` options in menuconfig. The :ref:`CONFIG_ULP_COPROC_RESERVE_MEM` option reserves RTC memory for the ULP and must be set to a value big enough to store both the ULP LP-Core code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one.
4. Build the application as usual (e.g., `idf.py app`).
4. Build the application as usual (e.g., ``idf.py app``).
During the build process, the following steps are taken to build ULP program:
1. **Run each source file through the C compiler and assembler.** This step generates the object files (.obj.c or .obj.S depending of source file processed) in the component build directory.
1. **Run each source file through the C compiler and assembler.** This step generates the object files (``.obj.c`` or ``.obj.S`` depending of source file processed) in the component build directory.
2. **Run the linker script template through the C preprocessor.** The template is located in ``components/ulp/ld`` directory.
@ -61,7 +62,7 @@ Accessing the ULP LP-Core Program Variables
Global symbols defined in the ULP LP-Core program may be used inside the main program.
For example, the ULP LP-Core program may define a variable ``measurement_count`` which will define the number of GPIO measurements the program needs to make before waking up the chip from deep sleep.
For example, the ULP LP-Core program may define a variable ``measurement_count`` which defines the number of GPIO measurements the program needs to make before waking up the chip from deep sleep.
.. code-block:: c
@ -89,7 +90,7 @@ The generated linker script file defines the locations of symbols in LP_MEM::
PROVIDE ( ulp_measurement_count = 0x50000060 );
To access the ULP LP-Core program variables from the main program, the generated header file should be included using an ``include`` statement. This will allow the ULP LP-Core program variables to be accessed as regular variables.
To access the ULP LP-Core program variables from the main program, the generated header file should be included using an ``include`` statement. This allows the ULP LP-Core program variables to be accessed as regular variables.
.. code-block:: c
@ -131,7 +132,7 @@ Once the program is loaded into LP memory, the application can be configured and
ULP LP-Core Program Flow
------------------------
How the ULP LP-Core coprocessor is started depends on the wakeup source selected in :cpp:type:`ulp_lp_core_cfg_t`. The most common use-case will be for the ULP to periodically wake-up, do some measurements before either waking up the main CPU or going back to sleep again.
How the ULP LP-Core coprocessor is started depends on the wakeup source selected in :cpp:type:`ulp_lp_core_cfg_t`. The most common use-case is for the ULP to periodically wake-up, do some measurements before either waking up the main CPU or going back to sleep again.
The ULP has the following wake-up sources:
* :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU` - LP Core can be woken up by the HP CPU.
@ -140,9 +141,9 @@ The ULP has the following wake-up sources:
* :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_LP_IO` - LP Core can be woken up when LP IO level changes. (Not yet supported)
* :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_LP_UART` - LP Core can be woken up after receiving a certain number of UART RX pulses. (Not yet supported)
When the ULP is woken up it will go through the following steps:
When the ULP is woken up, it will go through the following steps:
1. Initialize system feature, e.g. interrupts
1. Initialize system feature, e.g., interrupts
2. Call user code: ``main()``
3. Return from ``main()``
4. If ``lp_timer_sleep_duration_us`` is specified then configure the next wake-up alarm

View File

@ -1,8 +1,9 @@
ULP RISC-V Coprocessor Programming
==================================
:link_to_translation:`zh_CN:[中文]`
The ULP RISC-V coprocessor is a variant of the ULP present in {IDF_TARGET_NAME}. Similar to ULP FSM, the ULP RISC-V coprocessor can perform tasks such as sensor readings while the main CPU stays in low power modes. The main difference between ULP FSM and ULP RISC-V is that the latter can be programmed in C using standard GNU tools. The ULP RISC-V coprocessor can access the RTC_SLOW_MEM memory region, and registers in RTC_CNTL, RTC_IO, and SARADC peripherals. The RISC-V processor is a 32-bit fixed point machine. Its instruction set is based on RV32IMC which includes hardware multiplication and division, and compressed code.
The ULP RISC-V coprocessor is a variant of the ULP present in {IDF_TARGET_NAME}. Similar to ULP FSM, the ULP RISC-V coprocessor can perform tasks such as sensor readings while the main CPU stays in low power modes. The main difference between ULP FSM and ULP RISC-V is that the latter can be programmed in C using standard GNU tools. The ULP RISC-V coprocessor can access the RTC_SLOW_MEM memory region, and registers in ``RTC_CNTL``, ``RTC_IO``, and ``SARADC`` peripherals. The RISC-V processor is a 32-bit fixed point machine. Its instruction set is based on RV32IMC which includes hardware multiplication and division, and compressed code.
Installing the ULP RISC-V Toolchain
-----------------------------------
@ -11,16 +12,20 @@ The ULP RISC-V coprocessor code is written in C (assembly is also possible) and
If you have already set up ESP-IDF with CMake build system according to the :doc:`Getting Started Guide <../../../get-started/index>`, then the toolchain should already be installed.
.. note:: In earlier versions of ESP-IDF, RISC-V toolchain had a different prefix: `riscv-none-embed-gcc`.
.. note::
In earlier versions of ESP-IDF, RISC-V toolchain had a different prefix: ``riscv-none-embed-gcc``.
Compiling the ULP RISC-V Code
-----------------------------
To compile the ULP RISC-V code as part of the component, the following steps must be taken:
1. The ULP RISC-V code, written in C or assembly (must use the `.S` extension), must be placed in a separate directory inside the component directory, for instance, `ulp/`.
1. The ULP RISC-V code, written in C or assembly (must use the ``.S`` extension), must be placed in a separate directory inside the component directory, for instance, ``ulp/``.
.. note:: When registering the component (via ``idf_component_register``), this directory should not be added to the ``SRC_DIRS`` argument as it is currently done for the ULP FSM. See the step below for how to properly add ULP source files.
.. note::
When registering the component (via ``idf_component_register``), this directory should not be added to the ``SRC_DIRS`` argument as it is currently done for the ULP FSM. See the step below for how to properly add ULP source files.
2. Call ``ulp_embed_binary`` from the component CMakeLists.txt after registration. For example::
@ -35,11 +40,11 @@ To compile the ULP RISC-V code as part of the component, the following steps mus
The first argument to ``ulp_embed_binary`` specifies the ULP binary name. The name specified here will also be used by other generated artifacts such as the ELF file, map file, header file, and linker export file. The second argument specifies the ULP source files. Finally, the third argument specifies the list of component source files which include the header file to be generated. This list is needed to build the dependencies correctly and ensure that the generated header file will be created before any of these files are compiled. See the section below for the concept of generated header files for ULP applications.
3. Build the application as usual (e.g., `idf.py app`).
3. Build the application as usual (e.g., ``idf.py app``).
Inside, the build system will take the following steps to build ULP program:
1. **Run each source file through the C compiler and assembler.** This step generates the object files (.obj.c or .obj.S depending of source file processed) in the component build directory.
1. **Run each source file through the C compiler and assembler.** This step generates the object files (``.obj.c`` or ``.obj.S`` depending of source file processed) in the component build directory.
2. **Run the linker script template through the C preprocessor.** The template is located in ``components/ulp/ld`` directory.
@ -115,7 +120,7 @@ Starting the ULP RISC-V Program
To run a ULP RISC-V program, the main application needs to load the ULP program into RTC memory using the :cpp:func:`ulp_riscv_load_binary` function, and then start it using the :cpp:func:`ulp_riscv_run` function.
Note that `CONFIG_ULP_COPROC_ENABLED` and `CONFIG_ULP_COPROC_TYPE_RISCV` options must be enabled in menuconfig to work with ULP RISC-V. To reserve memory for the ULP, the ``RTC slow memory reserved for coprocessor`` option must be set to a value big enough to store ULP RISC-V code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one.
Note that the ``CONFIG_ULP_COPROC_ENABLED`` and ``CONFIG_ULP_COPROC_TYPE_RISCV`` options must be enabled in menuconfig to work with ULP RISC-V. To reserve memory for the ULP, the ``RTC slow memory reserved for coprocessor`` option must be set to a value big enough to store ULP RISC-V code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one.
Each ULP RISC-V program is embedded into the ESP-IDF application as a binary blob. The application can reference this blob and load it in the following way (suppose ULP_APP_NAME was defined to ``ulp_app_name``):
@ -162,9 +167,13 @@ The RTC I2C controller provides I2C master functionality in the RTC domain. The
Once the RTC I2C controller is initialized, the I2C slave device address must be programmed via the :cpp:func:`ulp_riscv_i2c_master_set_slave_addr` API before any read or write operation is performed.
.. note:: The RTC I2C peripheral always expects a slave sub-register address to be programmed via the :cpp:func:`ulp_riscv_i2c_master_set_slave_reg_addr` API. If it is not, the I2C peripheral uses the ``SENS_SAR_I2C_CTRL_REG[18:11]`` as the sub register address for the subsequent read or write operations. This could make the RTC I2C peripheral incompatible with certain I2C devices or sensors which do not need any sub-register to be programmed.
.. note::
The RTC I2C peripheral always expects a slave sub-register address to be programmed via the :cpp:func:`ulp_riscv_i2c_master_set_slave_reg_addr` API. If it is not, the I2C peripheral uses the ``SENS_SAR_I2C_CTRL_REG[18:11]`` as the sub-register address for the subsequent read or write operations. This could make the RTC I2C peripheral incompatible with certain I2C devices or sensors which do not need any sub-register to be programmed.
.. note:: There is no hardware atomicity protection in accessing the RTC I2C peripheral between the main CPU and the ULP RISC-V core. Therefore, care must be taken that both cores are not accessing the peripheral simultaneously.
.. note::
There is no hardware atomicity protection in accessing the RTC I2C peripheral between the main CPU and the ULP RISC-V core. Therefore, care must be taken that both cores are not accessing the peripheral simultaneously.
In case your RTC I2C based ULP RISC-V program is not working as expected, the following sanity checks can help in debugging the issue:
@ -174,13 +183,13 @@ In case your RTC I2C based ULP RISC-V program is not working as expected, the fo
* If the I2C slave device or sensor does not require a sub-register address to be programmed, it may not be compatible with the RTC I2C peripheral. Please refer the notes above.
* If the RTC driver reports a `Write Failed!` or `Read Failed!` error log when running on the main CPU, then make sure:
* If the RTC driver reports a ``Write Failed!`` or ``Read Failed!`` error log when running on the main CPU, then make sure:
* The I2C slave device or sensor works correctly with the standard I2C master on Espressif SoCs. This would rule out any problems with the I2C slave device itself.
* If the RTC I2C interrupt status log reports a `TIMEOUT` error or `ACK` error, it could typically mean that the I2C device did not respond to a `START` condition sent out by the RTC I2C controller. This could happen if the I2C slave device is not connected properly to the controller pins or if the I2C slave device is in a bad state. Make sure that the I2C slave device is in a good state and connected properly before continuing.
* If the RTC I2C interrupt status log reports a ``TIMEOUT`` error or ``ACK`` error, it could typically mean that the I2C device did not respond to a ``START`` condition sent out by the RTC I2C controller. This could happen if the I2C slave device is not connected properly to the controller pins or if the I2C slave device is in a bad state. Make sure that the I2C slave device is in a good state and connected properly before continuing.
* If the RTC I2C interrupt log does not report any error status, it could mean that the driver is not fast enough in receiving data from the I2C slave device. This could happen as the RTC I2C controller does not have a TX/RX FIFO to store multiple bytes of data but rather, it depends on single byte transmissions using an interrupt status polling mechanism. This could be mitigated to some extent by making sure that the SCL clock of the peripheral is running as fast as possible. This can be tweaked by configuring the SCL low period and SCL high period values in the initialization config parameters for the peripheral.
* Other methods of debugging problems would be to ensure that the RTC I2C controller is operational *only* on the main CPU *without* any ULP RISC-V code interfering and *without* any sleep mode being activated. This is the basic configuration under which the RTC I2C peripheral must work. This way you can rule out any potential issues due to the ULP or sleep modes.
* Other methods of debugging problems would be to ensure that the RTC I2C controller is operational **only** on the main CPU **without** any ULP RISC-V code interfering and **without** any sleep mode being activated. This is the basic configuration under which the RTC I2C peripheral must work. This way you can rule out any potential issues due to the ULP or sleep modes.
Debugging Your ULP RISC-V Program
----------------------------------

View File

@ -1,9 +1,9 @@
ULP Coprocessor programming
ULP Coprocessor Programming
=============================
:link_to_translation:`zh_CN:[中文]`
The Ultra Low Power (ULP) coprocessor is a simple finite state machine (FSM) which is designed to perform measurements using the ADC, temperature sensor, and external I2C sensors, while the main processors are in deep sleep mode. The ULP coprocessor can access the RTC_SLOW_MEM memory region, and registers in the RTC_CNTL, RTC_IO, and SARADC peripherals. The ULP coprocessor uses fixed-width 32-bit instructions, 32-bit memory addressing, and has 4 general-purpose 16-bit registers. This coprocessor is referred to as `ULP FSM` in ESP-IDF.
The Ultra Low Power (ULP) coprocessor is a simple finite state machine (FSM) which is designed to perform measurements using the ADC, temperature sensor, and external I2C sensors, while the main processors are in Deep-sleep mode. The ULP coprocessor can access the ``RTC_SLOW_MEM`` memory region, and registers in the ``RTC_CNTL``, ``RTC_IO``, and ``SARADC`` peripherals. The ULP coprocessor uses fixed-width 32-bit instructions, 32-bit memory addressing, and has 4 general-purpose 16-bit registers. This coprocessor is referred to as ``ULP FSM`` in ESP-IDF.
.. only:: esp32s2 or esp32s3
@ -32,9 +32,11 @@ Compiling the ULP Code
To compile the ULP FSM code as part of the component, the following steps must be taken:
1. The ULP FSM code, written in assembly, must be added to one or more files with `.S` extension. These files must be placed into a separate directory inside the component directory, for instance, `ulp/`.
1. The ULP FSM code, written in assembly, must be added to one or more files with ``.S`` extension. These files must be placed into a separate directory inside the component directory, for instance, ``ulp/``.
.. note:: When registering the component (via ``idf_component_register``), this directory should not be added to the ``SRC_DIRS`` argument. The logic behind this is that the ESP-IDF build system will compile files found in ``SRC_DIRS`` based on their extensions. For ``.S`` files, ``{IDF_TARGET_TOOLCHAIN_PREFIX}-as`` assembler is used. This is not desirable for ULP FSM assembly files, so the easiest way to achieve the distinction is by placing ULP FSM assembly files into a separate directory. The ULP FSM assembly source files should also **not** be added to ``SRCS`` for the same reason. See the step below for how to properly add ULP FSM assembly source files.
.. note::
When registering the component (via ``idf_component_register``), this directory should not be added to the ``SRC_DIRS`` argument. The logic behind this is that the ESP-IDF build system will compile files found in ``SRC_DIRS`` based on their extensions. For ``.S`` files, ``{IDF_TARGET_TOOLCHAIN_PREFIX}-as`` assembler is used. This is not desirable for ULP FSM assembly files, so the easiest way to achieve the distinction is by placing ULP FSM assembly files into a separate directory. The ULP FSM assembly source files should also **not** be added to ``SRCS`` for the same reason. See the steps below for how to properly add ULP FSM assembly source files.
2. Call ``ulp_embed_binary`` from the component CMakeLists.txt after registration. For example::
@ -49,7 +51,7 @@ To compile the ULP FSM code as part of the component, the following steps must b
The first argument to ``ulp_embed_binary`` specifies the ULP FSM binary name. The name specified here will also be used by other generated artifacts such as the ELF file, map file, header file and linker export file. The second argument specifies the ULP FSM assembly source files. Finally, the third argument specifies the list of component source files which include the header file to be generated. This list is needed to build the dependencies correctly and ensure that the generated header file will be created before any of these files are compiled. See the section below for the concept of generated header files for ULP applications.
3. Build the application as usual (e.g. `idf.py app`).
3. Build the application as usual (e.g., ``idf.py app``).
Inside, the build system will take the following steps to build ULP FSM program:
@ -74,7 +76,7 @@ Accessing the ULP FSM Program Variables
Global symbols defined in the ULP FSM program may be used inside the main program.
For example, the ULP FSM program may define a variable ``measurement_count`` which will define the number of ADC measurements the program needs to make before waking up the chip from deep sleep::
For example, the ULP FSM program may define a variable ``measurement_count`` which will define the number of ADC measurements the program needs to make before waking up the chip from Deep-sleep::
.global measurement_count
measurement_count: .long 0
@ -106,7 +108,7 @@ To access the ULP program variables from the main program, the generated header
.. only:: esp32
Note that the ULP FSM program can only use the lower 16 bits of each 32-bit word in RTC memory, because the registers are 16-bit, and there is no instruction to load from the high part of the word. Likewise, the ULP store instruction writes register values into the lower 16 bits of the 32-bit word in RTC memory. The upper 16 bits are written with a value which depends on the address of the store instruction, thus when reading variables written by the ULP coprocessor, the main application needs to mask the upper 16 bits, e.g.::
Note that the ULP FSM program can only use the lower 16 bits of each 32-bit word in RTC memory, because the registers are 16-bit, and there is no instruction to load from the high part of the word. Likewise, the ULP store instruction writes register values into the lower 16 bits of the 32-bit word in RTC memory. The upper 16 bits are written with a value which depends on the address of the store instruction, thus when reading variables written by the ULP coprocessor, the main application needs to mask the upper 16 bits, e.g.,::
printf("Last measurement value: %d\n", ulp_last_measurement & UINT16_MAX);
@ -142,7 +144,7 @@ Declaration of the entry point symbol comes from the generated header file menti
.. only:: esp32
ESP32 ULP program flow
ESP32 ULP Program Flow
-----------------------
ESP32 ULP coprocessor is started by a timer. The timer is started once :cpp:func:`ulp_run` is called. The timer counts a number of RTC_SLOW_CLK ticks (by default, produced by an internal 150 kHz RC oscillator). The number of ticks is set using ``SENS_ULP_CP_SLEEP_CYCx_REG`` registers (x = 0..4). When starting the ULP for the first time, ``SENS_ULP_CP_SLEEP_CYC0_REG`` will be used to set the number of timer ticks. Later the ULP program can select another ``SENS_ULP_CP_SLEEP_CYCx_REG`` register using ``sleep`` instruction.
@ -158,7 +160,7 @@ Declaration of the entry point symbol comes from the generated header file menti
.. only:: esp32s2 or esp32s3
{IDF_TARGET_NAME} ULP program flow
{IDF_TARGET_NAME} ULP Program Flow
----------------------------------
{IDF_TARGET_NAME} ULP coprocessor is started by a timer. The timer is started once :cpp:func:`ulp_run` is called. The timer counts a number of RTC_SLOW_CLK ticks (by default, produced by an internal 90 kHz RC oscillator). The number of ticks is set using ``RTC_CNTL_ULP_CP_TIMER_1_REG`` register.
@ -174,8 +176,8 @@ Declaration of the entry point symbol comes from the generated header file menti
Application Examples
--------------------
* ULP FSM Coprocessor counts pulses on an IO while main CPU is in deep sleep: :example:`system/ulp/ulp_fsm/ulp`.
* ULP FSM Coprocessor polls ADC in while main CPU is in deep sleep: :example:`system/ulp/ulp_fsm/ulp_adc`.
* ULP FSM Coprocessor counts pulses on an IO while main CPU is in Deep-sleep: :example:`system/ulp/ulp_fsm/ulp`.
* ULP FSM Coprocessor polls ADC in while main CPU is in Deep-sleep: :example:`system/ulp/ulp_fsm/ulp_adc`.
API Reference
-------------

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
Programming ULP FSM coprocessor using C macros (legacy)
Programming ULP FSM Coprocessor Using C Macros (Legacy)
=======================================================
In addition to the existing binutils port for the {IDF_TARGET_NAME} ULP coprocessor, it is possible to generate programs for the ULP FSM coprocessor by embedding assembly-like macros into an {IDF_TARGET_NAME} application. Here is an example how this can be done::
@ -16,13 +16,14 @@ In addition to the existing binutils port for the {IDF_TARGET_NAME} ULP coproces
ulp_process_macros_and_load(load_addr, program, &size);
ulp_run(load_addr);
The ``program`` array is an array of ``ulp_insn_t``, i.e. ULP coprocessor instructions. Each ``I_XXX`` preprocessor define translates into a single 32-bit instruction. Arguments of these preprocessor defines can be register numbers (``R0 — R3``) and literal constants. See the API reference section at the end of this guide for descriptions of instructions and arguments they take.
The ``program`` array is an array of ``ulp_insn_t``, i.e., ULP coprocessor instructions. Each ``I_XXX`` preprocessor define translates into a single 32-bit instruction. Arguments of these preprocessor defines can be register numbers (``R0 — R3``) and literal constants. See the API reference section at the end of this guide for descriptions of instructions and arguments they take.
.. note::
Because some of the instruction macros expand to inline function calls, defining such array in global scope will cause the compiler to produce an "initializer element is not constant" error. To fix this error, move the definition of instructions array into local scope.
.. note::
Load, store and move instructions use **addresses expressed in 32-bit words**. Address 0 corresponds to the first word of ``RTC_SLOW_MEM``.
This is different to how address arguments are handled in assembly code of the same instructions. See the section :ref:`ulp-fsm-addressing` for more details for reference.

View File

@ -25,7 +25,7 @@ The purpose of the IWDT is to ensure that interrupt service routines (ISRs) are
- Disabling interrupts
- Critical Sections (also disables interrupts)
- Other same/higher priority ISRs (will block same/lower priority ISRs from running it completes execution)
- Other same/higher priority ISRs ( blocks same/lower priority ISRs from running it completes execution)
The IWDT utilizes the watchdog timer in {IDF_TARGET_IWDT_TIMER_GROUP} as its underlying hardware timer and leverages the FreeRTOS tick interrupt on each CPU to feed the watchdog timer. If the tick interrupt on a particular CPU is not run at within the IWDT timeout period, it is indicative that something is blocking ISRs from being run on that CPU (see the list of reasons above).
@ -39,7 +39,7 @@ Configuration
- The IWDT is enabled by default via the :ref:`CONFIG_ESP_INT_WDT` option.
- The IWDT's timeout is configured by setting the :ref:`CONFIG_ESP_INT_WDT_TIMEOUT_MS` option.
- Note that the default timeout is higher if PSRAM support is enabled, as a critical section or interrupt routine that accesses a large amount of PSRAM will take longer to complete in some circumstances.
- Note that the default timeout is higher if PSRAM support is enabled, as a critical section or interrupt routine that accesses a large amount of PSRAM takes longer to complete in some circumstances.
- The timeout should always at least twice longer than the period between FreeRTOS ticks (see :ref:`CONFIG_FREERTOS_HZ`).
Tuning
@ -50,7 +50,7 @@ If you find the IWDT timeout is triggered because an interrupt or critical secti
- Critical sections should be made as short as possible. Any non-critical code/computation should be placed outside the critical section.
- Interrupt handlers should also perform the minimum possible amount of computation. Users can consider deferring any computation to a task by having the ISR push data to a task using queues.
Neither critical sections or interrupt handlers should ever block waiting for another event to occur. If changing the code to reduce the processing time is not possible or desirable, it's possible to increase the :ref:`CONFIG_ESP_INT_WDT_TIMEOUT_MS` setting instead.
Neither critical sections or interrupt handlers should ever block waiting for another event to occur. If changing the code to reduce the processing time is not possible or desirable, it is possible to increase the :ref:`CONFIG_ESP_INT_WDT_TIMEOUT_MS` setting instead.
.. _task-watchdog-timer:
@ -63,11 +63,11 @@ The Task Watchdog Timer (TWDT) is used to monitor particular tasks, ensuring tha
.. only:: not esp32c2
The TWDT is built around the Hardware Watchdog Timer in Timer Group 0. When a timeout occurs, an interrupt is triggered. Users can define the function `esp_task_wdt_isr_user_handler` in the user code, in order to receive the timeout event and extend the default behavior.
The TWDT is built around the Hardware Watchdog Timer in Timer Group 0. When a timeout occurs, an interrupt is triggered. Users can define the function ``esp_task_wdt_isr_user_handler`` in the user code, in order to receive the timeout event and extend the default behavior.
.. only:: esp32c2
The {IDF_TARGET_NAME} has only a single Timer Group, used by Interrupt Watchdog (IWDT). Thus, the Task Watchdog is built around the `esp_timer` component in order to implement a software timer. When a timeout occurs, an interrupt is triggered, notifying the `esp_timer`'s main task. The later will then execute the TWDT callback previously registered. Users can define the function `esp_task_wdt_isr_user_handler` in the user code, in order to receive the timeout event and extend the default behavior.
The {IDF_TARGET_NAME} has only a single Timer Group, used by Interrupt Watchdog (IWDT). Thus, the Task Watchdog is built around the ``esp_timer`` component in order to implement a software timer. When a timeout occurs, an interrupt is triggered, notifying the ``esp_timer``'s main task. The latter then executes the TWDT callback previously registered. Users can define the function ``esp_task_wdt_isr_user_handler`` in the user code, in order to receive the timeout event and extend the default behavior.
Usage
^^^^^
@ -83,14 +83,14 @@ The following functions can be used to watch tasks using the TWDT:
In the case where applications need to watch at a more granular level (i.e., ensure that a particular functions/stub/code-path is called), the TWDT allows subscription of "users".
- :cpp:func:`esp_task_wdt_add_user` to subscribe an arbitrary user of the TWDT. This function will return a user handle to the added user.
- :cpp:func:`esp_task_wdt_add_user` to subscribe an arbitrary user of the TWDT. This function returns a user handle to the added user.
- :cpp:func:`esp_task_wdt_reset_user` must be called using the user handle in order to prevent a TWDT timeout.
- :cpp:func:`esp_task_wdt_delete_user` unsubscribes an arbitrary user of the TWDT.
Configuration
^^^^^^^^^^^^^
The default timeout period for the TWDT is set using config item :ref:`CONFIG_ESP_TASK_WDT_TIMEOUT_S`. This should be set to at least as long as you expect any single task will need to monopolize the CPU (for example, if you expect the app will do a long intensive calculation and should not yield to other tasks). It is also possible to change this timeout at runtime by calling :cpp:func:`esp_task_wdt_init`.
The default timeout period for the TWDT is set using config item :ref:`CONFIG_ESP_TASK_WDT_TIMEOUT_S`. This should be set to at least as long as you expect any single task needs to monopolize the CPU (for example, if you expect the app will do a long intensive calculation and should not yield to other tasks). It is also possible to change this timeout at runtime by calling :cpp:func:`esp_task_wdt_init`.
.. note::
@ -124,9 +124,9 @@ The following config options control TWDT configuration. They are all enabled by
One of the optional clock inputs to the {IDF_TARGET_NAME} is an external 32 KHz crystal or oscillator (XTAL32K) that is used as a clock source (``XTAL32K_CLK``) to various subsystems (such as the RTC).
The XTWDT is a dedicated watchdog timer used to ensure that the XTAL32K is functioning correctly. When ``XTAL32K_CLK`` works as the clock source of ``RTC_SLOW_CLK`` and stops oscillating, the XTWDT will detect this and generate an interrupt. It also provides functionality for automatically switching over to the internal, but less accurate oscillator as the `RTC_SLOW_CLK` source.
The XTWDT is a dedicated watchdog timer used to ensure that the XTAL32K is functioning correctly. When ``XTAL32K_CLK`` works as the clock source of ``RTC_SLOW_CLK`` and stops oscillating, the XTWDT will detect this and generate an interrupt. It also provides functionality for automatically switching over to the internal, but less accurate oscillator as the ``RTC_SLOW_CLK`` source.
Since the switch to the backup clock is done in hardware it can also happen during deep sleep. This means that even if ``XTAL32K_CLK`` stops functioning while the chip in deep sleep, waiting for a timer to expire, it will still be able to wake-up as planned.
Since the switch to the backup clock is done in hardware it can also happen during deep sleep. This means that even if ``XTAL32K_CLK`` stops functioning while the chip in deep sleep, waiting for a timer to expire, it is still able to wake-up as planned.
If the ``XTAL32K_CLK`` starts functioning normally again, you can call ``esp_xt_wdt_restore_clk`` to switch back to this clock source and re-enable the watchdog timer.
@ -140,7 +140,7 @@ The following config options control TWDT configuration. They are all enabled by
JTAG & Watchdogs
----------------
While debugging using OpenOCD, the CPUs will be halted every time a breakpoint is reached. However if the watchdog timers continue to run when a breakpoint is encountered, they will eventually trigger a reset making it very difficult to debug code. Therefore OpenOCD will disable the hardware timers of both the interrupt and task watchdogs at every breakpoint. Moreover, OpenOCD will not reenable them upon leaving the breakpoint. This means that interrupt watchdog and task watchdog functionality will essentially be disabled. No warnings or panics from either watchdogs will be generated when the {IDF_TARGET_NAME} is connected to OpenOCD via JTAG.
While debugging using OpenOCD, the CPUs are halted every time a breakpoint is reached. However if the watchdog timers continue to run when a breakpoint is encountered, they will eventually trigger a reset making it very difficult to debug code. Therefore OpenOCD will disable the hardware timers of both the interrupt and task watchdogs at every breakpoint. Moreover, OpenOCD will not reenable them upon leaving the breakpoint. This means that interrupt watchdog and task watchdog functionality will essentially be disabled. No warnings or panics from either watchdogs will be generated when the {IDF_TARGET_NAME} is connected to OpenOCD via JTAG.
API Reference
-------------

View File

@ -1,5 +1,6 @@
控制台终端
==========
:link_to_translation:`en:[English]`
ESP-IDF 提供了 ``console`` 组件,它包含了开发基于串口的交互式控制终端所需要的所有模块,主要支持以下功能:
@ -12,7 +13,7 @@ ESP-IDF 提供了 ``console`` 组件,它包含了开发基于串口的交互
.. note::
这些功能模块可以一起使用也可以独立使用,例如仅使用行编辑和命令注册的功能,然后使用 ``getopt`` 函数或者自定义的函数来实现参数解析,而不是直接使用 `argtable3 <https://www.argtable.org/>`_ 库。同样地,还可以使用更简单的命令输入方法(比如 ``fgets`` 函数)和其他用于命令分割和参数解析的方法。
这些功能模块可以一起使用也可以独立使用,例如仅使用行编辑和命令注册的功能,然后使用 ``getopt`` 函数或者自定义的函数来实现参数解析,而不是直接使用 `argtable3 <https://www.argtable.org/>`_ 库。同样地,还可以使用更简单的命令输入方法(比如 ``fgets`` 函数)和其他用于命令分割和参数解析的方法。
.. note::
@ -25,7 +26,7 @@ ESP-IDF 提供了 ``console`` 组件,它包含了开发基于串口的交互
.. note::
此功能依赖于终端应用程序对 ANSI 转义符的支持。因此,显示原始 UART 数据的串口监视器不能与行编辑库一同使用。如果运行 :example:`system/console` 示例程序的时候看到的输出结果是 ``[6n`` 或者类似的转义字符而不是命令行提示符 ``esp> `` 时,就表明当前的串口监视器不支持 ANSI 转义字符。已知可用的串口监视程序有 GNU screen、minicom 和 esp-idf-monitor可以通过在项目目录下执行 ``idf.py monitor`` 来调用)。
此功能依赖于终端应用程序对 ANSI 转义符的支持。因此,显示原始 UART 数据的串口监视器不能与行编辑库一同使用。如果运行 :example:`system/console` 示例程序的时候看到的输出结果是 ``[6n`` 或者类似的转义字符而不是命令行提示符 ``esp>`` 时,就表明当前的串口监视器不支持 ANSI 转义字符。已知可用的串口监视程序有 GNU screen、minicom 和 esp-idf-monitor可以通过在项目目录下执行 ``idf.py monitor`` 来调用)。
前往这里可以查看 `linenoise <https://github.com/antirez/linenoise>`_ 库提供的所有函数的描述。
@ -34,19 +35,19 @@ ESP-IDF 提供了 ``console`` 组件,它包含了开发基于串口的交互
Linenoise 库不需要显式地初始化,但是在调用行编辑函数之前,可能需要对某些配置的默认值稍作修改。
:cpp:func:`linenoiseClearScreen`
- :cpp:func:`linenoiseClearScreen`
使用转义字符清除终端屏幕,并将光标定位在左上角。
:cpp:func:`linenoiseSetMultiLine`
- :cpp:func:`linenoiseSetMultiLine`
在单行和多行编辑模式之间进行切换。单行模式下,如果命令的长度超过终端的宽度,会在行内滚动命令文本以显示文本的结尾,在这种情况下,文本的开头部分会被隐藏。单行模式在每次按下按键时发送给屏幕刷新的数据比较少,与多行模式相比更不容易发生故障。另一方面,在单行模式下编辑命令和复制命令将变得更加困难。默认情况下开启的是单行模式。
:cpp:func:`linenoiseAllowEmpty`
- :cpp:func:`linenoiseAllowEmpty`
设置 linenoise 库收到空行的解析行为,设置为 ``true`` 时返回长度为零的字符串 (``""``) ,设置为 ``false`` 时返回 ``NULL``。默认情况下,将返回长度为零的字符串。
:cpp:func:`linenoiseSetMaxLineLen`
- :cpp:func:`linenoiseSetMaxLineLen`
设置 linenoise 库中每行的最大长度,默认长度为 4096 字节,可以通过更新该默认值来优化 RAM 内存的使用。
@ -54,11 +55,11 @@ Linenoise 库不需要显式地初始化,但是在调用行编辑函数之前
主循环
^^^^^^
:cpp:func:`linenoise`
- :cpp:func:`linenoise`
在大多数情况下,控制台应用程序都会具有相同的工作形式——在某个循环中不断读取输入的内容,然后解析再处理。 :cpp:func:`linenoise` 是专门用来获取用户按键输入的函数,当回车键被按下后会便返回完整的一行内容。因此可以用它来完成前面循环中的“读取”任务。
在大多数情况下,控制台应用程序都会具有相同的工作形式——在某个循环中不断读取输入的内容,然后解析再处理。:cpp:func:`linenoise` 是专门用来获取用户按键输入的函数,当回车键被按下后会便返回完整的一行内容。因此可以用它来完成前面循环中的“读取”任务。
:cpp:func:`linenoiseFree`
- :cpp:func:`linenoiseFree`
必须调用此函数才能释放从 :cpp:func:`linenoise` 函数获取的命令行缓冲区。
@ -66,21 +67,21 @@ Linenoise 库不需要显式地初始化,但是在调用行编辑函数之前
提示和补全
^^^^^^^^^^
:cpp:func:`linenoiseSetCompletionCallback`
- :cpp:func:`linenoiseSetCompletionCallback`
当用户按下制表键时, linenoise 会调用 **补全回调函数** ,该回调函数会检查当前已经输入的内容,然后调用 :cpp:func:`linenoiseAddCompletion` 函数来提供所有可能的补全后的命令列表。启用补全功能,需要事先调用 :cpp:func:`linenoiseSetCompletionCallback` 函数来注册补全回调函数。
``console`` 组件提供了一个现成的函数来为注册的命令提供补全功能 :cpp:func:`esp_console_get_completion` (见下文)。
:cpp:func:`linenoiseAddCompletion`
- :cpp:func:`linenoiseAddCompletion`
补全回调函数会通过调用此函数来通知 linenoise 库当前键入命令所有可能的补全结果。
:cpp:func:`linenoiseSetHintsCallback`
- :cpp:func:`linenoiseSetHintsCallback`
每当用户的输入改变时, linenoise 就会调用此回调函数,检查到目前为止输入的命令行内容,然后提供带有提示信息的字符串(例如命令参数列表),然后会在同一行上用不同的颜色显示出该文本。
:cpp:func:`linenoiseSetFreeHintsCallback`
- :cpp:func:`linenoiseSetFreeHintsCallback`
如果 **提示回调函数** 返回的提示字符串是动态分配的或者需要以其它方式回收,就需要使用 :cpp:func:`linenoiseSetFreeHintsCallback` 注册具体的清理函数。
@ -88,23 +89,23 @@ Linenoise 库不需要显式地初始化,但是在调用行编辑函数之前
历史记录
^^^^^^^^
:cpp:func:`linenoiseHistorySetMaxLen`
- :cpp:func:`linenoiseHistorySetMaxLen`
该函数设置要保留在内存中的最近输入的命令的数量。用户通过使用向上/向下箭头来导航历史记录。
:cpp:func:`linenoiseHistoryAdd`
- :cpp:func:`linenoiseHistoryAdd`
Linenoise 不会自动向历史记录中添加命令,应用程序需要调用此函数来将命令字符串添加到历史记录中。
:cpp:func:`linenoiseHistorySave`
- :cpp:func:`linenoiseHistorySave`
该函数将命令的历史记录从 RAM 中保存为文本文件,例如保存到 SD 卡或者 Flash 的文件系统中。
该函数将命令的历史记录从 RAM 中保存为文本文件,例如保存到 SD 卡或者 flash 的文件系统中。
:cpp:func:`linenoiseHistoryLoad`
- :cpp:func:`linenoiseHistoryLoad`
``linenoiseHistorySave`` 相对应,从文件中加载历史记录。
:cpp:func:`linenoiseHistoryFree`
- :cpp:func:`linenoiseHistoryFree`
释放用于存储命令历史记录的内存。当使用完 linenoise 库后需要调用此函数。
@ -123,9 +124,9 @@ Linenoise 库不需要显式地初始化,但是在调用行编辑函数之前
示例:
- ``abc def 1 20 .3`` [ ``abc``, ``def``, ``1``, ``20``, ``.3`` ]
- ``abc "123 456" def`` [ ``abc``, ``123 456``, ``def`` ]
- ```a\ b\\c\"`` [ ``a b\c"`` ]
- ``abc def 1 20 .3`` > [ ``abc``, ``def``, ``1``, ``20``, ``.3`` ]
- ``abc "123 456" def`` > [ ``abc``, ``123 456``, ``def`` ]
- ```a\ b\\c\"`` > [ ``a b\c"`` ]
参数解析
@ -150,19 +151,19 @@ Linenoise 库不需要显式地初始化,但是在调用行编辑函数之前
命令注册模块还提供了其它函数:
:cpp:func:`esp_console_run`
- :cpp:func:`esp_console_run`
该函数接受命令行字符串,使用 :cpp:func:`esp_console_split_argv` 函数将其拆分为 argc/argv 形式的参数列表,在已经注册的组件列表中查找命令,如果找到,则执行其对应的处理程序。
:cpp:func:`esp_console_register_help_command`
- :cpp:func:`esp_console_register_help_command`
``help`` 命令添加到已注册命令列表中,此命令将会以列表的方式打印所有注册的命令及其参数和帮助文本。
:cpp:func:`esp_console_get_completion`
- :cpp:func:`esp_console_get_completion`
与 linenoise 库中的 :cpp:func:`linenoiseSetCompletionCallback` 一同使用的回调函数,根据已经注册的命令列表为 linenoise 提供补全功能。
:cpp:func:`esp_console_get_hint`
- :cpp:func:`esp_console_get_hint`
与 linenoise 库中 :cpp:func:`linenoiseSetHintsCallback` 一同使用的回调函数,为 linenoise 提供已经注册的命令的参数提示功能。
@ -183,9 +184,9 @@ Linenoise 库不需要显式地初始化,但是在调用行编辑函数之前
应用程序示例
------------
:example:`system/console` 目录下提供了 ``console`` 组件的示例应用程序,展示了具体的使用方法。该示例介绍了如何初始化 UART 和 VFS 的功能,设置 linenoise 库,从 UART 中读取命令并加以处理,然后将历史命令存储到 Flash 中。更多信息,请参阅示例代码目录中的 README.md 文件。
:example:`system/console` 目录下提供了 ``console`` 组件的示例应用程序,展示了具体的使用方法。该示例介绍了如何初始化 UART 和 VFS 的功能,设置 linenoise 库,从 UART 中读取命令并加以处理,然后将历史命令存储到 flash 中。更多信息,请参阅示例代码目录中的 README.md 文件。
此外ESP-IDF 还提供了众多基于 `console` 组件的示例程序,它们可以辅助应用程序的开发。例如,:example:`peripherals/i2c/i2c_tools`:example:`wifi/iperf` 等等。
此外ESP-IDF 还提供了众多基于 ``console`` 组件的示例程序,它们可以辅助应用程序的开发。例如,:example:`peripherals/i2c/i2c_tools`:example:`wifi/iperf` 等等。
API 参考

View File

@ -152,7 +152,7 @@
通过重复调用 :cpp:func:`esp_event_handler_register_with`,可以将单个处理程序独立注册到多个事件中,且每次调用均可指定处理程序应执行的具体事件根基和事件 ID。
然而,在某些情况下,可能希望处理程序在以下情况时执行:
然而,在某些情况下,可能希望处理程序在以下情况时执行:
(1) 所有发布到循环的事件
(2) 特定基本标识符的所有事件
@ -182,7 +182,7 @@
处理程序自行注销
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
通常情况下,由事件循环运行的事件处理程序 *不允许在该事件循环上执行任何注册/注销活动* ,但允许处理程序自行注销。例如,可以执行以下操作:
通常情况下,由事件循环运行的事件处理程序 **不允许在该事件循环上执行任何注册/注销活动**,但允许处理程序自行注销。例如,可以执行以下操作:
.. code-block:: c

View File

@ -70,7 +70,7 @@
ETM 事件
---------
``esp_timer`` 的构建基于 *systimer* 硬件定时器,能够产生报警事件并与 :doc:`ETM </api-reference/peripherals/etm>` 模块交互。调用函数 :cpp:func:`esp_timer_new_etm_alarm_event` 以获取相应的 ETM 事件句柄。
``esp_timer`` 的构建基于 **systimer** 硬件定时器,能够产生报警事件并与 :doc:`ETM </api-reference/peripherals/etm>` 模块交互。调用函数 :cpp:func:`esp_timer_new_etm_alarm_event` 以获取相应的 ETM 事件句柄。
如需了解如何将 ETM 事件连接到相应 ETM 通道,请参阅 :doc:`ETM </api-reference/peripherals/etm>`

View File

@ -349,7 +349,7 @@ ESP-IDF 集成了用于请求 :ref:`堆内存信息 <heap-information>`、:ref:`
1. 构建程序并将其下载到目标设备,详情请参阅 :ref:`第五步:开始使用 ESP-IDF 吧 <get-started-build>`
2. 运行 OpenOCD (请参阅 :doc:`JTAG 调试 </api-guides/jtag-debugging/index>`)。
2. 运行 OpenOCD请参阅 :doc:`JTAG 调试 </api-guides/jtag-debugging/index>`)。
.. note::

View File

@ -51,9 +51,13 @@ DRAM
.. only:: esp32
.. note:: 有关 DRAM 使用限制的详细信息,请参阅 :ref:`dram`
.. note::
.. note:: 运行时可用的 DRAM 堆空间可能少于编译时计算的大小,因为启动时会在运行 FreeRTOS 调度程序之前从堆中分配部分内存,包括初始 FreeRTOS 任务的栈内存。
有关 DRAM 使用限制的详细信息,请参阅 :ref:`dram`
.. note::
运行时可用的 DRAM 堆空间可能少于编译时计算的大小,因为启动时会在运行 FreeRTOS 调度程序之前从堆中分配部分内存,包括初始 FreeRTOS 任务的栈内存。
IRAM
^^^^
@ -105,7 +109,7 @@ DMA 存储器
32 位可访问内存
^^^^^^^^^^^^^^^^^^^^^^^^
如果某个内存结构体仅以 32 位为单位寻址,例如一个整数或指针数组,则可以使用 ``MALLOC_CAP_32BIT`` 标志分配。通过这一方式,分配器能够在无法调用 malloc() 的情况下提供 IRAM 内存,从而充分利用 {IDF_TARGET_NAME} 中的所有可用内存。
如果某个内存结构体仅以 32 位为单位寻址,例如一个整数或指针数组,则可以使用 ``MALLOC_CAP_32BIT`` 标志分配。通过这一方式,分配器能够在无法调用 ``malloc()`` 的情况下提供 IRAM 内存,从而充分利用 {IDF_TARGET_NAME} 中的所有可用内存。
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA and SOC_CPU_HAS_FPU
@ -150,7 +154,9 @@ DMA 存储器
* :cpp:func:`heap_caps_aligned_alloc`
* :cpp:func:`heap_caps_aligned_free`
请注意,不建议使用此种方法。
.. note::
不建议使用此种方法。
堆跟踪及调试
------------------------

View File

@ -1,5 +1,6 @@
杂项系统 API
=========================
:link_to_translation:`en:[English]`
{IDF_TARGET_BASE_MAC_BLOCK: default="BLK1", esp32="BLK0"}
@ -36,7 +37,7 @@ MAC 地址
要获取特定接口(如 Wi-Fi、蓝牙、以太网的 MAC 地址,请调用函数 :cpp:func:`esp_read_mac`
在 ESP-IDF 中,各个网络接口的 MAC 地址是根据单个 *基准 MAC 地址 (Base MAC address)* 计算出来的。默认情况下使用乐鑫指定的基准 MAC 地址,该基准地址在产品生产过程中已预烧录至 {IDF_TARGET_NAME} eFuse。
在 ESP-IDF 中,各个网络接口的 MAC 地址是根据单个 **基准 MAC 地址 (Base MAC address)** 计算出来的。默认情况下使用乐鑫指定的基准 MAC 地址,该基准地址在产品生产过程中已预烧录至 {IDF_TARGET_NAME} eFuse。
.. only:: not esp32s2
@ -45,7 +46,7 @@ MAC 地址
:header-rows: 1
* - 接口
- MAC 地址(默认 4 个全局地址)
- MAC 地址(默认 4 个全局地址
- MAC 地址2 个全局地址)
* - Wi-Fi Station
- base_mac
@ -71,7 +72,7 @@ MAC 地址
:header-rows: 1
* - 接口
- MAC 地址(默认 2 个全局地址)
- MAC 地址(默认 2 个全局地址
- MAC 地址1 个全局地址)
* - Wi-Fi Station
- base_mac
@ -89,7 +90,9 @@ MAC 地址
.. only:: not SOC_EMAC_SUPPORTED
.. note:: {IDF_TARGET_NAME} 内部未集成以太网 MAC 地址,但仍可以计算得出该地址。不过,以太网 MAC 地址只能与外部以太网接口(如 SPI 以太网设备)一起使用,具体请参阅 :doc:`/api-reference/network/esp_eth`
.. note::
{IDF_TARGET_NAME} 内部未集成以太网 MAC 地址,但仍可以计算得出该地址。不过,以太网 MAC 地址只能与外部以太网接口(如 SPI 以太网设备)一起使用,具体请参阅 :doc:`/api-reference/network/esp_eth`
自定义接口 MAC
^^^^^^^^^^^^^^^^

View File

@ -1,5 +1,6 @@
空中升级 (OTA)
==============
:link_to_translation:`en:[English]`
OTA 流程概览
@ -7,7 +8,7 @@ OTA 流程概览
OTA 升级机制可以让设备在固件正常运行时根据接收数据(如通过 Wi-Fi 或蓝牙)进行自我更新。
要运行 OTA 机制,需配置设备的 :doc:`分区表 <../../api-guides/partition-tables>`,该分区表至少包括两个 OTA 应用程序分区(即 `ota_0``ota_1`)和一个 OTA 数据分区。
要运行 OTA 机制,需配置设备的 :doc:`分区表 <../../api-guides/partition-tables>`,该分区表至少包括两个 OTA 应用程序分区(即 ``ota_0````ota_1``)和一个 OTA 数据分区。
OTA 功能启动后,向当前未用于启动的 OTA 应用分区写入新的应用固件镜像。镜像验证后OTA 数据分区更新,指定在下一次启动时使用该镜像。
@ -35,7 +36,9 @@ OTA 数据分区的容量是 2 个 flash 扇区的大小0x2000 字节),
* 应用程序出现严重错误,无法继续工作,必须回滚到此前的版本,:cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot` 将正在运行的版本标记为 ``ESP_OTA_IMG_INVALID`` 然后复位。引导加载程序不会选取此版本,而是启动此前正常运行的版本。
* 如果 :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` 使能,则无需调用函数便可复位,回滚至之前的应用版本。
注解:应用程序的状态不是写到程序的二进制镜像,而是写到 ``otadata`` 分区。该分区有一个 ``ota_seq`` 计数器,该计数器是 OTA 应用分区的指针,指向下次启动时选取应用所在的分区 (ota_0, ota_1, ...)。
.. note::
应用程序的状态不是写到程序的二进制镜像,而是写到 ``otadata`` 分区。该分区有一个 ``ota_seq`` 计数器,该计数器是 OTA 应用分区的指针,指向下次启动时选取应用所在的分区 (ota_0, ota_1, ...)。
应用程序 OTA 状态
^^^^^^^^^^^^^^^^^
@ -73,7 +76,7 @@ Kconfig 中的 :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` 可以帮助用户
* 引导加载程序选取一个新版应用程序来引导,这样应用程序状态就不会设置为 ``ESP_OTA_IMG_INVALID````ESP_OTA_IMG_ABORTED``
* 引导加载程序检查所选取的新版应用程序,若状态设置为 ``ESP_OTA_IMG_NEW``,则写入 ``ESP_OTA_IMG_PENDING_VERIFY``。该状态表示,需确认应用程序的可操作性,如不确认,发生重启,则状态会重写为 ``ESP_OTA_IMG_ABORTED`` (见上文),该应用程序不可再启动,将回滚至上一版本。
* 新版应用程序启动,应进行自测。
* 若通过自测,则必须调用函数 :cpp:func:`esp_ota_mark_app_valid_cancel_rollback`,因为新版应用程序在等待确认其可操作性 (``ESP_OTA_IMG_PENDING_VERIFY`` 状态)
* 若通过自测,则必须调用函数 :cpp:func:`esp_ota_mark_app_valid_cancel_rollback`,因为新版应用程序在等待确认其可操作性 ``ESP_OTA_IMG_PENDING_VERIFY`` 状态)
* 若未通过自测,则调用函数 :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot`,回滚至之前能正常工作的应用程序版本,同时将无效的新版本应用程序设置为 ``ESP_OTA_IMG_INVALID``
* 如果新版应用程序可操作性没有确认,则状态一直为 ``ESP_OTA_IMG_PENDING_VERIFY``。下一次启动时,状态变更为 ``ESP_OTA_IMG_ABORTED``,阻止其再次启动,之后回滚到之前的版本。
@ -195,10 +198,10 @@ Kconfig 中的 :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` 可以帮助用户
具体可参考 :ref:`signed-app-verify`
OTA 工具 (otatool.py)
---------------------
OTA 工具 ``otatool.py``
----------------------------
`app_update` 组件中有 :component_file:`otatool.py<app_update/otatool.py>` 工具,用于在目标设备上完成下列 OTA 分区相关操作:
``app_update`` 组件中有 :component_file:`otatool.py<app_update/otatool.py>` 工具,用于在目标设备上完成下列 OTA 分区相关操作:
- 读取 otadata 分区 (read_otadata)
- 擦除 otadata 分区,将设备复位至工厂应用程序 (erase_otadata)
@ -212,7 +215,7 @@ OTA 工具 (otatool.py)
Python API
^^^^^^^^^^
首先,确保已导入 `otatool` 模块。
首先,确保已导入 ``otatool`` 模块。
.. code-block:: python
@ -255,7 +258,7 @@ Python API
命令行界面
^^^^^^^^^^
`otatool.py` 的命令行界面具有如下结构:
``otatool.py`` 的命令行界面具有如下结构:
.. code-block:: bash
@ -280,7 +283,7 @@ Python API
otatool.py --port "/dev/ttyUSB1" read_ota_partition --name=ota_3 --output=ota_3.bin
更多信息可用 `--help` 指令查看:
更多信息可用 ``--help`` 指令查看:
.. code-block:: bash

View File

@ -73,18 +73,18 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
{IDF_TARGET_NAME} 电源管理算法
--------------------------------
下表列出了启用动态调频时如何切换 CPU 频率和 APB 频率。可以使用 :cpp:func:`esp_pm_configure` :ref:`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ` 指定 CPU 最大频率。
下表列出了启用动态调频时如何切换 CPU 频率和 APB 频率。可以使用 :cpp:func:`esp_pm_configure`:ref:`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ` 指定 CPU 最大频率。
.. include:: inc/power_management_{IDF_TARGET_PATH_NAME}.rst
如果没有获取任何管理锁,调用 :cpp:func:`esp_pm_configure` 将启动 Light-sleep 模式。 Light-sleep 模式持续时间由以下因素决定:
如果没有获取任何管理锁,调用 :cpp:func:`esp_pm_configure` 将启动 Light-sleep 模式。Light-sleep 模式持续时间由以下因素决定:
- 处于阻塞状态的 FreeRTOS 任务数(有限超时)
- :doc:`高分辨率定时器 <esp_timer>` API 注册的计数器数量
也可以设置 Light-sleep 模式在最近事件(任务解除阻塞,或计时器超时)之前持续多久才唤醒芯片。
也可以设置 Light-sleep 模式在最近事件(任务解除阻塞,或计时器超时)之前的持续时间,在持续时间结束后再唤醒芯片。
为了跳过不必要的唤醒,可以将 `skip_unhandled_events` 选项设置为 true 来初始化 esp_timer。带有此标志的定时器不会唤醒系统,有助于减少功耗。
为了跳过不必要的唤醒,可以将 ``skip_unhandled_events`` 选项设置为 ``true`` 来初始化 ``esp_timer``。带有此标志的定时器不会唤醒系统,有助于减少功耗。
动态调频和外设驱动
@ -94,11 +94,11 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
以下外设不受 APB 频率变更的影响:
- **UART**:如果 REF_TICK 或者 XTAL 用作时钟源,则 UART 不受 APB 频率变更影响。请查看 :cpp:member:`uart_config_t::source_clk`
- **LEDC**:如果 REF_TICK 用作时钟源,则 LEDC 不受 APB 频率变更影响。请查看 :cpp:func:`ledc_timer_config` 函数。
- **RMT**:如果 REF_TICK 或者 XTAL 被用作时钟源,则 RMT 不受 APB 频率变更影响。请查看 :cpp:member:`rmt_config_t::flags` 以及 `RMT_CHANNEL_FLAGS_AWARE_DFS` 宏。
- **UART**:如果 ``REF_TICK`` 或者 XTAL 用作时钟源,则 UART 不受 APB 频率变更影响。请查看 :cpp:member:`uart_config_t::source_clk`
- **LEDC**:如果 ``REF_TICK`` 用作时钟源,则 LEDC 不受 APB 频率变更影响。请查看 :cpp:func:`ledc_timer_config` 函数。
- **RMT**:如果 ``REF_TICK`` 或者 XTAL 被用作时钟源,则 RMT 不受 APB 频率变更影响。请查看 :cpp:member:`rmt_config_t::flags` 以及 `RMT_CHANNEL_FLAGS_AWARE_DFS` 宏。
- **GPTimer**:如果 XTAL 用作时钟源,则 GPTimer 不受 APB 频率变更影响。请查看 :cpp:member:`gptimer_config_t::clk_src`
- **TSENS**XTAL 或 RTC_8M 用作时钟源,因此不受 APB 频率变化影响。
- **TSENS**XTAL 或 ``RTC_8M`` 用作时钟源,因此不受 APB 频率变化影响。
目前以下外设驱动程序可感知动态调频,并在调频期间使用 ``ESP_PM_APB_FREQ_MAX`` 锁:
@ -124,7 +124,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
- PCNT
- Sigma-delta
- 旧版定时器驱动Timer Group)
- 旧版定时器驱动 (Timer Group)
:SOC_MCPWM_SUPPORTED: - MCPWM
@ -135,8 +135,7 @@ Light-sleep 外设下电
{IDF_TARGET_NAME} 支持在 Light-sleep 时掉电外设的电源域.
如果在 menuconfig 中启用了 :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP`,在初始化外设时,驱动会将外设工作的寄存器上下文注册到休眠备份链表中,
在进入休眠前REG_DMA 外设会读取休眠备份链表中的配置根据链表中的配置将外设的寄存器上下文备份至内存REG_DMA 也会在唤醒时将上下文从内存恢复到外设寄存中。
如果在 menuconfig 中启用了 :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP`,在初始化外设时,驱动会将外设工作的寄存器上下文注册到休眠备份链表中,在进入休眠前,``REG_DMA`` 外设会读取休眠备份链表中的配置,根据链表中的配置将外设的寄存器上下文备份至内存,``REG_DMA`` 也会在唤醒时将上下文从内存恢复到外设寄存中。
目前 IDF 支持以下外设的 Light-sleep 上下文备份:
- INT_MTX
@ -168,7 +167,8 @@ Light-sleep 外设下电
- PARL_IO
- UART1
对于未支持 Light-sleep 上下文备份的外设,若启用了电源管理功能,应在外设工作时持有 `ESP_PM_NO_LIGHT_SLEEP` 锁以避免进入休眠导致外设工作上下文丢失。
对于未支持 Light-sleep 上下文备份的外设,若启用了电源管理功能,应在外设工作时持有 ``ESP_PM_NO_LIGHT_SLEEP`` 锁以避免进入休眠导致外设工作上下文丢失。
API 参考
-------------

View File

@ -1,5 +1,6 @@
睡眠模式
===========
:link_to_translation:`en:[English]`
{IDF_TARGET_SPI_POWER_DOMAIN:default="VDD_SPI", esp32="VDD_SDIO"}
@ -65,7 +66,7 @@ RTC 控制器中内嵌定时器,可用于在预定义的时间到达后唤醒
.. only:: SOC_ULP_SUPPORTED
关于 RTC 时钟选项的更多细节,请参考 *{IDF_TARGET_NAME} 技术参考手册* > *ULP 协处理器* [`PDF <{IDF_TARGET_TRM_EN_URL}#ulp>`__]。
关于 RTC 时钟选项的更多细节,请参考 **{IDF_TARGET_NAME} 技术参考手册** > **ULP 协处理器** [`PDF <{IDF_TARGET_TRM_EN_URL}#ulp>`__]。
在这种唤醒模式下,无需为睡眠模式中的 RTC 外设或内存供电。
@ -86,7 +87,7 @@ RTC 控制器中内嵌定时器,可用于在预定义的时间到达后唤醒
.. only:: SOC_PM_SUPPORT_EXT0_WAKEUP
外部唤醒 (ext0)
外部唤醒 (``ext0``)
^^^^^^^^^^^^^^^^^^^^^^
RTC IO 模块中包含这样一个逻辑——当某个 RTC GPIO 被设置为预定义的逻辑值时触发唤醒。RTC IO 是 RTC 外设电源域的一部分因此如果该唤醒源被请求RTC 外设将在 Deep-sleep 模式期间保持供电。
@ -99,14 +100,16 @@ RTC 控制器中内嵌定时器,可用于在预定义的时间到达后唤醒
可调用 :cpp:func:`esp_sleep_enable_ext0_wakeup` 函数来启用此唤醒源。
.. warning:: 从睡眠模式中唤醒后,用于唤醒的 IO pad 将被配置为 RTC IO。因此在将该 pad 用作数字 GPIO 之前,请调用 :cpp:func:`rtc_gpio_deinit` 函数对其进行重新配置。
.. warning::
从睡眠模式中唤醒后,用于唤醒的 IO pad 将被配置为 RTC IO。因此在将该 pad 用作数字 GPIO 之前,请调用 :cpp:func:`rtc_gpio_deinit` 函数对其进行重新配置。
.. only:: SOC_PM_SUPPORT_EXT1_WAKEUP
外部唤醒 (ext1)
外部唤醒 (``ext1``)
^^^^^^^^^^^^^^^^^^^^^^
RTC 控制器中包含使用多个 RTC GPIO 触发唤醒的逻辑。您可以从以下两个逻辑函数中选择其一,用于触发唤醒:
RTC 控制器中包含使用多个 RTC GPIO 触发唤醒的逻辑。从以下两个逻辑函数中任选其一,均可触发唤醒:
.. only:: esp32
@ -135,9 +138,10 @@ RTC 控制器中内嵌定时器,可用于在预定义的时间到达后唤醒
gpio_pulldown_en(gpio_num);
.. warning::
- 使用 EXT1 唤醒源时,用于唤醒的 IO pad 将被配置为 RTC IO。因此在将该 pad 用作数字 GPIO 之前,请调用 :cpp:func:`rtc_gpio_deinit` 函数对其进行重新配置。
- RTC 外设在默认情况下配置为断电,此时,唤醒 IO 在进入睡眠状态前将被设置为保持状态。因此,从 Light-sleep 状态唤醒芯片后,请调用 `rtc_gpio_hold_dis` 来禁用保持功能,以便对管脚进行重新配置。对于 Deep-sleep 唤醒,此问题已经在应用启动阶段解决。
- RTC 外设在默认情况下配置为断电,此时,唤醒 IO 在进入睡眠状态前将被设置为保持状态。因此,从 Light-sleep 状态唤醒芯片后,请调用 ``rtc_gpio_hold_dis`` 来禁用保持功能,以便对管脚进行重新配置。对于 Deep-sleep 唤醒,此问题已经在应用启动阶段解决。
可调用 :cpp:func:`esp_sleep_enable_ext1_wakeup` 函数来启用此唤醒源。
@ -170,9 +174,10 @@ RTC 控制器中内嵌定时器,可用于在预定义的时间到达后唤醒
可调用 :cpp:func:`esp_sleep_enable_gpio_wakeup` 函数来启用此唤醒源。
.. warning::
在进入 Light-sleep 模式前,请查看您将要驱动的 GPIO 管脚的电源域。如果有管脚属于 {IDF_TARGET_SPI_POWER_DOMAIN} 电源域,必须将此电源域配置为在睡眠期间保持供电。
例如,在 ESP32-WROOM-32 开发板上GPIO16 和 GPIO17 连接到 {IDF_TARGET_SPI_POWER_DOMAIN} 电源域。如果这两个管脚被配置为在睡眠期间保持高电平,则您需将对应电源域配置为保持供电。您可以使用函数 :cpp:func:`esp_sleep_pd_config()`::
在进入 Light-sleep 模式前,请查看将要驱动的 GPIO 管脚的电源域。如果有管脚属于 {IDF_TARGET_SPI_POWER_DOMAIN} 电源域,必须将此电源域配置为在睡眠期间保持供电。
例如,在 ESP32-WROOM-32 开发板上GPIO16 和 GPIO17 连接到 {IDF_TARGET_SPI_POWER_DOMAIN} 电源域。如果这两个管脚被配置为在睡眠期间保持高电平,则需将对应电源域配置为保持供电。为此,可以使用函数 :cpp:func:`esp_sleep_pd_config()`::
esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_ON);
@ -221,9 +226,9 @@ RTC 外设和内存断电
.. only:: not SOC_RTC_SLOW_MEM_SUPPORTED and SOC_RTC_FAST_MEM_SUPPORTED
{IDF_TARGET_NAME} 中只有 RTC 高速内存,因此,如果程序中的某些值被标记为 ``RTC_DATA_ATTR````RTC_SLOW_ATTR````RTC_FAST_ATTR`` 属性,那么所有这些值都将被存入 RTC 高速内存,默认情况下保持供电。如有需要,也可以使用函数 :cpp:func:`esp_sleep_pd_config` 对其进行修改。
{IDF_TARGET_NAME} 中只有 RTC 高速内存,因此,如果程序中的某些值被标记为 ``RTC_DATA_ATTR````RTC_SLOW_ATTR````RTC_FAST_ATTR`` 属性,那么所有这些值都将被存入 RTC 高速内存,默认情况下保持供电。如有需要,也可以使用函数 :cpp:func:`esp_sleep_pd_config` 对其进行修改。
Flash 断电
flash 断电
^^^^^^^^^^
默认情况下,调用函数 :cpp:func:`esp_light_sleep_start` 后, flash **不会** 断电,因为在 sleep 过程中断电 flash 存在风险。具体而言flash 断电需要时间,但是在此期间,系统有可能被唤醒,导致 flash 重新被上电。此时,断电尚未完成又重新上电的硬件行为有可能导致 flash 无法正常工作。
@ -231,9 +236,10 @@ Flash 断电
理论上讲,在 flash 完全断电后可以仅唤醒系统,然而现实情况是 flash 断电所需的时间很难预测。如果用户为 flash 供电电路添加了滤波电容,断电所需时间可能会更长。此外,即使可以预知 flash 彻底断电所需的时间,有时也不能通过设置足够长的睡眠时间来确保 flash 断电的安全(比如,突发的异步唤醒源会使得实际的睡眠时间不可控)。
.. warning::
如果在 flash 的供电电路上添加了滤波电容,那么应当尽一切可能避免 flash 断电。
因为这些不可控的因素ESP-IDF 很难保证 flash断电的绝对安全。因此 ESP-IDF 不推荐用户断电 flash。对于一些功耗敏感型应用可以通过设置 Kconfig 配置项 :ref:`CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND` 来减少 light sleep 期间 flash 的功耗。这种方式在几乎所有场景下都要比断电 flash 更好,兼顾了安全性和功耗。
因为这些不可控的因素ESP-IDF 很难保证 flash 断电的绝对安全。因此 ESP-IDF 不推荐用户断电 flash。对于一些功耗敏感型应用可以通过设置 Kconfig 配置项 :ref:`CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND` 来减少 light sleep 期间 flash 的功耗。这种方式在几乎所有场景下都要比断电 flash 更好,兼顾了安全性和功耗。
.. only:: SOC_SPIRAM_SUPPORTED
@ -283,10 +289,8 @@ Flash 断电
应用程序通过 API :cpp:func:`esp_light_sleep_start`:cpp:func:`esp_deep_sleep_start` 进入 Light-sleep 或 Deep-sleep 模式。此时,系统将按照被请求的唤醒源和断电选项配置有关的 RTC 控制器参数。
允许在未配置唤醒源的情况下进入睡眠模式。在此情况下,芯片将一直处于睡眠模式,直到从外部被复位。
UART 输出处理
^^^^^^^^^^^^^^^^^^^^
@ -309,7 +313,6 @@ UART 输出处理
对于 ext1 唤醒源,可以调用函数 :cpp:func:`esp_sleep_get_ext1_wakeup_status` 来确认触发唤醒的触摸管脚。
应用程序示例
-------------------

View File

@ -56,7 +56,7 @@ RTC 定时器有以下时钟源:
获取当前时间
--------------
要获取当前时间,请使用 POSIX 函数 ``gettimeofday()``。此外,也可以使用以下标准 C 库函数来获取时间并对其进行操作:
要获取当前时间,请使用 POSIX 函数 ``gettimeofday()``。此外,也可以使用以下标准 C 库函数来获取时间并对其进行操作:
.. code-block:: bash
@ -138,7 +138,7 @@ lwIP SNTP 库可在下列任一同步模式下工作:
如需查看示例代码,请前往 :example:`protocols/sntp` 目录。该目录下的示例展示了如何基于 lwIP SNTP 库实现时间同步。
也可以直接使用 lwIP API但请务必注意线程安全。线程安全的 API 如下:
也可以直接使用 lwIP API但请务必注意线程安全。线程安全的 API 如下:
- :cpp:func:`sntp_set_time_sync_notification_cb` 用于设置通知时间同步过程的回调函数。
- :cpp:func:`sntp_get_sync_status`:cpp:func:`sntp_set_sync_status` 用于获取/设置时间同步状态。

View File

@ -1,26 +1,31 @@
ULP RISC-V 协处理器编程
==================================
:link_to_translation:`en:[English]`
ULP RISC-V 协处理器是 ULP 的一种变体,用于 {IDF_TARGET_NAME}。与 ULP FSM 类似ULP RISC-V 协处理器可以在主 CPU 处于低功耗模式时执行传感器读数等任务。其与 ULP FSM 的主要区别在于ULP RISC-V 可以通过标准 GNU 工具使用 C 语言进行编程。ULP RISC-V 可以访问 RTC_SLOW_MEM 内存区域及 RTC_CNTL、RTC_IO、SARADC 等外设的寄存器。RISC-V 处理器是一种 32 位定点处理器,指令集基于 RV32IMC包括硬件乘除法和压缩指令。
ULP RISC-V 协处理器是 ULP 的一种变体,用于 {IDF_TARGET_NAME}。与 ULP FSM 类似ULP RISC-V 协处理器可以在主 CPU 处于低功耗模式时执行传感器读数等任务。其与 ULP FSM 的主要区别在于ULP RISC-V 可以通过标准 GNU 工具使用 C 语言进行编程。ULP RISC-V 可以访问 RTC_SLOW_MEM 内存区域及 ``RTC_CNTL````RTC_IO````SARADC`` 等外设的寄存器。RISC-V 处理器是一种 32 位定点处理器,指令集基于 RV32IMC包括硬件乘除法和压缩指令。
安装 ULP RISC-V 工具链
-----------------------------------
ULP RISC-V 协处理器代码以 C 语言(或汇编语言)编写,使用基于 GCC 的 RISC-V 工具链进行编译。
如果您已依照 :doc:`快速入门指南 <../../../get-started/index>` 中的介绍安装好了 ESP-IDF 及其 CMake 构建系统,那么 ULP RISC-V 工具链已经被默认安装到了的开发环境中。
如果依照 :doc:`快速入门指南 <../../../get-started/index>` 中的介绍安装好了 ESP-IDF 及其 CMake 构建系统,那么 ULP RISC-V 工具链已经被默认安装到了的开发环境中。
.. note:: 在早期版本的 ESP-IDF 中RISC-V 工具链具有不同的名称:`riscv-none-embed-gcc`
.. note::
在早期版本的 ESP-IDF 中RISC-V 工具链具有不同的名称:``riscv-none-embed-gcc``
编译 ULP RISC-V 代码
-----------------------------
要将 ULP RISC-V 代码编译为某组件的一部分,必须执行以下步骤:
1. ULP RISC-V 代码以 C 语言或汇编语言编写(必须使用 `.S` 扩展名),必须放在组件目录中一个独立的目录中,例如 `ulp/`
1. ULP RISC-V 代码以 C 语言或汇编语言编写(必须使用 ``.S`` 扩展名),必须放在组件目录中一个独立的目录中,例如 ``ulp/``
.. note:: 当注册组件时(通过 ``idf_component_register``),该目录不应被添加至 ``SRC_DIRS`` 参数,因为目前该步骤需用于 ULP FSM。如何正确添加 ULP 源文件,请见以下步骤。
.. note::
当注册组件时(通过 ``idf_component_register``),该目录不应被添加至 ``SRC_DIRS`` 参数,因为目前该步骤需用于 ULP FSM。如何正确添加 ULP 源文件,请见以下步骤。
2. 注册后从组件 CMakeLists.txt 中调用 ``ulp_embed_binary`` 示例如下::
@ -35,11 +40,11 @@ ULP RISC-V 协处理器代码以 C 语言(或汇编语言)编写,使用基
``ulp_embed_binary`` 的第一个参数指定生成的 ULP 二进制文件名。生成的其他文件,如 ELF 文件、.map 文件、头文件和链接器导出文件等也可使用此名称。第二个参数指定 ULP 源文件。最后,第三个参数指定组件源文件列表,其中包括生成的头文件。此列表用以正确构建依赖,并确保在构建过程中先生成后编译包含头文件的源文件。请参考下文,查看为 ULP 应用程序生成的头文件等相关概念。
3. 使用常规方法(例如 `idf.py app`)编译应用程序。
3. 使用常规方法(例如 ``idf.py app``)编译应用程序。
在内部,构建系统将按照以下步骤编译 ULP 程序:
1. **通过 C 编译器和汇编器运行每个源文件。** 此步骤在组件编译目录中生成目标文件(.obj.c 或 .obj.S取决于处理的源文件
1. **通过 C 编译器和汇编器运行每个源文件。** 此步骤在组件编译目录中生成目标文件( ``.obj.c````.obj.S``,取决于处理的源文件)。
2. **通过 C 预处理器运行链接器脚本模版。** 模版位于 ``components/ulp/ld`` 目录中。
@ -115,7 +120,7 @@ ULP 中的所有硬件指令都不支持互斥,所以 Lock API 需通过一种
要运行 ULP RISC-V 程序,主程序需要调用 :cpp:func:`ulp_riscv_load_binary` 函数,将 ULP 程序加载到 RTC 内存中,然后调用 :cpp:func:`ulp_riscv_run` 函数,启动 ULP RISC-V 程序。
注意,必须在 menuconfig 中启用 `CONFIG_ULP_COPROC_ENABLED``CONFIG_ULP_COPROC_TYPE_RISCV` 选项,以便正常运行 ULP RISC-V 程序。``RTC slow memory reserved for coprocessor`` 选项设置的值必须足够存储 ULP RISC-V 代码和数据。如果应用程序组件包含多个 ULP 程序RTC 内存必须足以容纳最大的程序。
注意,必须在 menuconfig 中启用 ``CONFIG_ULP_COPROC_ENABLED````CONFIG_ULP_COPROC_TYPE_RISCV`` 选项,以便正常运行 ULP RISC-V 程序。``RTC slow memory reserved for coprocessor`` 选项设置的值必须足够存储 ULP RISC-V 代码和数据。如果应用程序组件包含多个 ULP 程序RTC 内存必须足以容纳最大的程序。
每个 ULP RISC-V 程序均以二进制 BLOB 的形式嵌入到 ESP-IDF 应用程序中。应用程序可以引用此 BLOB并以下面的方式加载此 BLOB假设 ULP_APP_NAME 已被定义为 ``ulp_app_name``
@ -162,9 +167,13 @@ RTC I2C 控制器提供了在 RTC 电源域中作为 I2C 主机的功能。ULP R
初始化 RTC I2C 控制器之后,请务必先用 :cpp:func:`ulp_riscv_i2c_master_set_slave_addr` API 将 I2C 从机设备地址编入程序,再执行读写操作。
.. note:: RTC I2C 外设首先将检查 :cpp:func:`ulp_riscv_i2c_master_set_slave_reg_addr` API 是否将从机子寄存器地址编入程序。如未编入I2C 外设将以 ``SENS_SAR_I2C_CTRL_REG[18:11]`` 作为后续读写操作的子寄存器地址。这可能会导致 RTC I2C 外设与某些无需对子寄存器进行配置的 I2C 设备或传感器不兼容。
.. note::
.. note:: 在主 CPU 访问 RTC I2C 外设和 ULP RISC-V 内核访问 RTC I2C 外设之间,未提供硬件原子操作的正确性保护,因此请勿让两个内核同时访问外设。
RTC I2C 外设首先将检查 :cpp:func:`ulp_riscv_i2c_master_set_slave_reg_addr` API 是否将从机子寄存器地址编入程序。如未编入I2C 外设将以 ``SENS_SAR_I2C_CTRL_REG[18:11]`` 作为后续读写操作的子寄存器地址。这可能会导致 RTC I2C 外设与某些无需对子寄存器进行配置的 I2C 设备或传感器不兼容。
.. note::
在主 CPU 访问 RTC I2C 外设和 ULP RISC-V 内核访问 RTC I2C 外设之间,未提供硬件原子操作的正确性保护,因此请勿让两个内核同时访问外设。
如果基于 RTC I2C 的 ULP RISC-V 程序未按预期运行,可以进行以下完整性检查排查问题:
@ -174,22 +183,22 @@ RTC I2C 控制器提供了在 RTC 电源域中作为 I2C 主机的功能。ULP R
* 如果 I2C 从机设备或传感器不需要子寄存器地址进行配置,它可能与 RTC I2C 外设不兼容。请参考前文注意事项。
* 如果 RTC 驱动程序在主 CPU 上运行时出现 `Write Failed!``Read Failed!` 的错误日志,检查是否出现以下情况:
* 如果 RTC 驱动程序在主 CPU 上运行时出现 ``Write Failed!````Read Failed!`` 的错误日志,检查是否出现以下情况:
* I2C 从机设备或传感器与乐鑫 SoC 上的标准 I2C 主机设备一起正常工作,说明 I2C 从机设备本身没有问题。
* 如果 RTC I2C 中断状态日志报告 `TIMEOUT` 错误或 `ACK` 错误,则通常表示 I2C 设备未响应 RTC I2C 控制器发出的 `START` 条件。如果 I2C 从机设备未正确连接到控制器管脚或处于异常状态,则可能会发生这种情况。在进行后续操作之前,请确保 I2C 从机设备状态良好且连接正确。
* 如果 RTC I2C 中断状态日志报告 ``TIMEOUT`` 错误或 ``ACK`` 错误,则通常表示 I2C 设备未响应 RTC I2C 控制器发出的 ``START`` 条件。如果 I2C 从机设备未正确连接到控制器管脚或处于异常状态,则可能会发生这种情况。在进行后续操作之前,请确保 I2C 从机设备状态良好且连接正确。
* 如果 RTC I2C 中断日志没有报告任何错误状态,则可能表示驱动程序接收 I2C 从机设备数据时速度较慢。这可能是由于 RTC I2C 控制器没有 TX/RX FIFO 来存储多字节数据,而是依赖于使用中断状态轮询机制来进行单字节传输。通过在外设的初始化配置参数中设置 SCL 低周期和 SCL 高周期,可以尽量提高外设 SCL 时钟的运行速度,在一定程度上缓解这一问题。
* **还可以检查在没有任何 ULP RISC-V 代码干扰和任何睡眠模式未被激活的情况下RTC I2C 控制器是否仅在主 CPU 上正常工作。** RTC I2C 外设在此基本配置下应该正常工作,这样可以排除 ULP 或睡眠模式导致的潜在问题。
* **还可以检查在没有任何 ULP RISC-V 代码干扰和任何睡眠模式未被激活的情况下RTC I2C 控制器是否仅在主 CPU 上正常工作。** RTC I2C 外设在此基本配置下应该正常工作,这样可以排除 ULP 或睡眠模式导致的潜在问题。
调试 ULP RISC-V 程序
----------------------------------
在对 ULP RISC-V 进行配置时,若程序未按预期运行,有时很难找出的原因。因为其内核的简单性,许多标准的调试方法如 JTAG 或 ``printf`` 无法使用。
以下方法可以帮助您调试 ULP RISC-V 程序:
以下方法可以调试 ULP RISC-V 程序:
* 通过共享变量查看程序状态:如 :ref:`ulp-riscv-access-variables` 中所述,主 CPU 以及 ULP 内核都可以轻松访问 RTC 内存中的全局变量。通过 ULP 向该变量中写入状态信息,然后通过主 CPU 读取状态信息,可帮助您了解 ULP 内核的状态。该方法的缺点在于它要求主 CPU 一直处于唤醒状态,但现实情况可能并非如此。有时,保持主 CPU 处于唤醒状态还可能会掩盖一些问题,因为某些问题可能仅在特定电源域断电时才会出现。
* 通过共享变量查看程序状态:如 :ref:`ulp-riscv-access-variables` 中所述,主 CPU 以及 ULP 内核都可以轻松访问 RTC 内存中的全局变量。通过 ULP 向该变量中写入状态信息,然后通过主 CPU 读取状态信息,有助于了解 ULP 内核的状态。该方法的缺点在于它要求主 CPU 一直处于唤醒状态,但现实情况可能并非如此。有时,保持主 CPU 处于唤醒状态还可能会掩盖一些问题,因为某些问题可能仅在特定电源域断电时才会出现。
* 使用 bit-banged UART 驱动程序打印ULP RISC-V 组件中有一个低速 bit-banged UART TX 驱动程序,可用于打印独立于主 CPU 状态的信息。有关如何使用此驱动程序的示例,请参阅 :example:`system/ulp/ulp_riscv/uart_print`

View File

@ -3,18 +3,18 @@ ULP 协处理器编程
:link_to_translation:`en:[English]`
ULPUltra Low Power超低功耗协处理器是一种简单的有限状态机 (FSM),可以在主处理器处于深度睡眠模式时,使用 ADC、温度传感器和外部 I2C 传感器执行测量操作。ULP 协处理器可以访问 RTC_SLOW_MEM 内存区域及 RTC_CNTL、RTC_IO、SARADC 外设中的寄存器。ULP 协处理器使用 32 位固定宽度的指令32 位内存寻址,配备 4 个 16 位通用寄存器。在 ESP-IDF 项目中,此协处理器被称作 `ULP FSM`
ULPUltra Low Power超低功耗协处理器是一种简单的有限状态机 (FSM),可以在主处理器处于深度睡眠模式时,使用 ADC、温度传感器和外部 I2C 传感器执行测量操作。ULP 协处理器可以访问 ``RTC_SLOW_MEM`` 内存区域及 ``RTC_CNTL````RTC_IO````SARADC`` 外设中的寄存器。ULP 协处理器使用 32 位固定宽度的指令32 位内存寻址,配备 4 个 16 位通用寄存器。在 ESP-IDF 项目中,此协处理器被称作 ``ULP FSM``
.. only:: esp32s2 or esp32s3
{IDF_TARGET_NAME} 基于 RISC-V 指令集架构提供另一种 ULP 协处理器。关于 `ULP RISC-V` 的详细信息,请参考 :doc:`ULP-RISC-V Coprocessor <../../../api-reference/system/ulp-risc-v>`
{IDF_TARGET_NAME} 基于 RISC-V 指令集架构提供另一种 ULP 协处理器。关于 ``ULP RISC-V`` 的详细信息,请参考 :doc:`ULP-RISC-V Coprocessor <../../../api-reference/system/ulp-risc-v>`
安装工具链
----------
ULP FSM 协处理器代码由汇编语言编写,使用 `binutils-esp32ulp 工具链`_ 进行编译。
如果您已经按照 :doc:`快速入门指南 <../../../get-started/index>` 中的介绍安装好了 ESP-IDF 及其 CMake 构建系统,那么 ULP 工具链已经被默认安装到了您的开发环境中。
如果按照 :doc:`快速入门指南 <../../../get-started/index>` 中的介绍安装好了 ESP-IDF 及其 CMake 构建系统,那么 ULP 工具链已经默认安装到了你的开发环境中。
编写 ULP FSM
-------------------
@ -32,9 +32,11 @@ ULP FSM 协处理器代码由汇编语言编写,使用 `binutils-esp32ulp 工
若需要将 ULP FSM 代码编译为某组件的一部分,则必须执行以下步骤:
1. 用汇编语言编写的 ULP FSM 代码必须导入到一个或多个 `.S` 扩展文件中,且这些文件必须放在组件目录中一个独立的目录中,例如 `ulp/`
1. 用汇编语言编写的 ULP FSM 代码必须导入到一个或多个 ``.S`` 扩展文件中,且这些文件必须放在组件目录中一个独立的目录中,例如 ``ulp/``
.. note:: 在注册组件(通过 ``idf_component_register``)时,不应将该目录添加到 ``SRC_DIRS`` 参数中。因为 ESP-IDF 构建系统将基于文件扩展名编译在 ``SRC_DIRS`` 中搜索到的文件。对于 ``.S`` 文件,使用的是 ``{IDF_TARGET_TOOLCHAIN_PREFIX}-as`` 汇编器。但这并不适用于 ULP FSM 程序集文件,因此体现这种区别最简单的方式就是将 ULP FSM 程序集文件放到单独的目录中。同样ULP FSM 程序集源文件也 **不应该** 添加到 ``SRCS`` 中。请参考如下步骤,查看如何正确添加 ULP FSM 程序集源文件。
.. note::
在注册组件(通过 ``idf_component_register``)时,不应将该目录添加到 ``SRC_DIRS`` 参数中。因为 ESP-IDF 构建系统将基于文件扩展名编译在 ``SRC_DIRS`` 中搜索到的文件。对于 ``.S`` 文件,使用的是 ``{IDF_TARGET_TOOLCHAIN_PREFIX}-as`` 汇编器。但这并不适用于 ULP FSM 程序集文件,因此体现这种区别最简单的方式就是将 ULP FSM 程序集文件放到单独的目录中。同样ULP FSM 程序集源文件也 **不应该** 添加到 ``SRCS`` 中。请参考如下步骤,查看如何正确添加 ULP FSM 程序集源文件。
2. 注册后从组件 CMakeLists.txt 中调用 ``ulp_embed_binary`` 示例如下::
@ -49,7 +51,7 @@ ULP FSM 协处理器代码由汇编语言编写,使用 `binutils-esp32ulp 工
``ulp_embed_binary`` 的第一个参数为 ULP 二进制文件命名。指定的此名称也用于生成的其他文件ELF 文件、.map 文件、头文件和链接器导出文件。第二个参数指定 ULP FSM 程序集源文件。最后,第三个参数指定组件源文件列表,其中包括被生成的头文件。此列表用以建立正确的依赖项,并确保在编译这些文件之前先创建生成的头文件。有关 ULP FSM 应用程序生成的头文件等相关概念,请参考下文。
3. 使用常规方法(例如 `idf.py app`)编译应用程序。
3. 使用常规方法(例如 ``idf.py app``)编译应用程序。
在内部,构建系统将按照以下步骤编译 ULP FSM 程序:
@ -65,7 +67,7 @@ ULP FSM 协处理器代码由汇编语言编写,使用 `binutils-esp32ulp 工
6. 使用 ``esp32ulp-elf-nm`` 在 ELF 文件中 **生成全局符号列表** (``ulp_app_name.sym``)。
7. **创建 LD 导出脚本和头文件** (``ulp_app_name.ld````ulp_app_name.h``),包含来自 ``ulp_app_name.sym`` 的符号。此步骤可借助 ``esp32ulp_mapgen.py`` 工具来完成。
7. **创建 LD 导出脚本和头文件** ``ulp_app_name.ld````ulp_app_name.h``),包含来自 ``ulp_app_name.sym`` 的符号。此步骤可借助 ``esp32ulp_mapgen.py`` 工具来完成。
8. **将生成的二进制文件添加到要嵌入应用程序的二进制文件列表中。**