diff --git a/docs/conf_common.py b/docs/conf_common.py index e7ad6e2dd..84cbef64b 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -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/")} diff --git a/docs/en/api-guides/freertos-smp.rst b/docs/en/api-guides/freertos-smp.rst index a0dd96d22..780365394 100644 --- a/docs/en/api-guides/freertos-smp.rst +++ b/docs/en/api-guides/freertos-smp.rst @@ -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 task’s 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 task’s 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 isn’t 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 isn’t 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 - other’s 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 + other’s 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 diff --git a/docs/en/api-guides/index.rst b/docs/en/api-guides/index.rst index 946b85f6c..d8f08040d 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -6,14 +6,14 @@ API Guides :maxdepth: 1 Application Level Tracing - :esp32: BluFi + :SOC_BT_SUPPORTED: BluFi Bootloader Build System :esp32: Build System (Legacy GNU Make) Deep Sleep Wake Stubs :esp32s2: Device Firmware Upgrade through USB Error Handling - :esp32: ESP-BLE-MESH + :SOC_BT_SUPPORTED: ESP-BLE-MESH ESP-MESH (Wi-Fi) Core Dump Event Handling diff --git a/docs/en/api-reference/index.rst b/docs/en/api-reference/index.rst index 6ee0b74e7..ebc78d7e2 100644 --- a/docs/en/api-reference/index.rst +++ b/docs/en/api-reference/index.rst @@ -6,7 +6,7 @@ API Reference .. toctree:: :maxdepth: 2 - :esp32: Bluetooth + :SOC_BT_SUPPORTED: Bluetooth Networking Peripherals Protocols diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index 81ab79124..77de48111 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -15,13 +15,13 @@ Peripherals API I2C I2S LED Control - :esp32: MCPWM + :SOC_MCPWM_SUPPORTED: MCPWM Pulse Counter Remote Control :esp32: SD Pull-up Requirements - :esp32: SDMMC Host + :SOC_SDMMC_HOST_SUPPORTED: SDMMC Host SD SPI Host - :esp32: SDIO Slave + :SOC_SDIO_SLAVE_SUPPORTED: SDIO Slave Sigma-delta Modulation SPI Master SPI Slave diff --git a/docs/en/conf.py b/docs/en/conf.py index aca922afe..27253f03f 100644 --- a/docs/en/conf.py +++ b/docs/en/conf.py @@ -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 diff --git a/docs/en/contribute/add-ons-reference.rst b/docs/en/contribute/add-ons-reference.rst index 39493e67b..4cd9c3a99 100644 --- a/docs/en/contribute/add-ons-reference.rst +++ b/docs/en/contribute/add-ons-reference.rst @@ -128,15 +128,6 @@ Other Extensions :idf_file:`docs/idf_extensions/link_roles.py` This is an implementation of a custom `Sphinx Roles `_ 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 ----------------- diff --git a/docs/en/contribute/documenting-code.rst b/docs/en/contribute/documenting-code.rst index dee7a199a..b80c2d861 100644 --- a/docs/en/contribute/documenting-code.rst +++ b/docs/en/contribute/documenting-code.rst @@ -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 `_ 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 diff --git a/docs/en/get-started/index.rst b/docs/en/get-started/index.rst index d54fa4b0a..caaefe9c1 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -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. diff --git a/docs/idf_extensions/exclude_docs.py b/docs/idf_extensions/exclude_docs.py new file mode 100644 index 000000000..72476432e --- /dev/null +++ b/docs/idf_extensions/exclude_docs.py @@ -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'} diff --git a/docs/idf_extensions/gen_defines.py b/docs/idf_extensions/gen_defines.py new file mode 100644 index 000000000..8effe6bc2 --- /dev/null +++ b/docs/idf_extensions/gen_defines.py @@ -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'} diff --git a/docs/idf_extensions/run_doxygen.py b/docs/idf_extensions/run_doxygen.py index 474798ab6..ef98aa841 100644 --- a/docs/idf_extensions/run_doxygen.py +++ b/docs/idf_extensions/run_doxygen.py @@ -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 diff --git a/docs/zh_CN/api-guides/index.rst b/docs/zh_CN/api-guides/index.rst index 9a08e2ad3..b876db8f2 100644 --- a/docs/zh_CN/api-guides/index.rst +++ b/docs/zh_CN/api-guides/index.rst @@ -31,9 +31,9 @@ API 指南 ROM debug console :esp32: RF Calibration WiFi Driver - :esp32: ESP-BLE-MESH + :SOC_BT_SUPPORTED: ESP-BLE-MESH ESP-MESH (Wi-Fi) - :esp32: BluFi + :SOC_BT_SUPPORTED: BluFi External SPI-connected RAM 链接脚本生成机制 LwIP diff --git a/docs/zh_CN/api-reference/peripherals/index.rst b/docs/zh_CN/api-reference/peripherals/index.rst index dd44510d4..0c27a6fed 100644 --- a/docs/zh_CN/api-reference/peripherals/index.rst +++ b/docs/zh_CN/api-reference/peripherals/index.rst @@ -14,12 +14,12 @@ I2C I2S LED Control - :esp32: MCPWM + :SOC_MCPWM_SUPPORTED: MCPWM Pulse Counter Remote Control - :esp32: SDMMC Host + :SOC_SDMMC_HOST_SUPPORTED: SDMMC Host SD SPI Host - :esp32: SDIO Slave + :SOC_SDIO_SLAVE_SUPPORTED: SDIO Slave Sigma-delta Modulation SPI Master SPI Slave @@ -28,5 +28,5 @@ Touch Sensor UART -本部分的 API 示例代码存放在 ESP-IDF 示例项目的 :example:`peripherals` 目录下。 +本部分的 API 示例代码存放在 ESP-IDF 示例项目的 :example:`peripherals` 目录下。 diff --git a/docs/zh_CN/conf.py b/docs/zh_CN/conf.py index 3eba509d3..04ed16035 100644 --- a/docs/zh_CN/conf.py +++ b/docs/zh_CN/conf.py @@ -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