doc: add generation of tags from sdkconfig and x_caps.h headers

Also updates the way we handle exclude_patterns to use the new tags

Closes IDF-1484
This commit is contained in:
Marius Vikhammer 2020-04-30 16:55:12 +08:00 committed by bot
parent 695f075a13
commit fbb54184ef
15 changed files with 328 additions and 227 deletions

View file

@ -67,6 +67,8 @@ extensions = ['breathe',
'idf_extensions.gen_idf_tools_links',
'idf_extensions.format_idf_target',
'idf_extensions.latex_builder',
'idf_extensions.gen_defines',
'idf_extensions.exclude_docs',
# from https://github.com/pfalcon/sphinx_selective_exclude
'sphinx_selective_exclude.eager_only',
@ -124,47 +126,49 @@ print('Version: {0} Release: {1}'.format(version, release))
exclude_patterns = ['**/inc/**', '_static', '**/_build']
# Add target-specific excludes based on tags (for the IDF_TARGET). Haven't found any better way to do this yet
def update_exclude_patterns(tags):
if "esp32" not in tags:
# Exclude ESP32-only document pages so they aren't found in the initial search for .rst files
# note: in toctrees, these also need to be marked with a :esp32: filter
for e in ['api-guides/blufi.rst',
'api-guides/build-system-legacy.rst',
'api-guides/esp-ble-mesh/**',
'api-guides/RF_calibration.rst', # temporary until support re-added in esp_wifi
'api-guides/ulp-legacy.rst',
'api-guides/unit-tests-legacy.rst',
'api-guides/ulp_instruction_set.rst',
'api-guides/jtag-debugging/configure-wrover.rst',
'api-reference/system/himem.rst',
'api-reference/bluetooth/**',
'api-reference/peripherals/sdio_slave.rst',
'api-reference/peripherals/esp_slave_protocol.rst',
'api-reference/peripherals/mcpwm.rst',
'api-reference/peripherals/sd_pullup_requirements.rst',
'api-reference/peripherals/sdmmc_host.rst',
'api-reference/protocols/esp_serial_slave_link.rst',
'api-reference/system/ipc.rst',
'get-started-legacy/**',
'security/secure-boot-v1.rst',
'security/secure-boot-v2.rst',
'gnu-make-legacy.rst',
'hw-reference/esp32/**',
]:
exclude_patterns.append(e)
BT_DOCS = ['api-guides/blufi.rst',
'api-guides/esp-ble-mesh/**',
'api-reference/bluetooth/**']
if "esp32s2" not in tags:
# Exclude ESP32-S2-only document pages so they aren't found in the initial search for .rst files
# note: in toctrees, these also need to be marked with a :esp32: filter
for e in ['esp32s2.rst',
'hw-reference/esp32s2/**',
'api-guides/dfu.rst',
'api-guides/ulps2_instruction_set.rst',
'api-reference/peripherals/hmac.rst',
'api-reference/peripherals/temp_sensor.rst']:
exclude_patterns.append(e)
SDMMC_DOCS = ['api-reference/peripherals/sdmmc_host.rst',
'api-reference/peripherals/sd_pullup_requirements.rst']
SDIO_SLAVE_DOCS = ['api-reference/peripherals/sdio_slave.rst',
'api-reference/peripherals/esp_slave_protocol.rst',
'api-reference/protocols/esp_serial_slave_link.rst']
MCPWM_DOCS = ['api-reference/peripherals/mcpwm.rst']
LEGACY_DOCS = ['api-guides/build-system-legacy.rst',
'gnu-make-legacy.rst',
'api-guides/ulp-legacy.rst',
'api-guides/unit-tests-legacy.rst',
'get-started-legacy/**']
ESP32_DOCS = ['api-guides/ulp_instruction_set.rst',
'api-guides/jtag-debugging/configure-wrover.rst',
'api-reference/system/himem.rst',
'api-guides/RF_calibration.rst',
'api-reference/system/ipc.rst',
'security/secure-boot-v1.rst',
'security/secure-boot-v2.rst',
'hw-reference/esp32/**'] + LEGACY_DOCS
ESP32S2_DOCS = ['esp32s2.rst',
'hw-reference/esp32s2/**',
'api-guides/ulps2_instruction_set.rst',
'api-guides/dfu.rst',
'api-reference/peripherals/hmac.rst',
'api-reference/peripherals/temp_sensor.rst'
'']
# format: {tag needed to include: documents to included}, tags are parsed from sdkconfig and peripheral_caps.h headers
conditional_include_dict = {'SOC_BT_SUPPORTED':BT_DOCS,
'SOC_SDMMC_HOST_SUPPORTED':SDMMC_DOCS,
'SOC_SDIO_SLAVE_SUPPORTED':SDIO_SLAVE_DOCS,
'SOC_MCPWM_SUPPORTED':MCPWM_DOCS,
'esp32':ESP32_DOCS,
'esp32s2':ESP32S2_DOCS}
# The reST default role (used for this markup: `text`) to use for all
# documents.
@ -378,6 +382,8 @@ def setup(app):
app.add_config_value('idf_target', None, 'env')
app.add_config_value('idf_targets', None, 'env')
app.add_config_value('conditional_include_dict', None, 'env')
# Breathe extension variables (depend on build_dir)
# note: we generate into xml_in and then copy_if_modified to xml dir
app.config.breathe_projects = {"esp32-idf": os.path.join(app.config.build_dir, "xml_in/")}

View file

@ -4,7 +4,7 @@ ESP-IDF FreeRTOS SMP Changes
Overview
--------
.. only:: esp32
.. only:: not CONFIG_FREERTOS_UNICORE
The vanilla FreeRTOS is designed to run on a single core. However the ESP32 is
dual core containing a Protocol CPU (known as **CPU 0** or **PRO_CPU**) and an
@ -25,7 +25,7 @@ see :doc:`ESP-IDF FreeRTOS Additions<../api-reference/system/freertos_additions>
port of FreeRTOS v8.2.0, a number of FreeRTOS v9.0.0 features have been backported
to ESP-IDF.
.. only:: esp32
.. 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
@ -155,133 +155,133 @@ ESP-IDF FreeRTOS (see :ref:`backported-features`).
For more details see :component_file:`freertos/tasks.c`
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
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.
- ``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
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.
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
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.
respectively with ``tskNO_AFFINITY`` as the ``xCoreID`` value.
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
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.
Scheduling
----------
The vanilla FreeRTOS implements scheduling in the ``vTaskSwitchContext()``
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.
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.
.. _round-robin-scheduling:
Round Robin Scheduling
^^^^^^^^^^^^^^^^^^^^^^
Given multiple tasks in the Ready state and of the same priority, vanilla
Given multiple tasks in the Ready state and of the same priority, vanilla
FreeRTOS implements Round Robin scheduling between each task. This will result
in running those tasks in turn each time the scheduler is called
(e.g. every tick interrupt). On the other hand, the ESP-IDF FreeRTOS scheduler
may skip tasks when Round Robin scheduling multiple Ready state tasks of the
in running those tasks in turn each time the scheduler is called
(e.g. every tick interrupt). On the other hand, the ESP-IDF FreeRTOS scheduler
may skip tasks when Round Robin scheduling multiple Ready state tasks of the
same priority.
The issue of skipping tasks during Round Robin scheduling arises from the way
the Ready Tasks List is implemented in FreeRTOS. In vanilla FreeRTOS,
``pxReadyTasksList`` is used to store a list of tasks that are in the Ready
state. The list is implemented as an array of length ``configMAX_PRIORITIES``
where each element of the array is a linked list. Each linked list is of type
``List_t`` and contains TCBs of tasks of the same priority that are in the
Ready state. The following diagram illustrates the ``pxReadyTasksList``
The issue of skipping tasks during Round Robin scheduling arises from the way
the Ready Tasks List is implemented in FreeRTOS. In vanilla FreeRTOS,
``pxReadyTasksList`` is used to store a list of tasks that are in the Ready
state. The list is implemented as an array of length ``configMAX_PRIORITIES``
where each element of the array is a linked list. Each linked list is of type
``List_t`` and contains TCBs of tasks of the same priority that are in the
Ready state. The following diagram illustrates the ``pxReadyTasksList``
structure.
.. figure:: ../../_static/freertos-ready-task-list.png
:align: center
:alt: Vanilla FreeRTOS Ready Task List Structure
Illustration of FreeRTOS Ready Task List Data Structure
Illustration of FreeRTOS Ready Task List Data Structure
Each linked list also contains a ``pxIndex`` which points to the last TCB
returned when the list was queried. This index allows the ``vTaskSwitchContext()``
to start traversing the list at the TCB immediately after ``pxIndex`` hence
Each linked list also contains a ``pxIndex`` which points to the last TCB
returned when the list was queried. This index allows the ``vTaskSwitchContext()``
to start traversing the list at the TCB immediately after ``pxIndex`` hence
implementing Round Robin Scheduling between tasks of the same priority.
In ESP-IDF FreeRTOS, the Ready Tasks List is shared between cores hence
``pxReadyTasksList`` will contain tasks pinned to different cores. When a core
calls the scheduler, it is able to look at the ``xCoreID`` member of each TCB
in the list to determine if a task is allowed to run on calling the core. The
In ESP-IDF FreeRTOS, the Ready Tasks List is shared between cores hence
``pxReadyTasksList`` will contain tasks pinned to different cores. When a core
calls the scheduler, it is able to look at the ``xCoreID`` member of each TCB
in the list to determine if a task is allowed to run on calling the core. The
ESP-IDF FreeRTOS ``pxReadyTasksList`` is illustrated below.
.. figure:: ../../_static/freertos-ready-task-list-smp.png
:align: center
:alt: ESP-IDF FreeRTOS Ready Task List Structure
Illustration of FreeRTOS Ready Task List Data Structure in ESP-IDF
Therefore when **PRO_CPU** calls the scheduler, it will only consider the tasks
in blue or purple. Whereas when **APP_CPU** calls the scheduler, it will only
Therefore when **PRO_CPU** calls the scheduler, it will only consider the tasks
in blue or purple. Whereas when **APP_CPU** calls the scheduler, it will only
consider the tasks in orange or purple.
Although each TCB has an ``xCoreID`` in ESP-IDF FreeRTOS, the linked list of
each priority only has a single ``pxIndex``. Therefore when the scheduler is
called from a particular core and traverses the linked list, it will skip all
TCBs pinned to the other core and point the pxIndex at the selected task. If
the other core then calls the scheduler, it will traverse the linked list
Although each TCB has an ``xCoreID`` in ESP-IDF FreeRTOS, the linked list of
each priority only has a single ``pxIndex``. Therefore when the scheduler is
called from a particular core and traverses the linked list, it will skip all
TCBs pinned to the other core and point the pxIndex at the selected task. If
the other core then calls the scheduler, it will traverse the linked list
starting at the TCB immediately after ``pxIndex``. Therefore, TCBs skipped on
the previous scheduler call from the other core would not be considered on the
current scheduler call. This issue is demonstrated in the following
the previous scheduler call from the other core would not be considered on the
current scheduler call. This issue is demonstrated in the following
illustration.
.. figure:: ../../_static/freertos-ready-task-list-smp-pxIndex.png
:align: center
:alt: ESP-IDF pxIndex Behavior
Illustration of pxIndex behavior in ESP-IDF FreeRTOS
Referring to the illustration above, assume that priority 9 is the highest
priority, and none of the tasks in priority 9 will block hence will always be
Referring to the illustration above, assume that priority 9 is the highest
priority, and none of the tasks in priority 9 will block hence will always be
either in the running or Ready state.
1) **PRO_CPU** calls the scheduler and selects Task A to run, hence moves
1) **PRO_CPU** calls the scheduler and selects Task A to run, hence moves
``pxIndex`` to point to Task A
2) **APP_CPU** calls the scheduler and starts traversing from the task after
``pxIndex`` which is Task B. However Task B is not selected to run as it is not
pinned to **APP_CPU** hence it is skipped and Task C is selected instead.
2) **APP_CPU** calls the scheduler and starts traversing from the task after
``pxIndex`` which is Task B. However Task B is not selected to run as it is not
pinned to **APP_CPU** hence it is skipped and Task C is selected instead.
``pxIndex`` now points to Task C
3) **PRO_CPU** calls the scheduler and starts traversing from Task D. It skips
Task D and selects Task E to run and points ``pxIndex`` to Task E. Notice that
Task B isnt traversed because it was skipped the last time **APP_CPU** called
3) **PRO_CPU** calls the scheduler and starts traversing from Task D. It skips
Task D and selects Task E to run and points ``pxIndex`` to Task E. Notice that
Task B isnt traversed because it was skipped the last time **APP_CPU** called
the scheduler to traverse the list.
4) The same situation with Task D will occur if **APP_CPU** calls the
4) The same situation with Task D will occur if **APP_CPU** calls the
scheduler again as ``pxIndex`` now points to Task E
One solution to the issue of task skipping is to ensure that every task will
enter a blocked state so that they are removed from the Ready Task List.
Another solution is to distribute tasks across multiple priorities such that
a given priority will not be assigned multiple tasks that are pinned to
Another solution is to distribute tasks across multiple priorities such that
a given priority will not be assigned multiple tasks that are pinned to
different cores.
.. _scheduler-suspension:
@ -289,22 +289,22 @@ different cores.
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
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 ISRSs 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
current running task or ISRSs 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.
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
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.
In general, it's better to use other RTOS primitives like mutex semaphores to protect
@ -313,34 +313,34 @@ against data shared between tasks, rather than :cpp:func:`vTaskSuspendAll`.
.. _tick-interrupt-synchronicity:
Tick Interrupt Synchronicity
Tick Interrupt Synchronicity
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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
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.
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
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.
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,
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
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.
@ -349,47 +349,47 @@ to unblock multiple tasks at the same time.
Critical Sections & Disabling Interrupts
----------------------------------------
Vanilla FreeRTOS implements critical sections in ``vTaskEnterCritical`` which
disables the scheduler and calls ``portDISABLE_INTERRUPTS``. This prevents
context switches and servicing of ISRs during a critical section. Therefore,
critical sections are used as a valid protection method against simultaneous
Vanilla FreeRTOS implements critical sections in ``vTaskEnterCritical`` which
disables the scheduler and calls ``portDISABLE_INTERRUPTS``. This prevents
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:: esp32
.. only:: not CONFIG_FREERTOS_UNICORE
On the other hand, the ESP32 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
On the other hand, the ESP32 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:: esp32s2
.. 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 on top of specific spinlock component
and calls to enter or exit a critical must provide a spinlock object that
is associated with a shared resource requiring access protection.
referred by portMUX_Type objects on top of specific spinlock component
and calls to enter or exit a critical must provide a spinlock object that
is associated with a shared resource requiring access protection.
When entering a critical section in ESP-IDF FreeRTOS, the calling core will disable
its scheduler and interrupts similar to the vanilla FreeRTOS implementation. However,
the calling core will also take the locks whilst the other core is left unaffected during
the critical section. If the other core attempts to take the spinlock, it
will spin until the lock is released. Therefore, the ESP-IDF FreeRTOS
its scheduler and interrupts similar to the vanilla FreeRTOS implementation. However,
the calling core will also take the locks whilst the other core is left unaffected during
the critical section. If the other core attempts to take the spinlock, 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
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 :cpp:func:`vTaskEnterCritical`
- ``taskENTER_CRITICAL(mux)``, ``taskENTER_CRITICAL_ISR(mux)``,
``portENTER_CRITICAL(mux)``, ``portENTER_CRITICAL_ISR(mux)`` are all macro
defined to call :cpp:func:`vTaskEnterCritical`
- ``taskEXIT_CRITICAL(mux)``, ``taskEXIT_CRITICAL_ISR(mux)``,
``portEXIT_CRITICAL(mux)``, ``portEXIT_CRITICAL_ISR(mux)`` are all macro
- ``taskEXIT_CRITICAL(mux)``, ``taskEXIT_CRITICAL_ISR(mux)``,
``portEXIT_CRITICAL(mux)``, ``portEXIT_CRITICAL_ISR(mux)`` are all macro
defined to call :cpp:func:`vTaskExitCritical`
- ``portENTER_CRITICAL_SAFE(mux)``, ``portEXIT_CRITICAL_SAFE(mux)`` macro identifies
@ -400,14 +400,14 @@ The ESP-IDF FreeRTOS critical section functions have been modified as follows…
For more details see :component_file:`soc/include/soc/spinlock.h`
and :component_file:`freertos/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 type of call should not
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 type of call should not
matter.
.. only:: esp32
.. only:: not CONFIG_FREERTOS_UNICORE
.. _floating-points:
@ -415,16 +415,16 @@ matter.
-------------------------
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
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
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``,
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
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``.
@ -495,7 +495,7 @@ The ESP-IDF FreeRTOS can be configured in the project configuration menu
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:: esp32
.. 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
@ -504,9 +504,9 @@ ESP-IDF FreeRTOS configurations, see :doc:`FreeRTOS <../api-reference/kconfig>`
effects of running ESP-IDF FreeRTOS on a single core, search for
occurences of ``CONFIG_FREERTOS_UNICORE`` in the ESP-IDF components.
.. only:: esp32s2
.. only:: CONFIG_FREERTOS_UNICORE
As ESP32-S2 is a single core SoC, the config item :ref:`CONFIG_FREERTOS_UNICORE` is
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

View file

@ -6,14 +6,14 @@ API Guides
:maxdepth: 1
Application Level Tracing <app_trace>
:esp32: BluFi <blufi>
:SOC_BT_SUPPORTED: BluFi <blufi>
Bootloader <bootloader>
Build System <build-system>
:esp32: Build System (Legacy GNU Make) <build-system-legacy>
Deep Sleep Wake Stubs <deep-sleep-stub>
:esp32s2: Device Firmware Upgrade through USB <dfu>
Error Handling <error-handling>
:esp32: ESP-BLE-MESH <esp-ble-mesh/ble-mesh-index>
:SOC_BT_SUPPORTED: ESP-BLE-MESH <esp-ble-mesh/ble-mesh-index>
ESP-MESH (Wi-Fi) <mesh>
Core Dump <core_dump>
Event Handling <event-handling>

View file

@ -6,7 +6,7 @@ API Reference
.. toctree::
:maxdepth: 2
:esp32: Bluetooth <bluetooth/index>
:SOC_BT_SUPPORTED: Bluetooth <bluetooth/index>
Networking <network/index>
Peripherals <peripherals/index>
Protocols <protocols/index>

View file

@ -15,13 +15,13 @@ Peripherals API
I2C <i2c>
I2S <i2s>
LED Control <ledc>
:esp32: MCPWM <mcpwm>
:SOC_MCPWM_SUPPORTED: MCPWM <mcpwm>
Pulse Counter <pcnt>
Remote Control <rmt>
:esp32: SD Pull-up Requirements <sd_pullup_requirements>
:esp32: SDMMC Host <sdmmc_host>
:SOC_SDMMC_HOST_SUPPORTED: SDMMC Host <sdmmc_host>
SD SPI Host <sdspi_host>
:esp32: SDIO Slave <sdio_slave>
:SOC_SDIO_SLAVE_SUPPORTED: SDIO Slave <sdio_slave>
Sigma-delta Modulation <sigmadelta>
SPI Master <spi_master>
SPI Slave <spi_slave>

View file

@ -18,5 +18,3 @@ copyright = u'2016 - 2020, Espressif Systems (Shanghai) CO., LTD'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
language = 'en'
update_exclude_patterns(tags) # noqa: F405, need to import * from conf_common

View file

@ -128,15 +128,6 @@ Other Extensions
:idf_file:`docs/idf_extensions/link_roles.py`
This is an implementation of a custom `Sphinx Roles <https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html>`_ to help linking from documentation to specific files and folders in `ESP-IDF`_. For description of implemented roles please see :ref:`link-custom-roles` and :ref:`link-language-versions`.
:idf_file:`docs/idf_extensions/run_doxygen.py`
Subscribes to ``idf-info`` event and runs Doxygen (:idf_file:`docs/Doxyfile`) to generate XML files describing key headers, and then runs Breathe to convert these to ``.inc`` files which can be included directly into API reference pages.
Pushes a number of target-specific custom environment variables into Doxygen, including all macros defined in the project's default ``sdkconfig.h`` file and all macros defined in all ``soc`` component ``xxx_caps.h`` headers. This means that public API headers can depend on target-specific configuration options or ``soc`` capabilities headers options as ``#ifdef`` & ``#if`` preprocessor selections in the header.
This means we can generate different Doxygen files, depending on the target we are building docs for.
Please refer to :doc:`documenting-code` and :doc:`../api-reference/template`, section **API Reference** for additional details on this process.
:idf_file:`docs/idf_extensions/esp_err_definitions.py`
Small wrapper extension that calls ``gen_esp_err_to_name.py`` and updates the included .rst file if it has changed.
@ -166,6 +157,27 @@ Other Extensions
Creates and adds the espidf.sty latex package to the output directory, which contains some macros for run-time variables such as IDF-Target.
:idf_file:`docs/idf_extensions/gen_defines.py`
Sphinx extension to integrate defines from IDF into the Sphinx build, runs after the IDF dummy project has been built.
Parses defines and adds them as sphinx tags.
Emits the new 'idf-defines-generated' event which has a dictionary of raw text define values that other extensions can use to generate relevant data.
:idf_file:`docs/idf_extensions/exclude_docs.py`
Sphinx extension that updates the excluded documents according to the conditional_include_dict {tag:documents}. If the tag is set, then the list of documents will be included.
Subscribes to ``idf-defines-generated`` as it relies on the sphinx tags to determine which documents to exclude
:idf_file:`docs/idf_extensions/run_doxygen.py`
Subscribes to ``idf-defines-generated`` event and runs Doxygen (:idf_file:`docs/Doxyfile`) to generate XML files describing key headers, and then runs Breathe to convert these to ``.inc`` files which can be included directly into API reference pages.
Pushes a number of target-specific custom environment variables into Doxygen, including all macros defined in the project's default ``sdkconfig.h`` file and all macros defined in all ``soc`` component ``xxx_caps.h`` headers. This means that public API headers can depend on target-specific configuration options or ``soc`` capabilities headers options as ``#ifdef`` & ``#if`` preprocessor selections in the header.
This means we can generate different Doxygen files, depending on the target we are building docs for.
Please refer to :doc:`documenting-code` and :doc:`../api-reference/template`, section **API Reference** for additional details on this process.
Related Documents
-----------------

View file

@ -252,11 +252,22 @@ The documentation for all of Espressif's chips is built from the same files. To
Exclusion of content based on chip-target
"""""""""""""""""""""""""""""""""""""""""
Occasionally there will be content that is only relevant for one of targets. When this is the case, you can exclude that content by using the ''.. only:: TARGET'' directive, where you replace 'TARGET' with one of the chip names. As of now the following targets are available:
Occasionally there will be content that is only relevant for one of targets. When this is the case, you can exclude that content by using the ''.. only:: TAG'' directive, where you replace 'TAG' with one of the following names:
Chip name:
* esp32
* esp32s2
Define identifiers from 'sdkconfig.h', generated by the default menuconfig settings for the target, e.g:
* CONFIG_FREERTOS_UNICORE
Define identifiers from the soc '*_caps' headers, e.g:
* SOC_BT_SUPPORTED
* SOC_CAN_SUPPORTED
Example:
.. code-block:: none
@ -265,6 +276,14 @@ Example:
ESP32 specific content.
This directive also supports the boolean operators 'and', 'or' and 'not'. Example:
.. code-block:: none
.. only:: SOC_BT_SUPPORTED and CONFIG_FREERTOS_UNICORE
BT specific content only relevant for single-core targets.
This functionality is provided by the `Sphinx selective exclude <https://github.com/pfalcon/sphinx_selective_exclude>`_ extension.
A weakness in this extension is that it does not correctly handle the case were you exclude a section, and that is directly followed by a labeled new section. In these cases everything will render correctly, but the label will not correctly link to the section that follows. A temporary work-around for the cases were this can't be avoided is the following:
@ -290,7 +309,7 @@ A weakness in this extension is that it does not correctly handle the case were
^^^^^^^^^
Section 2 content
The :TARGET: role is used for excluding content from a table of content tree. For example:
The :TAG: role is used for excluding content from a table of content tree. For example:
.. code-block:: none
@ -302,16 +321,20 @@ The :TARGET: role is used for excluding content from a table of content tree. Fo
When building the documents, Sphinx will use the above mentioned directive and role to include or exclude content based on the target tag it was called with.
.. note:: If excluding an entire document from the toctree based on targets, it's necessary to also update the ``exclude_patterns`` list in :idf_file:`docs/conf_common.py` to exclude the file for other targets, or a Sphinx warning "WARNING: document isn't included in any toctree" will be generated..
.. note::
If you need to exclude content inside a list or bullet points then this should be done by using the '':TARGET:'' role inside the ''.. list:: '' directive.
If excluding an entire document from the toctree based on targets, it's necessary to also update the ``exclude_patterns`` list in :idf_file:`docs/conf_common.py` to exclude the file for other targets, or a Sphinx warning "WARNING: document isn't included in any toctree" will be generated..
The recommended way of doing it is adding the document to one of the list that gets included in ``conditional_include_dict`` in :idf_file:`docs/conf_common.py`, e.g. a document which should only be shown for BT capable targets should be added to ``BT_DOCS``. :idf_file:`docs/idf_extensions/exclude_docs.py` will then take care of adding it to ``exclude_patterns`` if the corresponding tag is not set.
If you need to exclude content inside a list or bullet points then this should be done by using the '':TAG:'' role inside the ''.. list:: '' directive.
.. code-block:: none
.. list::
:esp32: - ESP32 specific content
:esp32s2: - ESP32 S2 specific content
:SOC_BT_SUPPORTED: - BT specific content
- Common bullet point
- Also common bullet point

View file

@ -20,8 +20,8 @@ Introduction
.. list::
* Wi-Fi (2.4 GHz band)
:esp32: * Bluetooth
:esp32: * Dual high performance cores
:SOC_BT_SUPPORTED: * Bluetooth
:CONFIG_FREERTOS_UNICORE: * Dual high performance cores
* Ultra Low Power co-processor
* Multiple peripherals
:esp32s2: * Built-in security hardware
@ -322,7 +322,7 @@ Linux and macOS
.. code-block:: bash
cd ~/esp/hello_world
idf.py set-target {IDF_TARGET_CL}
idf.py set-target {IDF_TARGET_CL}
idf.py menuconfig
Windows
@ -590,7 +590,7 @@ See also:
Now you are ready to try some other :idf:`examples`, or go straight to developing your own applications.
.. important::
.. important::
Some of examples do not support {IDF_TARGET_NAME} because required hardware is not included in {IDF_TARGET_NAME} so it cannot be supported.

View file

@ -0,0 +1,12 @@
# Updates the excluded documents according to the conditional_include_dict {tag:documents}
def update_exclude_patterns(app, config):
for tag, docs in config.conditional_include_dict.items():
if not app.tags.has(tag):
app.config.exclude_patterns.extend(docs)
def setup(app):
# Tags are generated together with defines
app.connect('config-inited', update_exclude_patterns)
return {'parallel_read_safe': True, 'parallel_write_safe': True, 'version': '0.1'}

View file

@ -0,0 +1,72 @@
# Sphinx extension to integrate defines into the Sphinx Build
#
# Runs after the IDF dummy project has been built
#
# Then emits the new 'idf-defines-generated' event which has a dictionary of raw text define values
# that other extensions can use to generate relevant data.
import glob
import os
import subprocess
import re
def generate_defines(app, project_description):
sdk_config_path = os.path.join(project_description["build_dir"], "config")
# Parse kconfig macros to pass into doxygen
#
# TODO: this should use the set of "config which can't be changed" eventually,
# not the header
defines = get_defines(os.path.join(project_description["build_dir"],
"config", "sdkconfig.h"), sdk_config_path)
# Add all SOC _caps.h headers and kconfig macros to the defines
#
# kind of a hack, be nicer to add a component info dict in project_description.json
soc_path = [p for p in project_description["build_component_paths"] if p.endswith("/soc")][0]
soc_headers = glob.glob(os.path.join(soc_path, "soc", project_description["target"],
"include", "soc", "*_caps.h"))
assert len(soc_headers) > 0
for soc_header in soc_headers:
defines.update(get_defines(soc_header, sdk_config_path))
add_tags(app, defines)
app.emit('idf-defines-generated', defines)
def get_defines(header_path, sdk_config_path):
defines = {}
# Note: we run C preprocessor here without any -I arguments (except "sdkconfig.h"), so assumption is
# that these headers are all self-contained and don't include any other headers
# not in the same directory
print("Reading macros from %s..." % (header_path))
processed_output = subprocess.check_output(["xtensa-esp32-elf-gcc", "-I", sdk_config_path,
"-dM", "-E", header_path]).decode()
for line in processed_output.split("\n"):
line = line.strip()
m = re.search("#define ([^ ]+) ?(.*)", line)
if m and not m.group(1).startswith("_"):
defines[m.group(1)] = m.group(2)
return defines
def add_tags(app, defines):
# try to parse define values as ints and add to tags
for name, value in defines.items():
try:
define_value = int(value.strip("()"))
if define_value > 0:
app.tags.add(name)
except ValueError:
continue
def setup(app):
app.connect('idf-info', generate_defines)
app.add_event('idf-defines-generated')
return {'parallel_read_safe': True, 'parallel_write_safe': True, 'version': '0.1'}

View file

@ -2,7 +2,6 @@
from __future__ import print_function
from __future__ import unicode_literals
from io import open
import glob
import os
import os.path
import re
@ -45,28 +44,9 @@ def _parse_defines(header_path, sdk_config_path):
return defines
def generate_doxygen(app, project_description):
def generate_doxygen(app, defines):
build_dir = os.path.dirname(app.doctreedir.rstrip(os.sep))
sdk_config_path = os.path.join(project_description["build_dir"], "config")
# Parse kconfig macros to pass into doxygen
#
# TODO: this should use the set of "config which can't be changed" eventually,
# not the header
defines = _parse_defines(os.path.join(project_description["build_dir"],
"config", "sdkconfig.h"), sdk_config_path)
# Add all SOC _caps.h headers to the defines
#
# kind of a hack, be nicer to add a component info dict in project_description.json
soc_path = [p for p in project_description["build_component_paths"] if p.endswith("/soc")][0]
soc_headers = glob.glob(os.path.join(soc_path, "soc", project_description["target"],
"include", "soc", "*_caps.h"))
assert len(soc_headers) > 0
for soc_header in soc_headers:
defines.update(_parse_defines(soc_header, sdk_config_path))
# Call Doxygen to get XML files from the header files
print("Calling Doxygen to generate latest XML files")
doxy_env = os.environ

View file

@ -31,9 +31,9 @@ API 指南
ROM debug console <romconsole>
:esp32: RF Calibration <RF_calibration>
WiFi Driver <wifi>
:esp32: ESP-BLE-MESH <esp-ble-mesh/ble-mesh-index>
:SOC_BT_SUPPORTED: ESP-BLE-MESH <esp-ble-mesh/ble-mesh-index>
ESP-MESH (Wi-Fi) <mesh>
:esp32: BluFi <blufi>
:SOC_BT_SUPPORTED: BluFi <blufi>
External SPI-connected RAM <external-ram>
链接脚本生成机制 <linker-script-generation>
LwIP <lwip>

View file

@ -14,12 +14,12 @@
I2C <i2c>
I2S <i2s>
LED Control <ledc>
:esp32: MCPWM <mcpwm>
:SOC_MCPWM_SUPPORTED: MCPWM <mcpwm>
Pulse Counter <pcnt>
Remote Control <rmt>
:esp32: SDMMC Host <sdmmc_host>
:SOC_SDMMC_HOST_SUPPORTED: SDMMC Host <sdmmc_host>
SD SPI Host <sdspi_host>
:esp32: SDIO Slave <sdio_slave>
:SOC_SDIO_SLAVE_SUPPORTED: SDIO Slave <sdio_slave>
Sigma-delta Modulation <sigmadelta>
SPI Master <spi_master>
SPI Slave <spi_slave>
@ -28,5 +28,5 @@
Touch Sensor <touch_pad>
UART <uart>
本部分的 API 示例代码存放在 ESP-IDF 示例项目的 :example:`peripherals` 目录下。
本部分的 API 示例代码存放在 ESP-IDF 示例项目的 :example:`peripherals` 目录下。

View file

@ -18,5 +18,3 @@ copyright = u'2016 - 2020 乐鑫信息科技(上海)股份有限公司'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
language = 'zh_CN'
update_exclude_patterns(tags) # noqa: F405, need to import * from conf_common