Merge branch 'docs/s3_not_updated_docs' into 'master'

docs: update docs with S3 specific information.

Closes IDF-3272, IDF-3279, IDF-3283, IDF-3290, and IDF-3303

See merge request espressif/esp-idf!16635
This commit is contained in:
Marius Vikhammer 2022-01-06 04:44:27 +00:00
commit 5d47efb72d
26 changed files with 580 additions and 577 deletions

View File

@ -31,7 +31,7 @@ Concepts
- "components" are modular pieces of standalone code which are compiled into static libraries (.a files) and linked into an app. Some are provided by ESP-IDF itself, others may be sourced from other places.
- "Target" is the hardware for which an application is built. At the moment, ESP-IDF supports ``esp32``, ``esp32s2`` and ``esp32c3`` targets.
- "Target" is the hardware for which an application is built. A full list of supported targets in your version if ESP-IDF can be seen by running `idf.py --list-targets`.
Some things are not part of the project:
@ -47,15 +47,15 @@ Using the Build System
idf.py
------
The ``idf.py`` command line tool provides a front-end for easily managing your project builds. It manages the following tools:
The ``idf.py`` command-line tool provides a front-end for easily managing your project builds. It manages the following tools:
- CMake_, which configures the project to be built
- A command line build tool (either Ninja_ build or `GNU Make`)
- A command-line build tool (either Ninja_ build or `GNU Make`)
- `esptool.py`_ for flashing the target.
The :ref:`getting started guide <get-started-configure>` contains a brief introduction to how to set up ``idf.py`` to configure, build, and flash projects.
``idf.py`` should be run in an ESP-IDF "project" directory, ie one containing a ``CMakeLists.txt`` file. Older style projects with a Makefile will not work with ``idf.py``.
``idf.py`` should be run in an ESP-IDF "project" directory, i.e. one containing a ``CMakeLists.txt`` file. Older style projects with a Makefile will not work with ``idf.py``.
Type ``idf.py --help`` for a list of commands. Here are a summary of the most useful ones:
@ -1060,11 +1060,7 @@ The subproject is inserted as an external project from the top-level project, by
Selecting the Target
====================
ESP-IDF supports multiple targets (chips). The identifiers used for each chip are as follows:
* ``esp32`` — for ESP32-D0WD, ESP32-D2WD, ESP32-S0WD (ESP-SOLO), ESP32-U4WDH, ESP32-PICO-D4
* ``esp32s2``— for ESP32-S2
* ``esp32c3``— for ESP32-C3
ESP-IDF supports multiple targets (chips). A full list of supported targets in your version if ESP-IDF can be seen by running `idf.py --list-targets`.
To select the target before building the project, use ``idf.py set-target <target>`` command, for example::

View File

@ -1,7 +1,7 @@
Core Dump
=========
{IDF_TARGET_ROM_ELF:default="https://dl.espressif.com/dl/esp32_rom.elf", esp32="https://dl.espressif.com/dl/esp32_rom.elf", esp32s2="https://dl.espressif.com/dl/esp32s2_rom.elf", esp32c3="https://dl.espressif.com/dl/esp32c3_rev3_rom.elf"}
{IDF_TARGET_ROM_ELF:default="https://dl.espressif.com/dl/esp32_rom.elf", esp32="https://dl.espressif.com/dl/esp32_rom.elf", esp32s2="https://dl.espressif.com/dl/esp32s2_rom.elf", esp32s3="https://dl.espressif.com/dl/esp32s3_rom.elf", esp32c3="https://dl.espressif.com/dl/esp32c3_rev3_rom.elf"}
Overview
--------
@ -172,7 +172,7 @@ Generic command syntax: ``espcoredump.py [options] command [args]``
:Script Options:
--chip {auto,esp32,esp32s2,esp32c3}
--chip {auto,esp32,esp32s2,esp32s3,esp32c3}
Target chip type. Default value is "auto"
--port PORT, -p PORT Serial port device. Either "chip" or "port" need to be specified to determine the port when you have multi-target connected at the same time.

View File

@ -104,11 +104,11 @@ To reduce wake-up time use the `CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` K
CRC Check For Wake Stubs
------------------------
.. only:: SOC_PM_SUPPORT_DEEPSLEEP_VERIFY_STUB_ONLY
.. only:: SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
During deep sleep, only the wake stubs area of RTC Fast memory is validated with CRC. When {IDF_TARGET_NAME} wakes up from deep sleep, the wake stubs area is validated again. If the validation passes, the wake stubs code will be executed. Otherwise, the normal initialization, bootloader, and esp-idf codes will be executed.
.. only:: not SOC_PM_SUPPORT_DEEPSLEEP_VERIFY_STUB_ONLY
.. only:: not SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
During deep sleep, all RTC Fast memory areas will be validated with CRC. When {IDF_TARGET_NAME} wakes up from deep sleep, the RTC fast memory will be validated with CRC again. If the validation passes, the wake stubs code will be executed. Otherwise, the normal initialization, bootloader and esp-idf codes will be executed.

View File

@ -2,11 +2,6 @@
Device Firmware Upgrade through USB
***********************************************
.. only:: esp32
.. note::
Device Firmware Upgrade through USB is not supported with ESP32 chips.
Device Firmware Upgrade (DFU) is a mechanism for upgrading the firmware of devices through Universal Serial Bus (USB).
DFU is supported by {IDF_TARGET_NAME} chips. The necessary connections for the USB peripheral are shown in the following table.

View File

@ -8,8 +8,9 @@ Support for External RAM
Introduction
============
{IDF_TARGET_PSRAM_SIZE:default="Value not updated", esp32="4 MB", esp32s2="10.5 MB", esp32s3="16 MB"}
{IDF_TARGET_NAME} has a few hundred kilobytes of internal RAM, residing on the same die as the rest of the chip components. It can be insufficient for some purposes, so {IDF_TARGET_NAME} has the ability to also use up to 4 MB of external SPI RAM memory. The external memory is incorporated in the memory map and, with certain restrictions, is usable in the same way as internal data RAM.
{IDF_TARGET_NAME} has a few hundred kilobytes of internal RAM, residing on the same die as the rest of the chip components. It can be insufficient for some purposes, so {IDF_TARGET_NAME} has the ability to also use up to {IDF_TARGET_PSRAM_SIZE} of external SPI RAM memory. The external memory is incorporated in the memory map and, with certain restrictions, is usable in the same way as internal data RAM.
Hardware
@ -36,19 +37,20 @@ ESP-IDF fully supports the use of external RAM in applications. Once the externa
* :ref:`external_ram_config_memory_map`
* :ref:`external_ram_config_capability_allocator`
* :ref:`external_ram_config_malloc` (default)
:esp32: * :ref:`external_ram_config_bss`
:esp32 or esp32s2: * :ref:`external_ram_config_bss`
:esp32: * :ref:`external_ram_config_noinit`
.. _external_ram_config_memory_map:
Integrate RAM into the {IDF_TARGET_NAME} Memory Map
---------------------------------------------------
{IDF_TARGET_PSRAM_ADDR_START:default="Value not updated", esp32="0x3F800000", esp32s2="0x3F500000", esp32s3="0x3D000000"}
Select this option by choosing "Integrate RAM into memory map" from :ref:`CONFIG_SPIRAM_USE`.
This is the most basic option for external SPI RAM integration. Most likely, you will need another, more advanced option.
During the ESP-IDF startup, external RAM is mapped into the data address space, starting at address 0x3F800000 (byte-accessible). The length of this region is the same as the SPI RAM size (up to the limit of 4 MB).
During the ESP-IDF startup, external RAM is mapped into the data address space, starting at address {IDF_TARGET_PSRAM_ADDR_START} (byte-accessible). The length of this region is the same as the SPI RAM size (up to the limit of {IDF_TARGET_PSRAM_SIZE}).
Applications can manually place data in external memory by creating pointers to this region. So if an application uses external memory, it is responsible for all management of the external SPI RAM: coordinating buffer usage, preventing corruption, etc.
@ -60,7 +62,7 @@ Add External RAM to the Capability Allocator
Select this option by choosing "Make RAM allocatable using heap_caps_malloc(..., MALLOC_CAP_SPIRAM)" from :ref:`CONFIG_SPIRAM_USE`.
When enabled, memory is mapped to address 0x3F800000 and also added to the :doc:`capabilities-based heap memory allocator </api-reference/system/mem_alloc>` using ``MALLOC_CAP_SPIRAM``.
When enabled, memory is mapped to address {IDF_TARGET_PSRAM_ADDR_START} and also added to the :doc:`capabilities-based heap memory allocator </api-reference/system/mem_alloc>` using ``MALLOC_CAP_SPIRAM``.
To allocate memory from external RAM, a program should call ``heap_caps_malloc(size, MALLOC_CAP_SPIRAM)``. After use, this memory can be freed by calling the normal ``free()`` function.
@ -85,7 +87,7 @@ If a suitable block of preferred internal/external memory is not available, the
Because some buffers can only be allocated in internal memory, a second configuration item :ref:`CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL` defines a pool of internal memory which is reserved for *only* explicitly internal allocations (such as memory for DMA use). Regular ``malloc()`` will not allocate from this pool. The :ref:`MALLOC_CAP_DMA <dma-capable-memory>` and ``MALLOC_CAP_INTERNAL`` flags can be used to allocate memory from this pool.
.. only:: esp32
.. only:: esp32 or esp32s2
.. _external_ram_config_bss:
@ -94,7 +96,7 @@ Because some buffers can only be allocated in internal memory, a second configur
Enable this option by checking :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY`. This configuration setting is independent of the other three.
If enabled, a region of the address space starting from 0x3F800000 will be used to store zero-initialized data (BSS segment) from the lwIP, net80211, libpp, and bluedroid ESP-IDF libraries.
If enabled, a region of the address space starting from {IDF_TARGET_PSRAM_ADDR_START} will be used to store zero-initialized data (BSS segment) from the lwIP, net80211, libpp, and bluedroid ESP-IDF libraries.
Additional data can be moved from the internal BSS segment to external RAM by applying the macro ``EXT_RAM_ATTR`` to any static declaration (which is not initialized to a non-zero value).
@ -104,6 +106,9 @@ Because some buffers can only be allocated in internal memory, a second configur
Remaining external RAM can also be added to the capability heap allocator using the method shown above.
.. only:: esp32
.. _external_ram_config_noinit:
Allow .noinit Segment to be Placed in External Memory
@ -135,7 +140,7 @@ Failure to initialize
By default, failure to initialize external RAM will cause the ESP-IDF startup to abort. This can be disabled by enabling the config item :ref:`CONFIG_SPIRAM_IGNORE_NOTFOUND`.
.. only:: esp32
.. only:: esp32 or esp32s2
If :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` is enabled, the option to ignore failure is not available as the linker will have assigned symbols to external memory addresses at link time.

View File

@ -1,147 +1,192 @@
ESP-IDF FreeRTOS SMP Changes
============================
ESP-IDF FreeRTOS (SMP)
======================
.. 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.
This document describes the API and behavioral differences between Vanilla FreeRTOS and ESP-IDF FreeRTOS that were made in order to support Symmetric Multiprocessing (SMP). This document is split into the following parts.
.. contents:: Contents
:depth: 3
.. ---------------------------------------------------- Overview -------------------------------------------------------
Overview
--------
.. only:: not CONFIG_FREERTOS_UNICORE
The original FreeRTOS (hereinafter referred to as Vanilla FreeRTOS) is a small and efficient Real Time Operating System supported on many single-core MCUs and SoCs. However, numerous ESP targets (such as the ESP32 and ESP32-S3) are capable of dual core symmetric multiprocessing (SMP). Therefore, the version of FreeRTOS used in ESP-IDF (hereinafter referred to as ESP-IDF FreeRTOS) is a modified version of Vanilla FreeRTOS v10.4.3. Theses modifications allow ESP-IDF FreeRTOS to utilize the dual core SMP capabilities of ESP SoCs.
The vanilla FreeRTOS is designed to run on a single core. However the {IDF_TARGET_NAME} is
dual core containing a Protocol CPU (known as **CPU 0** or **PRO_CPU**) and an
Application CPU (known as **CPU 1** or **APP_CPU**). The two cores are
identical in practice and share the same memory. This allows the two cores to
run tasks interchangeably between them.
.. only:: CONFIG_FREERTOS_UNICORE
The ESP-IDF FreeRTOS is a modified version of vanilla FreeRTOS which supports
symmetric multiprocessing (SMP). ESP-IDF FreeRTOS is based on the Xtensa port
of FreeRTOS v10.2.0. This guide outlines the major differences between vanilla
FreeRTOS and ESP-IDF FreeRTOS. The API reference for vanilla FreeRTOS can be
found via https://www.freertos.org/a00106.html
.. note::
Some ESP targets (such as the ESP32-S2 and ESP32-C3) are single core SoCs. ESP-IDF applications built for these targets will be built with **ESP-IDF FreeRTOS instead of Vanilla FreeRTOS**. However, the builds for these single core targets will always have the :ref:`CONFIG_FREERTOS_UNICORE` configuration enabled. See :ref:`freertos-smp-single-core` for more details.
For information regarding features that are exclusive to ESP-IDF FreeRTOS,
see :doc:`ESP-IDF FreeRTOS Additions</api-reference/system/freertos_additions>`.
.. note::
- For information regarding features that have been added to ESP-IDF FreeRTOS, see :doc:`ESP-IDF FreeRTOS Additions</api-reference/system/freertos_additions>`.
- For a detailed ESP-IDF FreeRTOS API Reference, see :doc:`FreeRTOS API reference<../api-reference/system/freertos>`.
.. only:: not CONFIG_FREERTOS_UNICORE
:ref:`tasks-and-task-creation`: Use :cpp:func:`xTaskCreatePinnedToCore` or
:cpp:func:`xTaskCreateStaticPinnedToCore` to create tasks in ESP-IDF FreeRTOS. The
last parameter of the two functions is ``xCoreID``. This parameter specifies
which core the task is pinned to. Acceptable values are ``0`` for **PRO_CPU**,
``1`` for **APP_CPU**, or ``tskNO_AFFINITY`` which allows the task to run on
both.
.. -------------------------------------------- Symmetric Multiprocessing ----------------------------------------------
:ref:`round-robin-scheduling`: The ESP-IDF FreeRTOS scheduler implements a "Best Effort Round-Robin Scheduling" instead of the ideal Round-Robin scheduling in vanilla FreeRTOS.
Symmetric Multiprocessing
-------------------------
:ref:`scheduler-suspension`: Suspending the scheduler in ESP-IDF FreeRTOS will only
affect the scheduler on the the calling core. In other words, calling
:cpp:func:`vTaskSuspendAll` on **PRO_CPU** will not prevent **APP_CPU** from scheduling, and
vice versa. Use critical sections or semaphores instead for simultaneous
access protection.
Basic Concepts
^^^^^^^^^^^^^^
:ref:`tick-interrupt-synchronicity`: Tick interrupts of **PRO_CPU** and **APP_CPU**
are not synchronized. Do not expect to use :cpp:func:`vTaskDelay` or
:cpp:func:`vTaskDelayUntil` as an accurate method of synchronizing task execution
between the two cores. Use a counting semaphore instead as their context
switches are not tied to tick interrupts due to preemption.
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...
:ref:`critical-sections`: In ESP-IDF FreeRTOS, critical sections are implemented using
mutexes. Entering critical sections involve taking a mutex, then disabling the
scheduler and interrupts of the calling core. However the other core is left
unaffected. If the other core attemps to take same mutex, it will spin until
the calling core has released the mutex by exiting the critical section.
- 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.
.. only:: esp32
The main advantages of an SMP system compared to single core or Asymmetric Multiprocessing systems are that...
:ref:`floating-points`: The ESP32 supports hardware acceleration of single
precision floating point arithmetic (``float``). However the use of hardware
acceleration leads to some behavioral restrictions in ESP-IDF FreeRTOS.
Therefore, tasks that utilize ``float`` will automatically be pinned to a core if
not done so already. Furthermore, ``float`` cannot be used in interrupt service
routines.
- 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.
:ref:`deletion-callbacks`: Deletion callbacks are called automatically during task deletion and are
used to free memory pointed to by TLSP. Call
:cpp:func:`vTaskSetThreadLocalStoragePointerAndDelCallback()` to set TLSP and Deletion
Callbacks.
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.
:ref:`esp-idf-freertos-configuration`: Several aspects of ESP-IDF FreeRTOS can be
set in the project configuration (``idf.py menuconfig``) such as running ESP-IDF in
Unicore (single core) Mode, or configuring the number of Thread Local Storage Pointers
each task will have.
- A thread that is pinned to a particular core will 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.
It is not necessary to manually start the FreeRTOS scheduler by calling :cpp:func:`vTaskStartScheduler`. In ESP-IDF the
scheduler is started by the :doc:`startup` and is already running when the ``app_main`` function is called (see :ref:`app-main-task` for details).
SMP on an ESP Target
^^^^^^^^^^^^^^^^^^^^
.. _tasks-and-task-creation:
ESP targets (such as the ESP32, ESP32-S3) are dual core SMP SoCs. These targets have the following hardware features that make them SMP capable:
Tasks and Task Creation
-----------------------
- Two identical cores known as CPU0 (i.e., Protocol CPU or PRO_CPU) and CPU1 (i.e., Application CPU or APP_CPU). This means that the execution of a piece of code is identical regardless of which core it runs on.
- Symmetric memory (with some small exceptions).
Tasks in ESP-IDF FreeRTOS are designed to run on a particular core, therefore
two new task creation functions have been added to ESP-IDF FreeRTOS by
appending ``PinnedToCore`` to the names of the task creation functions in
vanilla FreeRTOS. The vanilla FreeRTOS functions of :cpp:func:`xTaskCreate`
and :cpp:func:`xTaskCreateStatic` have led to the addition of
:cpp:func:`xTaskCreatePinnedToCore` and :cpp:func:`xTaskCreateStaticPinnedToCore` in
ESP-IDF FreeRTOS
- If multiple cores access the same memory address, their access will be serialized at the memory bus level.
- True atomic access to the same memory address is achieved via an atomic compare-and-swap instruction provided by the ISA.
For more details see :component_file:`freertos/FreeRTOS-Kernel/tasks.c`
- Cross-core interrupts that allow one CPU to trigger and interrupt on another CPU. This allows cores to signal each other.
The ESP-IDF FreeRTOS task creation functions are nearly identical to their
vanilla counterparts with the exception of the extra parameter known as
``xCoreID``. This parameter specifies the core on which the task should run on
and can be one of the following values.
.. 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).
- ``0`` pins the task to **PRO_CPU**
- ``1`` pins the task to **APP_CPU**
- ``tskNO_AFFINITY`` allows the task to be run on both CPUs
For example ``xTaskCreatePinnedToCore(tsk_callback, “APP_CPU Task”, 1000, NULL, 10, NULL, 1)``
creates a task of priority 10 that is pinned to **APP_CPU** with a stack size
of 1000 bytes. It should be noted that the ``uxStackDepth`` parameter in
vanilla FreeRTOS specifies a tasks stack depth in terms of the number of
words, whereas ESP-IDF FreeRTOS specifies the stack depth in terms of bytes.
.. ------------------------------------------------------ Tasks --------------------------------------------------------
Note that the vanilla FreeRTOS functions :cpp:func:`xTaskCreate` and
:cpp:func:`xTaskCreateStatic` have been defined in ESP-IDF FreeRTOS as inline functions which call
:cpp:func:`xTaskCreatePinnedToCore` and :cpp:func:`xTaskCreateStaticPinnedToCore`
respectively with ``tskNO_AFFINITY`` as the ``xCoreID`` value.
Tasks
-----
Each Task Control Block (TCB) in ESP-IDF stores the ``xCoreID`` as a member.
Hence when each core calls the scheduler to select a task to run, the
``xCoreID`` member will allow the scheduler to determine if a given task is
permitted to run on the core that called it.
Creation
^^^^^^^^
Scheduling
----------
Vanilla FreeRTOS provides the following functions to create a task:
The vanilla FreeRTOS implements scheduling in the ``vTaskSwitchContext()``
function. This function is responsible for selecting the highest priority task
to run from a list of tasks in the Ready state known as the Ready Tasks List
(described in the next section). In ESP-IDF FreeRTOS, each core will call
``vTaskSwitchContext()`` independently to select a task to run from the
Ready Tasks List which is shared between both cores. There are several
differences in scheduling behavior between vanilla and ESP-IDF FreeRTOS such as
differences in Round Robin scheduling, scheduler suspension, and tick interrupt
synchronicity.
- :cpp:func:`xTaskCreate` creates a task. The task's memory is dynamically allocated
- :cpp:func:`xTaskCreateStatic` creates a task. The task's memory is statically allocated (i.e., provided by the user)
.. _round-robin-scheduling:
However, in an SMP system, tasks need to be assigned a particular affinity. Therefore, ESP-IDF provides a ``PinnedToCore`` version of Vanilla FreeRTOS's task creation functions:
Round Robin Scheduling
^^^^^^^^^^^^^^^^^^^^^^
- :cpp:func:`xTaskCreatePinnedToCore` creates a task with a particular core affinity. The task's memory is dynamically allocated.
- :cpp:func:`xTaskCreateStaticPinnedToCore` creates a task with a particular core affinity. The task's memory is statically allocated (i.e., provided by the user)
Given multiple tasks in the Ready state and of the same priority, vanilla FreeRTOS implements Round Robin scheduling between multiple ready state tasks of the same priority. This will result in running those tasks in turn each time the scheduler is called (e.g. when the tick interrupt occurs or when a task blocks/yields).
The ``PinnedToCore`` versions of the task creation functions API differ from their vanilla counter parts by having an extra ``xCoreID`` parameter that is used to specify the created task's core affinity. The valid values for core affinity are:
On the other hand, it is not possible for the ESP-IDF FreeRTOS scheduler to implement perfect Round Robin due to the fact that a particular task may not be able to run on a particular core due to the following reasons:
- ``0`` which pins the created task to CPU0
- ``1`` which pins the created task to CPU1
- ``tskNO_AFFINITY`` which allows the task to be run on both CPUs
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
^^^^^^^^^
The anatomy of a task in ESP-IDF FreeRTOS is the same as Vanilla FreeRTOS. More specifically, ESP-IDF FreeRTOS tasks:
- Can only be in one of following states: Running, Ready, Blocked, or Suspended.
- Task functions are typically implemented as an infinite loop
- Task functions should never return
Deletion
^^^^^^^^
Task deletion in Vanilla FreeRTOS is called via :cpp:func:`vTaskDelete`. The function allows deletion of another task or the currently running task (if the provided task handle is ``NULL``). The actual freeing of the task's memory is sometimes delegated to the idle task (if the task being deleted is the currently running task).
ESP-IDF FreeRTOS provides the same :cpp:func:`vTaskDelete` function. However, due to the dual core nature, there are some behavioral differences when calling :cpp:func:`vTaskDelete` in ESP-IDF FreeRTOS:
- When deleting a task that is pinned to the other core, that task's memory is always freed by the idle task of the other core (due to the need to clear FPU registers).
- When deleting a task that is currently running on the other core, a yield is triggered on the other core and the task's memory is freed by one of the idle tasks (depending on the task's core affinity)
- A deleted task's memory is freed immediately if...
- The tasks is currently running on this core and is also pinned to this core
- The task is not currently running and is not pinned to any core
Users should avoid calling :cpp:func:`vTaskDelete` on a task that is currently running on the other core. This is due to the fact that it is difficult to know what the task currently running on the other core is executing, thus can lead to unpredictable behavior such as...
- Deleting a task that is holding a mutex
- Deleting a task that has yet to free memory it previously allocated
Where possible, users should design their application such that :cpp:func:`vTaskDelete` is only ever called on tasks in a known state. For example:
- Tasks self deleting (via ``vTaskDelete(NULL)``) when their execution is complete and have also cleaned up all resources used within the task.
- Tasks placing themselves in the suspend state (via :cpp:func:`vTaskSuspend`) before being deleted by another task.
.. --------------------------------------------------- Scheduling ------------------------------------------------------
SMP Scheduler
-------------
The Vanilla FreeRTOS scheduler is best described as a **Fixed Priority Preemptive scheduler with Time Slicing** meaning that:
- 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 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:
- 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
However, users should not assume that the two highest priority ready state tasks are always run by the scheduler as a task's core affinity must also be accounted for. For example, given the following tasks:
- Task A of priority 10 pinned to CPU0
- Task B of priority 9 pinned to CPU0
- Task C of priority 8 pinned to CPU1
The resulting schedule will have Task A running on CPU0 and Task C running on CPU1. Task B is not run even though it is the second highest priority task.
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:
- Task A of priority 8 currently running on CPU0
- Task B of priority 9 currently running on CPU1
- Task C of priority 10 that is unpinned and was unblocked by Task B
The resulting schedule will have Task A running on CPU0 and Task C preempting Task B given that the scheduler always gives preference to the current core.
Time Slicing
^^^^^^^^^^^^
The Vanilla FreeRTOS scheduler implements time slicing meaning that if current highest ready priority contains multiple ready tasks, the scheduler will switch between those tasks periodically in a round robin fashion.
However, in ESP-IDF FreeRTOS, it is not possible to implement perfect Round Robin time slicing due to the fact that a particular task may not be able to run on a particular core due to the following reasons:
- The task is pinned to the another core.
- For unpinned tasks, the task is already being run by another core.
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 scheduling 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 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 following example demonstrates the Best Effort Round Robin Scheduling in action. Assume that:
The following example demonstrates the Best Effort Round Robin time slicing in action. Assume that:
- There are four ready state tasks of the same priority ``AX, B0, C1, D1`` where:
- The priority is the current highest priority with ready state tasks
@ -205,248 +250,179 @@ The following example demonstrates the Best Effort Round Robin Scheduling in act
Head [ D0 , C1 , B0 , AX ] Tail
The implications to users regarding the Best Effort Round Robin Scheduling:
The implications to users regarding the Best Effort Round Robin time slicing:
- Users cannot expect multiple ready state tasks of the same priority to run sequentially (as is the case in Vanilla FreeRTOS). As demonstrated in the example above, a core may need to skip over tasks.
- However, given enough ticks, a task will eventually be given some processing time.
- If a core cannot find a task runnable task at the highest ready state priority, it will drop to a lower priority to search for tasks.
- To achieve ideal round robin scheduling, users should ensure that all tasks of a particular priority are pinned to the same core.
- To achieve ideal round robin time slicing, users should ensure that all tasks of a particular priority are pinned to the same core.
Tick Interrupts
^^^^^^^^^^^^^^^
.. _scheduler-suspension:
Vanilla FreeRTOS requires that a periodic tick interrupt occurs. The tick interrupt is responsible for:
- Incrementing the scheduler's tick count
- Unblocking any blocked tasks that have timed out
- 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. Furthermore, the tick interrupt 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
.. 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.
Idle Tasks
^^^^^^^^^^
Vanilla FreeRTOS will implicitly create an idle task of priority 0 when the scheduler is started. The idle task runs when no other task is ready to run, and it has the following responsibilities:
- Freeing the memory of deleted tasks
- Executing the application idle hook
In ESP-IDF FreeRTOS, a separate pinned idle task is created for each core. The idle tasks on each core have the same responsibilities as their vanilla counterparts.
Scheduler Suspension
^^^^^^^^^^^^^^^^^^^^
In vanilla FreeRTOS, suspending the scheduler via :cpp:func:`vTaskSuspendAll` will
prevent calls of ``vTaskSwitchContext`` from context switching until the
scheduler has been resumed with :cpp:func:`xTaskResumeAll`. However servicing ISRs
are still permitted. Therefore any changes in task states as a result from the
current running task or ISRs will not be executed until the scheduler is
resumed. Scheduler suspension in vanilla FreeRTOS is a common protection method
against simultaneous access of data shared between tasks, whilst still allowing
ISRs to be serviced.
Vanilla FreeRTOS allows the scheduler to be suspended/resumed by calling :cpp:func:`vTaskSuspendAll` and :cpp:func:`xTaskResumeAll` respectively. While the scheduler is suspended:
In ESP-IDF FreeRTOS, :cpp:func:`xTaskSuspendAll` will only prevent calls of
``vTaskSwitchContext()`` from switching contexts on the core that called for the
suspension. Hence if **PRO_CPU** calls :cpp:func:`vTaskSuspendAll`, **APP_CPU** will
still be able to switch contexts. If data is shared between tasks that are
pinned to different cores, scheduler suspension is **NOT** a valid method of
protection against simultaneous access. Consider using critical sections
(disables interrupts) or semaphores (does not disable interrupts) instead when
protecting shared resources in ESP-IDF FreeRTOS.
- 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)
In general, it's better to use other RTOS primitives like mutex semaphores to protect
against data shared between tasks, rather than :cpp:func:`vTaskSuspendAll`.
On scheduler resumption, :cpp:func:`xTaskResumeAll` will catch 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:
- Task switching is disabled only on the current core but interrupts for the current core are left enabled
- Calling any blocking/yielding function on the current core is forbidden. Time slicing is disabled on the current core.
- If suspending on CPU0, the tick count is frozen. The tick interrupt will still occur to execute the application tick hook.
When resuming the scheduler on CPU0, :cpp:func:`xTaskResumeAll` will catch up all of the lost ticks and unblock any timed out tasks.
.. 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.
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.
.. 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.
Startup and Termination
^^^^^^^^^^^^^^^^^^^^^^^
ESP-IDF FreeRTOS **does not** require users to call :cpp:func:`vTaskStartScheduler` to start the scheduler. The startup flow of an ESP-IDF application will already call this automatically. The entry point for user code is a user defined ``void app_main(void)`` function. For more details regarding the startup of ESP-IDF FreeRTOS applications, see :ref:`freertos-applications`.
ESP-IDF FreeRTOS **does not** support scheduler termination. Calling :cpp:func:`vTaskEndScheduler` will simply cause the application to abort.
.. _tick-interrupt-synchronicity:
.. ------------------------------------------------ Critical Sections --------------------------------------------------
Tick Interrupt Synchronicity
Critical Sections
-----------------
API Changes
^^^^^^^^^^^
Vanilla FreeRTOS implements critical sections by disabling interrupts, This prevents preemptive context switches and the servicing of ISRs during a critical section. Thus a task/ISR that enters a critical section is guaranteed to be the sole entity to access a shared resource. Critical sections in Vanilla FreeRTOS have the following API:
- ``taskENTER_CRITICAL()`` enters a critical section by disabling interrupts
- ``taskEXIT_CRITICAL()`` exits a critical section by reenabling interrupts
- ``taskENTER_CRITICAL_FROM_ISR()`` enters a critical section from an ISR by disabling interrupt nesting
- ``taskEXIT_CRITICAL_FROM_ISR()`` exits a critical section from an ISR by reenabling interrupt nesting
However, in an SMP system, merely disabling interrupts does not constitute a critical section as the presence of other cores means that a shared resource can still be concurrently accessed. Therefore, critical sections in ESP-IDF FreeRTOS are implemented using spinlocks. To accommodate the spinlocks, the ESP-IDF FreeRTOS critical section APIs contain an additional spinlock parameter as shown below:
- Spinlocks are of ``portMUX_TYPE`` (**not to be confused to FreeRTOS mutexes**)
- ``taskENTER_CRITICAL(&mux)`` enters a critical from a task context
- ``taskEXIT_CRITICAL(&mux)`` exits a critical section from a task context
- ``taskENTER_CRITICAL_ISR(&mux)`` enters a critical section from an interrupt context
- ``taskEXIT_CRITICAL_ISR(&mux)`` 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.
Implementation
^^^^^^^^^^^^^^
In ESP-IDF FreeRTOS, the process of a particular core entering and exiting a critical section is as follows:
- For ``taskENTER_CRITICAL(&mux)`` (or ``taskENTER_CRITICAL_ISR(&mux)``)
#. The core disables its interrupts (or interrupt nesting) up to ``configMAX_SYSCALL_INTERRUPT_PRIORITY``
#. The core then spins on the spinlock using an atomic compare-and-set instruction until it acquires the lock. A lock is acquired when the core is able to set the lock's owner value to the core's ID.
#. Once the spinlock is acquired, the function returns. The remainder of the critical section runs with interrupts (or interrupt nesting) disabled.
- For ``taskEXIT_CRITICAL(&mux)`` (or ``taskEXIT_CRITICAL_ISR(&mux)``)
#. The core releases the spinlock by clearing the spinlock's owner value
#. The core re-enables interrupts (or interrupt nesting)
Restrictions and Considerations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Given that interrupts (or interrupt nesting) are disabled during a critical section, there are multiple restrictions regarding what can be done within a critical sections. During a critical section, users should keep the following restrictions and considerations in mind:
- Critical sections should be as kept as short as possible
- The longer the critical section lasts, the longer a pending interrupt can be delayed.
- A typical critical section should only access a few data structures and/or hardware registers
- If possible, defer as much processing and/or event handling to the outside of critical sections.
- FreeRTOS API should not be called from within a critical section
- Users should never call any blocking or yielding functions within a critical section
.. ------------------------------------------------------ Misc ---------------------------------------------------------
Misc
----
Floating Point Usage
^^^^^^^^^^^^^^^^^^^^
Usually, when a context switch occurs:
- the current state of a CPU's registers are saved to the stack of task being switch out
- the previously saved state of the CPU's registers are loaded from the stack of the task being switched in
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.
- 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.
Furthermore, ESP-IDF FreeRTOS by default does not support the usage of the FPU within an interrupt context given that the FPU's register state is tied to a particular task.
.. 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``.
.. -------------------------------------------------- Single Core -----------------------------------------------------
.. _freertos-smp-single-core:
ESP-IDF FreeRTOS Single Core
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In ESP-IDF FreeRTOS, tasks on different cores that unblock on the same tick
count might not run at exactly the same time due to the scheduler calls from
each core being independent, and the tick interrupts to each core being
unsynchronized.
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).
In vanilla FreeRTOS the tick interrupt triggers a call to
:cpp:func:`xTaskIncrementTick` which is responsible for incrementing the tick
counter, checking if tasks which have called :cpp:func:`vTaskDelay` have fulfilled
their delay period, and moving those tasks from the Delayed Task List to the
Ready Task List. The tick interrupt will then call the scheduler if a context
switch is necessary.
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.
In ESP-IDF FreeRTOS, delayed tasks are unblocked with reference to the tick
interrupt on PRO_CPU as PRO_CPU is responsible for incrementing the shared tick
count. However tick interrupts to each core might not be synchronized (same
frequency but out of phase) hence when PRO_CPU receives a tick interrupt,
APP_CPU might not have received it yet. Therefore if multiple tasks of the same
priority are unblocked on the same tick count, the task pinned to PRO_CPU will
run immediately whereas the task pinned to APP_CPU must wait until APP_CPU
receives its out of sync tick interrupt. Upon receiving the tick interrupt,
APP_CPU will then call for a context switch and finally switches contexts to
the newly unblocked task.
Therefore, task delays should **NOT** be used as a method of synchronization
between tasks in ESP-IDF FreeRTOS. Instead, consider using a counting semaphore
to unblock multiple tasks at the same time.
.. _critical-sections:
Critical Sections & Disabling Interrupts
----------------------------------------
Vanilla FreeRTOS implements critical sections with ``taskENTER_CRITICAL()`` which
calls ``portDISABLE_INTERRUPTS()``. This prevents preemptive context switches and
servicing of ISRs during a critical section. Therefore, critical sections are
used as a valid protection method against simultaneous access in vanilla FreeRTOS.
.. only:: not CONFIG_FREERTOS_UNICORE
On the other hand, {IDF_TARGET_NAME} has no hardware method for cores to disable each
others interrupts. Calling ``portDISABLE_INTERRUPTS()`` will have no effect on
the interrupts of the other core. Therefore, disabling interrupts is **NOT**
a valid protection method against simultaneous access to shared data as it
leaves the other core free to access the data even if the current core has
disabled its own interrupts.
.. only:: CONFIG_FREERTOS_UNICORE
ESP-IDF contains some modifications to work with dual core concurrency,
and the dual core API is used even on a single core only chip.
For this reason, ESP-IDF FreeRTOS implements critical sections using special
mutexes, referred by ``portMUX_Type`` objects. These are implemented on top of a
specific spinlock component. Calls to ``taskENTER_CRITICAL`` or
``taskEXIT_CRITICAL`` each provide a spinlock object as an argument. The
spinlock is associated with a shared resource requiring access protection. When
entering a critical section in ESP-IDF FreeRTOS, the calling core will disable
interrupts similar to the vanilla FreeRTOS implementation, and will then take the
spinlock and enter the critical section. The other core is unaffected at this point,
unless it enters its own critical section and attempts to take the same spinlock.
In that case it will spin until the lock is released. Therefore, the ESP-IDF FreeRTOS
implementation of critical sections allows a core to have protected access to a shared
resource without disabling the other core. The other core will only be affected if it
tries to concurrently access the same resource.
The ESP-IDF FreeRTOS critical section functions have been modified as follows…
- ``taskENTER_CRITICAL(mux)``, ``taskENTER_CRITICAL_ISR(mux)``,
``portENTER_CRITICAL(mux)``, ``portENTER_CRITICAL_ISR(mux)`` are all macro
defined to call internal function :cpp:func:`vPortEnterCritical`
- ``taskEXIT_CRITICAL(mux)``, ``taskEXIT_CRITICAL_ISR(mux)``,
``portEXIT_CRITICAL(mux)``, ``portEXIT_CRITICAL_ISR(mux)`` are all macro
defined to call internal function :cpp:func:`vPortExitCritical`
- ``portENTER_CRITICAL_SAFE(mux)``, ``portEXIT_CRITICAL_SAFE(mux)`` macro identifies
the context of execution, i.e ISR or Non-ISR, and calls appropriate critical
section functions (``port*_CRITICAL`` in Non-ISR and ``port*_CRITICAL_ISR`` in ISR)
in order to be in compliance with Vanilla FreeRTOS.
For more details see :component_file:`esp_hw_support/include/soc/spinlock.h`,
:component_file:`freertos/FreeRTOS-Kernel/include/freertos/task.h`,
and :component_file:`freertos/FreeRTOS-Kernel/tasks.c`
It should be noted that when modifying vanilla FreeRTOS code to be ESP-IDF
FreeRTOS compatible, it is trivial to modify the type of critical section called
as they are all defined to call the same function. As long as the same spinlock
is provided upon entering and exiting, the exact macro or function used for the
call should not matter.
.. only:: not CONFIG_FREERTOS_UNICORE
.. _floating-points:
Floating Point Arithmetic
-------------------------
ESP-IDF FreeRTOS implements Lazy Context Switching for FPUs. In other words,
the state of a core's FPU registers are not immediately saved when a context
switch occurs. Therefore, tasks that utilize ``float`` must be pinned to a
particular core upon creation. If not, ESP-IDF FreeRTOS will automatically pin
the task in question to whichever core the task was running on upon the task's
first use of ``float``. Likewise due to Lazy Context Switching, only interrupt
service routines of lowest priority (that is it the Level 1) can use ``float``,
higher priority interrupts do not support FPU usage.
ESP32 does not support hardware acceleration for double precision floating point
arithmetic (``double``). Instead ``double`` is implemented via software hence the
behavioral restrictions with regards to ``float`` do not apply to ``double``. Note
that due to the lack of hardware acceleration, ``double`` operations may consume
significantly larger amount of CPU time in comparison to ``float``.
.. _task-deletion:
Task Deletion
-------------
In FreeRTOS task deletion the freeing of task memory will occur
immediately (within :cpp:func:`vTaskDelete`) if the task being deleted is not currently
running or is not pinned to the other core (with respect to the core
:cpp:func:`vTaskDelete` is called on). TLSP deletion callbacks will also run immediately
if the same conditions are met.
However, calling :cpp:func:`vTaskDelete` to delete a task that is either currently
running or pinned to the other core will still result in the freeing of memory
being delegated to the Idle Task.
.. _deletion-callbacks:
Thread Local Storage Pointers & Deletion Callbacks
--------------------------------------------------
Thread Local Storage Pointers (TLSP) are pointers stored directly in the TCB.
TLSP allow each task to have its own unique set of pointers to data structures.
However task deletion behavior in vanilla FreeRTOS does not automatically
free the memory pointed to by TLSP. Therefore if the memory pointed to by
TLSP is not explicitly freed by the user before task deletion, memory leak will
occur.
ESP-IDF FreeRTOS provides the added feature of Deletion Callbacks. Deletion
Callbacks are called automatically during task deletion to free memory pointed
to by TLSP. Each TLSP can have its own Deletion Callback. Note that due to the
to `Task Deletion`_ behavior, there can be instances where Deletion
Callbacks are called in the context of the Idle Tasks. Therefore Deletion
Callbacks **should never attempt to block** and critical sections should be kept
as short as possible to minimize priority inversion.
Deletion callbacks are of type
``void (*TlsDeleteCallbackFunction_t)( int, void * )`` where the first parameter
is the index number of the associated TLSP, and the second parameter is the
TLSP itself.
Deletion callbacks are set alongside TLSP by calling
:cpp:func:`vTaskSetThreadLocalStoragePointerAndDelCallback`. 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. If a deletion callback is `NULL`,
users should manually free the memory pointed to by the associated TLSP before
task deletion in order to avoid memory leak.
For more details see :doc:`FreeRTOS API reference<../api-reference/system/freertos>`.
.. _esp-idf-freertos-configuration:
Configuring ESP-IDF FreeRTOS
----------------------------
The ESP-IDF FreeRTOS can be configured in the project configuration menu
(``idf.py menuconfig``) under ``Component Config/FreeRTOS``. The following section
highlights some of the ESP-IDF FreeRTOS configuration options. For a full list of
ESP-IDF FreeRTOS configurations, see :doc:`FreeRTOS <../api-reference/kconfig>`
.. only:: not CONFIG_FREERTOS_UNICORE
:ref:`CONFIG_FREERTOS_UNICORE` will run ESP-IDF FreeRTOS only
on **PRO_CPU**. Note that this is **not equivalent to running vanilla
FreeRTOS**. Note that this option may affect behavior of components other than
:component:`freertos`. For more details regarding the
effects of running ESP-IDF FreeRTOS on a single core, search for
occurences of ``CONFIG_FREERTOS_UNICORE`` in the ESP-IDF components.
.. only:: CONFIG_FREERTOS_UNICORE
As {IDF_TARGET_NAME} is a single core SoC, the config item :ref:`CONFIG_FREERTOS_UNICORE` is
always set. This means ESP-IDF only runs on the single CPU. Note that this is **not
equivalent to running vanilla FreeRTOS**. Behaviors of multiple components in ESP-IDF
will be modified. For more details regarding the effects of running ESP-IDF FreeRTOS
on a single core, search for occurences of ``CONFIG_FREERTOS_UNICORE`` in the ESP-IDF components.
:ref:`CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION` will trigger a halt in
particular functions in ESP-IDF FreeRTOS which have not been fully tested
in an SMP context.
:ref:`CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER` will enclose all task functions
within a wrapper function. In the case that a task function mistakenly returns
(i.e. does not call :cpp:func:`vTaskDelete`), the call flow will return to the
wrapper function. The wrapper function will then log an error and abort the
application, as illustrated below::
E (25) FreeRTOS: FreeRTOS task should not return. Aborting now!
abort() was called at PC 0x40085c53 on core 0
.. 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.

View File

@ -14,10 +14,12 @@ DRAM (Data RAM)
Non-constant static data (.data) and zero-initialized data (.bss) is placed by the linker into Internal SRAM as data memory. Remaining space in this region is used for the runtime heap.
.. only:: esp32
.. only:: esp32 or esp32s2
By applying the ``EXT_RAM_ATTR`` macro, zero-initialized data can also be placed into external RAM. To use this macro, the :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` needs to be enabled. See :ref:`external_ram_config_bss`.
.. only:: esp32
The available size of the internal DRAM region is reduced by 64kB (by shifting start address to ``0x3FFC0000``) if Bluetooth stack is used. Length of this region is also reduced by 16 kB or 32kB if trace memory is used. Due to some memory fragmentation issues caused by ROM, it is also not possible to use all available DRAM for static allocations - however the remaining DRAM is still available as heap at runtime.
.. only:: not esp32
@ -200,7 +202,7 @@ Placing DMA buffers in the stack is possible but discouraged. If doing so, pay a
.. list::
:SOC_SPIRAM_SUPPORTED: - Placing DRAM buffers on the stack is not recommended if if the stack may be in PSRAM. If the stack of a task is placed in the PSRAM, several steps have to be taken as described in :doc:`external-ram`.
:SOC_SPIRAM_SUPPORTED: - Placing DRAM buffers on the stack is not recommended if the stack may be in PSRAM. If the stack of a task is placed in the PSRAM, several steps have to be taken as described in :doc:`external-ram`.
- Use macro ``WORD_ALIGNED_ATTR`` in functions before variables to place them in proper positions like::
void app_main()

View File

@ -38,7 +38,7 @@ To minimize static memory use:
.. list::
- Declare structures, buffers, or other variables ``const`` whenever possible. Constant data can be stored in flash not RAM. This may require changing functions in the firmware to take ``const *`` arguments instead of mutable pointer arguments. These changes can also reduce the stack usage of some functions.
:esp32: - If using Bluedroid, setting the option :ref:`CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY` will cause Bluedroid to allocate memory on initialization and free it on deinitialization. This doesn't necessarily reduce the peak memory usage, but changes it from static memory usage to runtime memory usage.
:SOC_BT_SUPPORTED: - If using Bluedroid, setting the option :ref:`CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY` will cause Bluedroid to allocate memory on initialization and free it on deinitialization. This doesn't necessarily reduce the peak memory usage, but changes it from static memory usage to runtime memory usage.
.. _optimize-stack-sizes:
@ -78,7 +78,7 @@ The default stack sizes for these tasks are usually set conservatively high, to
- FreeRTOS Timer Task to handle FreeRTOS timer callbacks has stack size :ref:`CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH`.
- :doc:`/api-guides/event-handling` system task to execute callbacks for the default system event loop has stack size :ref:`CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE`.
- :doc:`/api-guides/lwip` TCP/IP task has stack size :ref:`CONFIG_LWIP_TCPIP_TASK_STACK_SIZE`
:esp32: - :doc:`Bluedroid Bluetooth Host </api-reference/bluetooth/index>` have task stack sizes :ref:`CONFIG_BT_BTC_TASK_STACK_SIZE`, :ref:`CONFIG_BT_BTU_TASK_STACK_SIZE`.
:SOC_BT_SUPPORTED: - :doc:`Bluedroid Bluetooth Host </api-reference/bluetooth/index>` have task stack sizes :ref:`CONFIG_BT_BTC_TASK_STACK_SIZE`, :ref:`CONFIG_BT_BTU_TASK_STACK_SIZE`.
:SOC_BT_SUPPORTED: - :doc:`NimBLE Bluetooth Host </api-reference/bluetooth/nimble/index>` has task stack size :ref:`CONFIG_BT_NIMBLE_TASK_STACK_SIZE`
- The Ethernet driver creates a task for the MAC to receive Ethernet frames. If using the default config ``ETH_MAC_DEFAULT_CONFIG`` then the task stack size is 4 KB. This setting can be changed by passing a custom :cpp:class:`eth_mac_config_t` struct when initializing the Ethernet MAC.
- FreeRTOS idle task stack size is configured by :ref:`CONFIG_FREERTOS_IDLE_TASK_STACKSIZE`.

View File

@ -414,7 +414,7 @@ VFS
* :ref:`CONFIG_VFS_SUPPORT_TERMIOS` — can be disabled if the application doesn't use ``termios`` family of functions. Currently, these functions are implemented only for UART VFS driver. Most applications can disable this option. Disabling this option reduces the code size by about 1.8 kB.
* :ref:`CONFIG_VFS_SUPPORT_SELECT` can be disabled if the application doesn't use ``select`` function with file descriptors. Currently, only the UART and eventfd VFS drivers implement ``select`` support. Note that when this option is disabled, ``select`` can still be used for socket file descriptors. Disabling this option reduces the code size by about 2.7 kB.
* :ref:`CONFIG_VFS_SUPPORT_DIR` — can be disabled if the application doesn't use directory related functions, such as ``readdir`` (see the description of this option for the complete list). Applications which only open, read and write specific files and don't need to enumerate or create directories can disable this option, reducing the code size by 0.5 kB or more, depending on the filesystem drivers in use.
* :ref:`CONFIG_VFS_SUPPORT_IO` — can be disabled if the application doesn't use filesystems or file-like peripheral drivers. This disables all VFS functionality, including the three options mentioned above. When this option is disabled, :doc:`console </api-reference/system/console>` can't be used. Note that the application can still use standard I/O functions with socket file descriptors when this option is disabled. Compared to the default configuration, disabling this option reduces code size by about 9.4 kB.
* :ref:`CONFIG_VFS_SUPPORT_IO` — can be disabled if the application doesn't use filesystems or file-like peripheral drivers. This disables all VFS functionality, including the three options mentioned above. When this option is disabled, :doc:`console </api-reference/system/console>` can't be used. Note that the application can still use standard I/O functions with socket file descriptors when this option is disabled. Compared to the default configuration, disabling this option reduces code size by about 9.4 kB.
Bootloader Size
---------------

View File

@ -2,11 +2,18 @@ ULP-RISC-V Coprocessor programming
==================================
:link_to_translation:`zh_CN:[中文]`
.. only:: esp32s3
.. warning::
This feature is not supported in v4.4
.. toctree::
:maxdepth: 1
The ULP-RISC-V coprocessor is a variant of the ULP, present in ESP32-S2. Similar to ULP, ULP RISC-V coprocessor can perform tasks such as sensor readings while the main CPU stays in low power modes. The main difference from the FSM ULP is this variant 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 ESP32-S2. Similar to ULP, ULP RISC-V coprocessor can perform tasks such as sensor readings while the main CPU stays in low power modes. The main difference from the FSM ULP is this variant 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
-----------------------------------
@ -70,7 +77,7 @@ For example, the ULP-RISC-V program may define a variable ``measurement_count``
.. code-block:: c
volatile int measurement_count;
volatile int measurement_count;
int some_function()
{

View File

@ -3,6 +3,12 @@ ULP Coprocessor programming
:link_to_translation:`zh_CN:[中文]`
.. only:: esp32s3
.. warning::
This feature is not supported in v4.4
.. toctree::
:maxdepth: 1

View File

@ -7,6 +7,12 @@ SD Pull-up Requirements
This document is not updated for ESP32-C3 yet.
.. only:: esp32s3
.. warning::
This document is not updated for ESP32-S3 yet.
Espressif hardware products are designed for multiple use cases which may require different pull states on pins. For this reason, the pull state of particular pins on certain products will need to be adjusted to provide the pull-ups required in the SD bus.
SD pull-up requirements apply to cases where {IDF_TARGET_NAME} uses the SPI controller to communicate with SD cards. When an SD card is operating in SPI mode or 1-bit SD mode, the CMD and DATA (DAT0 - DAT3) lines of the SD bus must be pulled up by 10 kOhm resistors. Slaves should also have pull-ups on all above-mentioned lines (regardless of whether these lines are connected to the host) in order to prevent SD cards from entering a wrong state.

View File

@ -7,6 +7,12 @@ SDIO Card Slave Driver
This document is not updated for ESP32-C3 yet.
.. only:: esp32s3
.. warning::
This document is not updated for ESP32-S3 yet.
Overview
--------
@ -189,9 +195,9 @@ To allow the host sending data to the slave, the application has to load buffers
1. Register the buffer by calling ``sdio_slave_recv_register_buf``, and get the handle of the registered buffer. The driver
will allocate memory for the linked-list descriptor needed to link the buffer onto the hardware. The size of these buffers should equal to the Receiving buffer size.
2. Load buffers onto the driver by passing the buffer handle to ``sdio_slave_recv_load_buf``.
3. Get the received data by calling ``sdio_slave_recv`` or ``sdio_slave_recv_packet``. If non-blocking call is needed, set ``wait=0``.
3. Get the received data by calling ``sdio_slave_recv`` or ``sdio_slave_recv_packet``. If non-blocking call is needed, set ``wait=0``.
The difference between two APIs is that, ``sdio_slave_recv_packet`` gives more information about packet, which can consist of several buffers. When ``ESP_ERR_NOT_FINISHED`` is returned by this API, you should call this API iteratively until the return value is ``ESP_OK``. All the continuous buffers returned with ``ESP_ERR_NOT_FINISHED``, together with the last buffer returned with ``ESP_OK``, belong to one packet from the host. Call ``sdio_slave_recv_get_buf`` to get the address of the received data, and the actual length received in each buffer. The packet length is the sum of received length of all the buffers in the packet.
The difference between two APIs is that, ``sdio_slave_recv_packet`` gives more information about packet, which can consist of several buffers. When ``ESP_ERR_NOT_FINISHED`` is returned by this API, you should call this API iteratively until the return value is ``ESP_OK``. All the continuous buffers returned with ``ESP_ERR_NOT_FINISHED``, together with the last buffer returned with ``ESP_OK``, belong to one packet from the host. Call ``sdio_slave_recv_get_buf`` to get the address of the received data, and the actual length received in each buffer. The packet length is the sum of received length of all the buffers in the packet.
If the host never send data longer than the Receiving buffer size, or you don't care about the packet boundary (e.g. the data is only a byte stream), you can call the simpler version ``sdio_slave_recv`` instead.

View File

@ -7,6 +7,13 @@ SDMMC Host Driver
This document is not updated for ESP32-C3 yet.
.. only:: esp32s3
.. warning::
This document is not updated for ESP32-S3 yet.
Overview
--------

View File

@ -1,6 +1,12 @@
Temperature Sensor
===================
.. only:: esp32s3
.. warning::
This feature is not supported in v4.4
Overview
--------

View File

@ -204,6 +204,12 @@ Bit timing **macro initializers** are also available for commonly used bit rates
:esp32s2: - ``TWAI_TIMING_CONFIG_10KBITS()``
:esp32s2: - ``TWAI_TIMING_CONFIG_5KBITS()``
:esp32s2: - ``TWAI_TIMING_CONFIG_1KBITS()``
:esp32s3: - ``TWAI_TIMING_CONFIG_20KBITS()``
:esp32s3: - ``TWAI_TIMING_CONFIG_16KBITS()``
:esp32s3: - ``TWAI_TIMING_CONFIG_12_5KBITS()``
:esp32s3: - ``TWAI_TIMING_CONFIG_10KBITS()``
:esp32s3: - ``TWAI_TIMING_CONFIG_5KBITS()``
:esp32s3: - ``TWAI_TIMING_CONFIG_1KBITS()``
:esp32c3: - ``TWAI_TIMING_CONFIG_20KBITS()``
:esp32c3: - ``TWAI_TIMING_CONFIG_16KBITS()``
:esp32c3: - ``TWAI_TIMING_CONFIG_12_5KBITS()``

View File

@ -176,7 +176,7 @@ counter.
Application Example
-------------------
The example below shows how ESP32 SDIO host and slave communicate with each other. The host use the ESSL SDIO.
The example below shows how {IDF_TARGET_NAME} SDIO host and slave communicate with each other. The host use the ESSL SDIO.
:example:`peripherals/sdio`.

View File

@ -7,11 +7,87 @@ Overview
This section contains documentation of FreeRTOS types, functions, and macros. It is automatically generated from FreeRTOS header files.
.. note::
ESP-IDF FreeRTOS is based on the Xtensa port of FreeRTOS v10.4.3
ESP-IDF FreeRTOS is based on Vanilla FreeRTOS v10.4.3
For more information about FreeRTOS features specific to ESP-IDF, see :doc:`ESP-IDF FreeRTOS SMP Changes<../../api-guides/freertos-smp>`
and :doc:`ESP-IDF FreeRTOS Additions<freertos_additions>`.
- For more information about the SMP changes of ESP-IDF FreeRTOS, see :doc:`/api-guides/freertos-smp`
- For more information about the features added to ESP-IDF FreeRTOS, see :doc:`/api-reference/system/freertos_additions`.
Configuration
-------------
Vanilla FreeRTOS allows ports and applications to configure the kernel by adding various ``#define config...`` macros to ``FreeRTOSConfig.h``. Through these macros, the kernel's scheduling behavior and various kernel features can be enabled or disabled. **However, in ESP-IDF FreeRTOS, the ``FreeRTOSConfig.h`` file is considered a private and must not be modified by users**. Any FreeRTOS configuration that is exposed to the user will be done so via menuconfig.
ESP-IDF FreeRTOS can be configured in the project configuration menu (``idf.py menuconfig``) under ``Component Config/FreeRTOS``. The following section highlights some of the ESP-IDF FreeRTOS configuration options. For a full list of ESP-IDF FreeRTOS configurations, see :doc:`/api-reference/kconfig`
- :ref:`CONFIG_FREERTOS_UNICORE` will run ESP-IDF FreeRTOS only on CPU0. Note that this is **not equivalent to running Vanilla FreeRTOS**. Futhermore, this option may affect behavior of components other than :component:`freertos`. For more details regarding the effects of running ESP-IDF FreeRTOS on a single core, refer to :ref:`freertos-smp-single-core`. Alternatively, users can also search for occurrences of ``CONFIG_FREERTOS_UNICORE`` in the ESP-IDF components.
- :ref:`CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION` will trigger a halt in functions in ESP-IDF FreeRTOS that have not been fully tested in an SMP context.
- :ref:`CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER` will enclose all task functions within a wrapper function. In the case that a task function mistakenly returns (i.e. does not call :cpp:func:`vTaskDelete`), the call flow will return to the wrapper function. The wrapper function will then log an error and abort the application, as illustrated below::
E (25) FreeRTOS: FreeRTOS task should not return. Aborting now!
abort() was called at PC 0x40085c53 on core 0
.. only:: CONFIG_FREERTOS_UNICORE
.. note::
As {IDF_TARGET_NAME} is a single core SoC, the :ref:`CONFIG_FREERTOS_UNICORE` configuration is always set.
.. _freertos-applications:
ESP-IDF FreeRTOS Applications
-----------------------------
Unlike Vanilla FreeRTOS, users must not call :cpp:func:`vTaskStartScheduler`. Instead, ESP-IDF FreeRTOS is started automatically. The entry point is a user defined ``void app_main(void)`` function.
- Typically, users would spawn the rest of their applications task from ``app_main``.
- The ``app_main`` function is allowed to return at any point (i.e., before the application terminates).
- The ``app_main`` function is called from the ``main`` task.
The ``main`` task is one of multiple tasks that are automatically spawned by ESP-IDF during startup. These tasks are:
.. only:: not CONFIG_FREERTOS_UNICORE
.. list-table:: List of Tasks Created During Startup
:widths: 25 25 5 50
:header-rows: 1
* - Task Name
- Affinity
- Priority
- Description
* - Main Task (``main``)
- CPU0
- 1
- Task that simply calls ``app_main``. This task will self delete when ``app_main`` returns
* - Idle Tasks (``IDLEx``)
- CPU0 and CPU1
- 0
- Idle tasks created for (and pinned to) each CPU
* - IPC Tasks (``ipcx``)
- CPU0 and CPU1
- 24
- IPC tasks created for (and pinned to ) each CPU. IPC tasks are used to implement the IPC feature. See :doc:`/api-reference/system/ipc` for more details.
.. only:: CONFIG_FREERTOS_UNICORE
.. list-table:: List of Tasks Created During Startup
:widths: 25 25 5 50
:header-rows: 1
* - Task Name
- Affinity
- Priority
- Description
* - Main Task (``main``)
- CPU0
- 1
- Task that simply calls ``app_main``. This task will self delete when ``app_main`` returns
* - Idle Tasks (``IDLEx``)
- CPU0 and CPU1
- 0
- Idle task created for (and pinned to) each CPU
Task API
--------

View File

@ -1,66 +1,48 @@
FreeRTOS Additions
==================
This document describes the additional features added to ESP-IDF FreeRTOS. This document is split into the following parts:
.. contents:: Contents
:depth: 2
.. ---------------------------------------------------- Overview -------------------------------------------------------
Overview
--------
ESP-IDF FreeRTOS is based on the Xtensa port of FreeRTOS v10.4.3 with significant modifications
for SMP compatibility (see :doc:`ESP-IDF FreeRTOS SMP Changes<../../api-guides/freertos-smp>`).
However, various features specific to ESP-IDF FreeRTOS have been added. The features are as follows:
ESP-IDF FreeRTOS is modified version of based on the Xtensa port of FreeRTOS v10.4.3 with significant modifications for SMP compatibility (see :doc:`ESP-IDF FreeRTOS SMP Changes<../../api-guides/freertos-smp>`). However, various new features specific to ESP-IDF FreeRTOS have been added. The features are as follows:
:ref:`ring-buffers`: Ring buffers were added to provide a form of buffer that could accept
entries of arbitrary lengths.
:ref:`hooks`: ESP-IDF FreeRTOS hooks provides support for registering extra Idle and
Tick hooks at run time. Moreover, the hooks can be asymmetric amongst both CPUs.
:ref:`component-specific-properties`: Currently added only one component specific property `ORIG_INCLUDE_PATH`.
- **Ring buffers**: Ring buffers provide a FIFO buffer that can accept entries of arbitrary lengths.
- **Hooks**: ESP-IDF FreeRTOS hooks provides support for registering extra Idle and Tick hooks at run time. Moreover, the hooks can be asymmetric among both CPUs.
- **Thread Local Storage Pointer (TLSP) Deletion Callbacks**: TLSP Deletion callbacks are run automatically when a task is deleted, thus allowing users to clean up their TLSPs automatically.
- **Component Specific Properties**: Currently added only one component specific property ``ORIG_INCLUDE_PATH``.
.. _ring-buffers:
.. -------------------------------------------------- Ring Buffers -----------------------------------------------------
Ring Buffers
------------
The ESP-IDF FreeRTOS ring buffer is a strictly FIFO buffer 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 API
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:
The ESP-IDF FreeRTOS ring buffer is a strictly FIFO buffer 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 API 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** 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.
**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** 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.
**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 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.
.. 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 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.
Usage
^^^^^
The following example demonstrates the usage of :cpp:func:`xRingbufferCreate`
and :cpp:func:`xRingbufferSend` to create a ring buffer and then send an item to it.
The following example demonstrates the usage of :cpp:func:`xRingbufferCreate` and :cpp:func:`xRingbufferSend` to create a ring buffer and then send an item to it.
.. code-block:: c
@ -82,11 +64,7 @@ and :cpp:func:`xRingbufferSend` to create a ring buffer and then send an item to
printf("Failed to send item\n");
}
The following example demonstrates the usage of :cpp:func:`xRingbufferSendAcquire` and
:cpp:func:`xRingbufferSendComplete` instead of :cpp:func:`xRingbufferSend` to acquire
memory on the ring buffer (of type `RINGBUF_TYPE_NOSPLIT`) and then send an item to it. This
adds one more step, but allows getting the address of the memory to write to, and writing to the
memory yourself.
The following example demonstrates the usage of :cpp:func:`xRingbufferSendAcquire` and :cpp:func:`xRingbufferSendComplete` instead of :cpp:func:`xRingbufferSend` to acquire memory on the ring buffer (of type `RINGBUF_TYPE_NOSPLIT`) and then send an item to it. This adds one more step, but allows getting the address of the memory to write to, and writing to the memory yourself.
.. code-block:: c
@ -123,8 +101,7 @@ memory yourself.
printf("Failed to send item\n");
}
The following example demonstrates retrieving and returning an item from a **No-Split ring buffer**
using :cpp:func:`xRingbufferReceive` and :cpp:func:`vRingbufferReturnItem`
The following example demonstrates retrieving and returning an item from a **No-Split ring buffer** using :cpp:func:`xRingbufferReceive` and :cpp:func:`vRingbufferReturnItem`
.. code-block:: c
@ -149,8 +126,7 @@ using :cpp:func:`xRingbufferReceive` and :cpp:func:`vRingbufferReturnItem`
}
The following example demonstrates retrieving and returning an item from an **Allow-Split ring buffer**
using :cpp:func:`xRingbufferReceiveSplit` and :cpp:func:`vRingbufferReturnItem`
The following example demonstrates retrieving and returning an item from an **Allow-Split ring buffer** using :cpp:func:`xRingbufferReceiveSplit` and :cpp:func:`vRingbufferReturnItem`
.. code-block:: c
@ -181,8 +157,7 @@ using :cpp:func:`xRingbufferReceiveSplit` and :cpp:func:`vRingbufferReturnItem`
}
The following example demonstrates retrieving and returning an item from a **byte buffer**
using :cpp:func:`xRingbufferReceiveUpTo` and :cpp:func:`vRingbufferReturnItem`
The following example demonstrates retrieving and returning an item from a **byte buffer** using :cpp:func:`xRingbufferReceiveUpTo` and :cpp:func:`vRingbufferReturnItem`
.. code-block:: c
@ -207,8 +182,7 @@ using :cpp:func:`xRingbufferReceiveUpTo` and :cpp:func:`vRingbufferReturnItem`
}
For ISR safe versions of the functions used above, call :cpp:func:`xRingbufferSendFromISR`, :cpp:func:`xRingbufferReceiveFromISR`,
:cpp:func:`xRingbufferReceiveSplitFromISR`, :cpp:func:`xRingbufferReceiveUpToFromISR`, and :cpp:func:`vRingbufferReturnItemFromISR`
For ISR safe versions of the functions used above, call :cpp:func:`xRingbufferSendFromISR`, :cpp:func:`xRingbufferReceiveFromISR`, :cpp:func:`xRingbufferReceiveSplitFromISR`, :cpp:func:`xRingbufferReceiveUpToFromISR`, and :cpp:func:`vRingbufferReturnItemFromISR`
.. note::
@ -217,154 +191,99 @@ For ISR safe versions of the functions used above, call :cpp:func:`xRingbufferSe
Sending to Ring Buffer
^^^^^^^^^^^^^^^^^^^^^^
The following diagrams illustrate the differences between No-Split and Allow-Split buffers as compared to
byte buffers with regard to sending items/data. The diagrams assume that three
items of sizes **18, 3, and 27 bytes** are sent respectively to a **buffer of 128 bytes**.
The following diagrams illustrate the differences between No-Split and Allow-Split buffers as compared to byte buffers with regard to sending items/data. The diagrams assume that three items of sizes **18, 3, and 27 bytes** are sent respectively to a **buffer of 128 bytes**.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_send_non_byte_buf.diag
:caption: Sending items to No-Split or Allow-Split ring buffers
:align: center
For No-Split and Allow-Split buffers, a header of 8 bytes precedes every data item. Furthermore, the space
occupied by each item is **rounded up to the nearest 32-bit aligned size** in order to maintain overall
32-bit alignment. However, the true size of the item is recorded inside the header which will be
returned when the item is retrieved.
For No-Split and Allow-Split buffers, a header of 8 bytes precedes every data item. Furthermore, the space occupied by each item is **rounded up to the nearest 32-bit aligned size** in order to maintain overall 32-bit alignment. However, the true size of the item is recorded inside the header which will be returned when the item is retrieved.
Referring to the diagram above, the 18, 3, and 27 byte items are **rounded up to 20, 4, and 28 bytes**
respectively. An 8 byte header is then added in front of each item.
Referring to the diagram above, the 18, 3, and 27 byte items are **rounded up to 20, 4, and 28 bytes** respectively. An 8 byte header is then added in front of each item.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_send_byte_buf.diag
:caption: Sending items to byte buffers
:align: center
Byte buffers treat data as a sequence of bytes and does not incur any overhead
(no headers). As a result, all data sent to a byte buffer is merged into a single item.
Byte buffers treat data as a sequence of bytes and does not incur any overhead (no headers). As a result, all data sent to a byte buffer is merged into a single item.
Referring to the diagram above, the 18, 3, and 27 byte items are sequentially written to the
byte buffer and **merged into a single item of 48 bytes**.
Referring to the diagram above, the 18, 3, and 27 byte items are sequentially written to the byte buffer and **merged into a single item of 48 bytes**.
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 will prevent 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`` 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.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_send_acquire_complete.diag
:caption: SendAcquire/SendComplete items in No-Split ring buffers
:align: center
After that, we fill (use) the buffers, and send them to the ring buffer by ``SendComplete`` in the
order of 8, 24, 20. When 8 bytes and 24 bytes data are sent, the consumer still can only get the
16 bytes data item. Hence, if ``SendComplete`` is not called for the 20 bytes, it will not be available, nor will
the data items following the 20 bytes item.
After that, we fill (use) the buffers, and send them to the ring buffer by ``SendComplete`` in the order of 8, 24, 20. When 8 bytes and 24 bytes data are sent, the consumer still can only get the 16 bytes data item. Hence, if ``SendComplete`` is not called for the 20 bytes, it will not be available, nor will the data items following the 20 bytes item.
When the 20 bytes item is finally completed, all the 3 data items can be received now, in the
order of 20, 8, 24 bytes, right after the 16 bytes item existing in the buffer at the beginning.
When the 20 bytes item is finally completed, all the 3 data items can be received now, in the order of 20, 8, 24 bytes, right after the 16 bytes item existing in the buffer at the beginning.
Allow-Split buffers and byte buffers do not allow using ``SendAcquire`` or ``SendComplete`` since acquired buffers are
required to be complete (not wrapped).
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
^^^^^^^^^^^
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**.
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**.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_no_split.diag
: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 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.
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.
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.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_allow_split.diag
:caption: Wrap around in Allow-Split buffers
:align: center
Allow-Split buffers will attempt to **split the item into two parts** when the free space at the tail
of the buffer is insufficient to store the item data and its header. Both parts of the
split item will have their own headers (therefore incurring an extra 8 bytes of overhead).
Allow-Split buffers will attempt to **split the item into two parts** when the free space at the tail of the buffer is insufficient to store the item data and its header. Both parts of the split item will have their own headers (therefore incurring an extra 8 bytes of overhead).
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.
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.
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 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.
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 will be treated as a separate item by the byte buffer.
Retrieving/Returning
^^^^^^^^^^^^^^^^^^^^
The following diagrams illustrate the differences between No-Split and Allow-Split buffers as compared to
byte buffers in retrieving and returning data.
The following diagrams illustrate the differences between No-Split and Allow-Split buffers as compared to byte buffers in retrieving and returning data.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_read_ret_non_byte_buf.diag
: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 will prevent 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.
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.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_read_ret_byte_buf.diag
: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 will be 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.
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.
Ring Buffers with Queue Sets
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Ring buffers can be added to FreeRTOS queue sets using :cpp:func:`xRingbufferAddToQueueSetRead` such that every
time a ring buffer receives an item or data, the queue set is notified. Once added to a queue set, every
attempt to retrieve an item from a ring buffer should be preceded by a call to :cpp:func:`xQueueSelectFromSet`.
To check whether the selected queue set member is the ring buffer, call :cpp:func:`xRingbufferCanRead`.
Ring buffers can be added to FreeRTOS queue sets using :cpp:func:`xRingbufferAddToQueueSetRead` such that every time a ring buffer receives an item or data, the queue set is notified. Once added to a queue set, every attempt to retrieve an item from a ring buffer should be preceded by a call to :cpp:func:`xQueueSelectFromSet`. To check whether the selected queue set member is the ring buffer, call :cpp:func:`xRingbufferCanRead`.
The following example demonstrates queue set usage with ring buffers.
@ -444,96 +363,78 @@ The code snippet below demonstrates a ring buffer being allocated entirely in ex
free(buffer_struct);
free(buffer_storage);
Priority Inversion
^^^^^^^^^^^^^^^^^^
Ring Buffer API Reference
-------------------------
Ideally, ring buffers can be used with multiple tasks in an SMP fashion where the **highest priority task will always be serviced first.** However due to the usage of binary semaphores in the ring buffer's underlying implementation, priority inversion may occur under very specific circumstances.
.. note::
Ideally, ring buffers can be used with multiple tasks in an SMP fashion where the **highest
priority task will always be serviced first.** However due to the usage of binary semaphores
in the ring buffer's underlying implementation, priority inversion may occur under very
specific circumstances.
The ring buffer governs sending by a binary semaphore which is given whenever space is freed on the ring buffer. The highest priority task waiting to send will repeatedly take the semaphore until sufficient free space becomes available or until it times out. Ideally this should prevent any lower priority tasks from being serviced as the semaphore should always be given to the highest priority task.
The ring buffer governs sending by a binary semaphore which is given whenever space is
freed on the ring buffer. The highest priority task waiting to send will repeatedly take
the semaphore until sufficient free space becomes available or until it times out. Ideally
this should prevent any lower priority tasks from being serviced as the semaphore should
always be given to the highest priority task.
However, in between iterations of acquiring the semaphore, there is a **gap in the critical section** which may permit another task (on the other core or with an even higher priority) to free some space on the ring buffer and as a result give the semaphore. Therefore, the semaphore will be given before the highest priority task can re-acquire the semaphore. This will result in the **semaphore being acquired by the second-highest priority task** waiting to send, hence causing priority inversion.
However, in between iterations of acquiring the semaphore, there is a **gap in the critical
section** which may permit another task (on the other core or with an even higher priority) to
free some space on the ring buffer and as a result give the semaphore. Therefore, the semaphore
will be given before the highest priority task can re-acquire the semaphore. This will result
in the **semaphore being acquired by the second-highest priority task** waiting to send, hence
causing priority inversion.
This side effect will not affect ring buffer performance drastically given if the number
of tasks using the ring buffer simultaneously is low, and the ring buffer is not operating
near maximum capacity.
.. include-build-file:: inc/ringbuf.inc
This side effect will not affect ring buffer performance drastically given if the number of tasks using the ring buffer simultaneously is low, and the ring buffer is not operating near maximum capacity.
.. _hooks:
.. ------------------------------------------------------ Hooks --------------------------------------------------------
Hooks
-----
FreeRTOS consists of Idle Hooks and Tick Hooks which allow for application
specific functionality to be added to the Idle Task and Tick Interrupt.
ESP-IDF provides its own Idle and Tick Hook API in addition to the hooks
provided by vanilla FreeRTOS. ESP-IDF hooks have the added benefit of
being run time configurable and asymmetrical.
FreeRTOS consists of Idle Hooks and Tick Hooks which allow for application specific functionality to be added to the Idle Task and Tick Interrupt. ESP-IDF provides its own Idle and Tick Hook API in addition to the hooks provided by vanilla FreeRTOS. ESP-IDF hooks have the added benefit of being run time configurable and asymmetrical.
Vanilla FreeRTOS Hooks
^^^^^^^^^^^^^^^^^^^^^^
Idle and Tick Hooks in vanilla FreeRTOS are implemented by the user
defining the functions ``vApplicationIdleHook()`` and ``vApplicationTickHook()``
respectively somewhere in the application. Vanilla FreeRTOS will run the user
defined Idle Hook and Tick Hook on every iteration of the Idle Task and Tick
Interrupt respectively.
Idle and Tick Hooks in vanilla FreeRTOS are implemented by the user defining the functions ``vApplicationIdleHook()`` and ``vApplicationTickHook()`` respectively somewhere in the application. Vanilla FreeRTOS will run the user defined Idle Hook and Tick Hook on every iteration of the Idle Task and Tick Interrupt respectively.
Vanilla FreeRTOS hooks are referred to as **Legacy Hooks** in ESP-IDF FreeRTOS.
To enable legacy hooks, :ref:`CONFIG_FREERTOS_LEGACY_HOOKS` should be enabled
in :doc:`project configuration menu </api-reference/kconfig>`.
Vanilla FreeRTOS hooks are referred to as **Legacy Hooks** in ESP-IDF FreeRTOS. To enable legacy hooks, :ref:`CONFIG_FREERTOS_LEGACY_HOOKS` should be enabled in :doc:`project configuration menu </api-reference/kconfig>`.
.. only:: not CONFIG_FREERTOS_UNICORE
Due to vanilla FreeRTOS being designed for single core, ``vApplicationIdleHook()``
and ``vApplicationTickHook()`` can only be defined once. However, the {IDF_TARGET_NAME} is dual-core
in nature, therefore same Idle Hook and Tick Hook are used for both cores (in other words,
the hooks are symmetrical for both cores).
Due to vanilla FreeRTOS being designed for single core, ``vApplicationIdleHook()`` and ``vApplicationTickHook()`` can only be defined once. However, the {IDF_TARGET_NAME} is dual-core in nature, therefore same Idle Hook and Tick Hook are used for both cores (in other words, the hooks are symmetrical for both cores).
ESP-IDF Idle and Tick Hooks
^^^^^^^^^^^^^^^^^^^^^^^^^^^
For some use-cases it may be necessary for the Idle Tasks or Tick Interrupts to execute multiple hooks
that are configurable at run time.
For some use-cases it may be necessary for the Idle Tasks or Tick Interrupts to execute multiple hooks that are configurable at run time.
.. only:: not CONFIG_FREERTOS_UNICORE
Furthermore, due to the dual-core nature of the {IDF_TARGET_NAME}, it may be necessary for some
applications to have separate hooks for each core.
Furthermore, due to the dual-core nature of the {IDF_TARGET_NAME}, it may be necessary for some applications to have separate hooks for each core.
Therefore, ESP-IDF provides its own hooks API in addition to the legacy hooks provided
by vanilla FreeRTOS.
Therefore, ESP-IDF provides its own hooks API in addition to the legacy hooks provided by vanilla FreeRTOS.
The ESP-IDF tick and idle hooks are registered at run time. Each tick hook and idle hook
must be registered to a specific CPU. When the idle task runs or a tick interrupt
occurs on a particular CPU, the CPU will run each of its registered idle hook and tick hook
in turn.
The ESP-IDF tick and idle hooks are registered at run time. Each tick hook and idle hook must be registered to a specific CPU. When the idle task runs or a tick interrupt occurs on a particular CPU, the CPU will run each of its registered idle hook and tick hook in turn.
.. note:: Tick interrupt stays active whilst cache is disabled and hence ``vApplicationTickHook()`` (legacy case) or ESP-IDF tick hooks must be placed in internal RAM. Please refer to the :ref:`SPI flash API documentation <iram-safe-interrupt-handlers>` for more details.
.. note::
Tick interrupt stays active whilst cache is disabled and hence ``vApplicationTickHook()`` (legacy case) or ESP-IDF tick hooks must be placed in internal RAM. Please refer to the :ref:`SPI flash API documentation <iram-safe-interrupt-handlers>` for more details.
Hooks API Reference
-------------------
.. -------------------------------------------------- TLSP Callback ----------------------------------------------------
.. include-build-file:: inc/esp_freertos_hooks.inc
TLSP Deletion Callbacks
-----------------------
Vanilla FreeRTOS provides a Thread Local Storage Pointers (TLSP) feature. These are pointers stored directly in the Task Control Block (TCB) of a particular task. TLSPs allow each task to have its own unique set of pointers to data structures. Vanilla FreeRTOS expects users to...
- set a task's TLSPs by calling :cpp:func:`vTaskSetThreadLocalStoragePointer` after the task has been created.
- get a task's TLSPs by calling :cpp:func:`pvTaskGetThreadLocalStoragePointer` during the task's lifetime.
- free the memory pointed to by the TLSPs before the task is deleted.
However, there can be instances where users may want the freeing of TLSP memory to be automatic. Therefore, ESP-IDF FreeRTOS provides the additional feature of TLSP deletion callbacks. These user provided deletion callbacks are called automatically when a task is deleted, thus allows the TLSP memory to be cleaned up without needing to add the cleanup logic explicitly to the code of every task.
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.
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.
.. _component-specific-properties:
.. ------------------------------------------ Component Specific Properties --------------------------------------------
Component Specific Properties
-----------------------------
@ -541,3 +442,19 @@ Component Specific Properties
Besides standard component variables that are available with basic cmake build properties, FreeRTOS component also provides arguments (only one so far) for simpler integration with other modules:
- `ORIG_INCLUDE_PATH` - contains an absolute path to freertos root include folder. Thus instead of `#include "freertos/FreeRTOS.h"` you can refer to headers directly: `#include "FreeRTOS.h"`.
.. -------------------------------------------------- API Reference ----------------------------------------------------
API Reference
-------------
Ring Buffer API
^^^^^^^^^^^^^^^
.. include-build-file:: inc/ringbuf.inc
Hooks API
^^^^^^^^^
.. include-build-file:: inc/esp_freertos_hooks.inc

View File

@ -1,6 +1,13 @@
Performance Monitor
===================
.. only:: esp32s3
.. warning::
This feature is not supported in v4.4
The Performance Monitor component provides APIs to use {IDF_TARGET_NAME} internal performance counters to profile functions and
applications.

View File

@ -96,7 +96,7 @@ To skip unnecessary wake-up you can consider initializing an esp_timer with the
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 work 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 will keep counting, however, the speed at which they count will change proportionally to the APB frequency.
The following peripherals work normally even when the APB frequency is changing:
@ -120,7 +120,7 @@ The following drivers will hold the ``ESP_PM_APB_FREQ_MAX`` lock while the drive
- **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.
- **TWAI**: between calls to :cpp:func:`twai_driver_install` and :cpp:func:`twai_driver_uninstall`.
: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 esp32c3: - **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 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:
@ -129,7 +129,7 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
- PCNT
- Sigma-delta
- Timer group
:esp32: - MCPWM
:SOC_MCPWM_SUPPORTED: - MCPWM
API Reference
-------------

View File

@ -227,10 +227,6 @@ Implementation of basic functionality of deep sleep is shown in :example:`protoc
More extensive example in :example:`system/deep_sleep` illustrates usage of various deep sleep wakeup triggers and ULP coprocessor programming.
.. only:: esp32c3
An example in :example:`system/deep_sleep` illustrates usage of deep sleep wakeup triggered by timer.
API Reference
-------------

View File

@ -18,12 +18,6 @@ This is the documentation for Espressif IoT Development Framework (`esp-idf <htt
This document describes using ESP-IDF with the {IDF_TARGET_NAME} SoC.
.. only:: esp32s3
.. warning::
Not all documents are updated for ESP32-S3 yet.
================== ================== ==================
|Get Started|_ |API Reference|_ |H/W Reference|_
------------------ ------------------ ------------------

View File

@ -1,5 +1,5 @@
+---------------+---------------------------------------+-------------------------------------+
| CPU最高频率 | 电源管理锁获取情况 | APB 频率和 CPU 频率 |
| CPU 最高频率 | 电源管理锁获取情况 | APB 频率和 CPU 频率 |
| | | |
+---------------+---------------------------------------+-------------------------------------+
| 240 | 获取 ``ESP_PM_CPU_FREQ_MAX`` | | CPU: 240 MHz |

View File

@ -120,7 +120,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
- **WiFi**:从调用 :cpp:func:`esp_wifi_start`:cpp:func:`esp_wifi_stop` 期间。如果启用了调制解调器睡眠模式,广播关闭时将释放此管理锁。
- **TWAI**:从调用 :cpp:func:`twai_driver_install`:cpp:func:`twai_driver_uninstall` 期间。
:SOC_BT_SUPPORTED and esp32: - **Bluetooth**:从调用 :cpp:func:`esp_bt_controller_enable` 至 :cpp:func:`esp_bt_controller_disable` 期间。如果启用了蓝牙调制解调器,广播关闭时将释放此管理锁。但依然占用 ``ESP_PM_NO_LIGHT_SLEEP`` 锁,除非将 :ref:`CONFIG_BTDM_CTRL_LOW_POWER_CLOCK` 选项设置为 “外部 32 kHz 晶振”。
:SOC_BT_SUPPORTED and esp32c3: - **Bluetooth**:从调用 :cpp:func:`esp_bt_controller_enable` 至 :cpp:func:`esp_bt_controller_disable` 期间。如果启用了蓝牙调制解调器,广播关闭时将释放此管理锁。但依然占用 ``ESP_PM_NO_LIGHT_SLEEP`` 锁。
:SOC_BT_SUPPORTED and not esp32: - **Bluetooth**:从调用 :cpp:func:`esp_bt_controller_enable` 至 :cpp:func:`esp_bt_controller_disable` 期间。如果启用了蓝牙调制解调器,广播关闭时将释放此管理锁。但依然占用 ``ESP_PM_NO_LIGHT_SLEEP`` 锁。
以下外设驱动程序无法感知动态调频,应用程序需自己获取/释放管理锁:
@ -129,7 +129,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
- PCNT
- Sigma-delta
- Timer group
:esp32: - MCPWM
:SOC_MCPWM_SUPPORTED: - MCPWM
API 参考
-------------

View File

@ -18,11 +18,6 @@ ESP-IDF 编程指南
本文档仅包含针对 {IDF_TARGET_NAME} 芯片的 ESP-IDF 使用。
.. only:: esp32s3
.. warning::
ESP32-S3 的相关文档尚未全部更新完毕。
================== ================== ==================
|快速入门|_ |API 参考|_ |H/W 参考|_