docs: Provide Chinese translation for api-reference/system/ipc.rst

This commit is contained in:
Ren Pei Ying 2023-10-13 14:40:20 +08:00
parent ca1cd88e25
commit 3a16224d1d
2 changed files with 201 additions and 42 deletions

View File

@ -1,51 +1,57 @@
Inter-Processor Call
====================
Inter-Processor Call (IPC)
==========================
:link_to_translation:`zh_CN:[中文]`
.. note::
The IPC is an **Inter-Processor Call** and **NOT Inter-Process Communication** as found on other operating systems.
IPC stands for an **"Inter-Processor Call"** and **NOT** "Inter-Process Communication" as found on other operating systems.
Overview
--------
Due to the dual core nature of the {IDF_TARGET_NAME}, there are instances where a certain callback must be run in the context of a particular CPU such as:
Due to the dual core nature of the {IDF_TARGET_NAME}, there are some scenarios where a certain callback must be executed from a particular core such as:
- When allocating an ISR to an interrupt source of a particular CPU (applies to freeing a particular CPU's interrupt source as well).
- On particular chips (such as the ESP32), accessing memory that is exclusive to a particular CPU (such as RTC Fast Memory).
- Reading the registers/state of another CPU.
- When allocating an ISR to an interrupt source of a particular core (applies to freeing a particular core's interrupt source as well)
- On particular chips (such as the ESP32), accessing memory that is exclusive to a particular core (such as RTC Fast Memory)
- Reading the registers/state of another core
The IPC (Inter-Processor Call) feature allows a particular CPU (the calling CPU) to trigger the execution of a callback function on another CPU (the target CPU). The IPC feature allows execution of a callback function on the target CPU in either ``a task context``, or ``an interrupt context``. Depending on the context that the callback function is executed in, different restrictions apply to the implementation of the callback function.
The IPC (Inter-Processor Call) feature allows a particular core (the calling core) to trigger the execution of a callback function on another core (the target core). The IPC feature allows execution of a callback function on the target core in either a task context, or an interrupt context. Depending on the context that the callback function is executed in, different restrictions apply to the implementation of the callback function.
IPC in Task Context
-------------------
The IPC feature implements callback execution in a task context by creating an IPC task for each CPU during application startup. When the calling CPU needs to execute a callback on the target CPU, the callback will execute in the context of the target CPU's IPC task.
The IPC feature implements callback execution in a task context by creating an IPC task for each core during application startup. When the calling core needs to execute a callback on the target core, the callback will execute in the context of the target core's IPC task.
When using IPCs in a task context, users need to consider the following:
- IPC callbacks should ideally be simple and short. **An IPC callback should avoid attempting to block or yield**.
- The IPC tasks are created at the highest possible priority (i.e., ``configMAX_PRIORITIES - 1``) thus the callback should also run at that priority as a result. However, :ref:`CONFIG_ESP_IPC_USES_CALLERS_PRIORITY` is enabled by default which temporarily lowers the priority of the target CPU's IPC task to the calling CPU before executing the callback.
- IPC callbacks should ideally be simple and short. An IPC callback **must never block or yield**.
- The IPC tasks are created at the highest possible priority (i.e., ``configMAX_PRIORITIES - 1``).
- If :ref:`CONFIG_ESP_IPC_USES_CALLERS_PRIORITY` is enabled, the target core's IPC task will be lowered to the current priority of the target core before executing the callback.
- If :ref:`CONFIG_ESP_IPC_USES_CALLERS_PRIORITY` is disabled, the target core will always execute the callback at the highest possible priority.
- Depending on the complexity of the callback, users may need to configure the stack size of the IPC task via :ref:`CONFIG_ESP_IPC_TASK_STACK_SIZE`.
- The IPC feature is internally protected by a mutex. Therefore, simultaneous IPC calls from two or more calling CPUs are handled on a first come first serve basis.
- The IPC feature is internally protected by a mutex. Therefore, simultaneous IPC calls from two or more calling core's are serialized on a first come first serve basis.
API Usage
^^^^^^^^^
Task Context IPC callbacks have the following restrictions:
- The callback must be of type ``void func(void *arg)``
- The callback should avoid attempting to block or yield as this will result in the target CPU's IPC task blocking or yielding.
- The callback must avoid changing any aspect of the IPC task (e.g., by calling ``vTaskPrioritySet(NULL, x)``).
- The callback must be of the :cpp:type:`esp_ipc_func_t` type.
- The callback **must never block or yield** as this will result in the target core's IPC task blocking or yielding.
- The callback must avoid changing any aspect of the IPC task's state, e.g., by calling ``vTaskPrioritySet(NULL, x)``.
The IPC feature offers the API listed below to execute a callback in a task context on a target CPU. The API allows the calling CPU to block until the callback's execution has completed, or return immediately once the callback's execution has started.
The IPC feature offers the API listed below to execute a callback in a task context on a target core. The API allows the calling core to block until the callback's execution has completed, or return immediately once the callback's execution has started.
- :cpp:func:`esp_ipc_call` triggers an IPC call on the target CPU. This function will block until the target CPU's IPC task **begins** execution of the callback.
- :cpp:func:`esp_ipc_call_blocking` triggers an IPC on the target CPU. This function will block until the target CPU's IPC task **completes** execution of the callback.
- :cpp:func:`esp_ipc_call` triggers an IPC call on the target core. This function will block until the target core's IPC task **begins** execution of the callback.
- :cpp:func:`esp_ipc_call_blocking` triggers an IPC on the target core. This function will block until the target core's IPC task **completes** execution of the callback.
IPC in Interrupt Context
------------------------
In some cases, we need to quickly obtain the state of another CPU such as in a core dump, GDB stub, various unit tests, and DPORT workaround. The IPC ISR feature implements the High Priority Interrupt context by reserving a High Priority Interrupt on each CPU for IPC usage. When a calling CPU needs to execute a callback on the target CPU, the callback will execute in the context of the High Priority Interrupt of the target CPU.
In some cases, we need to quickly obtain the state of another core such as in a core dump, GDB stub, various unit tests, and hardware errata workarounds. The IPC ISR feature implements callback execution from a High Priority Interrupt context by reserving a High Priority Interrupt on each core for IPC usage. When a calling core needs to execute a callback on the target core, the callback will execute in the context of the High Priority Interrupt of the target core.
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
@ -61,10 +67,10 @@ When using IPCs in High Priority Interrupt context, users need to consider the f
When the callback executes, users need to consider the following:
.. list::
- The calling CPU will disable interrupts of level 3 and lower.
:CONFIG_IDF_TARGET_ARCH_XTENSA: - Although the priority of the reserved interrupt depends on :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`, during the execution IPC ISR callback, the target CPU will disable interrupts of level 5 and lower regardless of what :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` is set to.
:CONFIG_IDF_TARGET_ARCH_RISCV: - Although the priority of the reserved interrupt depends on :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`, during the execution IPC ISR callback, the target CPU will disable all interrupts.
- The calling core will disable interrupts of priority level 3 and lower.
:CONFIG_IDF_TARGET_ARCH_XTENSA: - Although the priority of the reserved interrupt depends on :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`, during the execution of IPC ISR callback, the target core will disable interrupts of priority level 5 and lower regardless of what :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` is set to.
:CONFIG_IDF_TARGET_ARCH_RISCV: - Although the priority of the reserved interrupt depends on :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`, during the execution of IPC ISR callback, the target core will disable all interrupts.
API Usage
^^^^^^^^^
@ -73,32 +79,32 @@ API Usage
High Priority Interrupt IPC callbacks have the following restrictions:
- The callback must be of type ``void func(void *arg)`` but implemented entirely in assembly
- The callback must be of type :cpp:type:`esp_ipc_isr_func_t` but implemented entirely in assembly.
- The callback is invoked via the ``CALLX0`` instruction with register windowing disabled, thus the callback:
- Must not call any register window related instructions (e.g., ``entry`` and ``retw``).
- Must not call other C functions as register windowing is disabled
- The callback should be placed in IRAM at a 4-byte aligned address
- (On invocation of/after returning from) the callback, the registers ``a2, a3, a4`` are (saved/restored) automatically thus can be used in the callback. The callback should **ONLY** use those registers.
- ``a2`` contains the ``void *arg`` of the callback
- ``a3/a4`` are free to use as scratch registers
- must not call any register window related instructions, e.g., ``entry`` and ``retw``.
- must not call other C functions as register windowing is disabled.
- The callback should be placed in IRAM at a 4-byte aligned address.
- On invocation of, or after returning from the callback, the registers ``a2, a3, a4`` are saved/restored automatically, thus can be used in the callback. The callback should **ONLY** use those registers.
- ``a2`` contains the ``void *arg`` of the callback.
- ``a3/a4`` are free to use as scratch registers.
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
High Priority Interrupt IPC callbacks have the same restrictions as for regular interrupt handlers. The callback function can be written in C.
High Priority Interrupt IPC callbacks must be of type :cpp:type:`esp_ipc_isr_func_t` and have the same restrictions as for regular interrupt handlers. The callback function can be written in C.
The IPC feature offers the API listed below to execute a callback in a High Priority Interrupt context.
The IPC feature offers the API listed below to execute a callback in a High Priority Interrupt context:
- :cpp:func:`esp_ipc_isr_call` triggers an IPC call on the target CPU. This function will busy-wait until the target CPU begins execution of the callback.
- :cpp:func:`esp_ipc_isr_call_blocking` triggers an IPC call on the target CPU. This function will busy-wait until the target CPU completes execution of the callback.
- :cpp:func:`esp_ipc_isr_call` triggers an IPC call on the target core. This function will busy-wait until the target core **begins** execution of the callback.
- :cpp:func:`esp_ipc_isr_call_blocking` triggers an IPC call on the target core. This function will busy-wait until the target core **completes** execution of the callback.
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
The following code-blocks demonstrates a High Priority Interrupt IPC callback written in assembly that simply reads the target CPU's cycle count.
The following code-blocks demonstrates a High Priority Interrupt IPC callback written in assembly that simply reads the target core's cycle count:
.. code-block:: asm
/* esp_test_ipc_isr_get_cycle_count_other_cpu(void *arg) */
// this function reads CCOUNT of the target CPU and stores it in arg.
// this function reads CCOUNT of the target core and stores it in arg.
// use only a2, a3 and a4 regs here.
.section .iram1, "ax"
.align 4
@ -122,7 +128,7 @@ The IPC feature offers the API listed below to execute a callback in a High Prio
.. note::
For more examples of High Priority Interrupt IPC callbacks, see :idf_file:`components/esp_system/port/arch/xtensa/esp_ipc_isr_routines.S` and :idf_file:`components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/xtensa/test_ipc_isr.S`.
For more examples of High Priority Interrupt IPC callbacks, you can refer to :idf_file:`components/esp_system/port/arch/xtensa/esp_ipc_isr_routines.S` and :idf_file:`components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/xtensa/test_ipc_isr.S`.
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
@ -132,13 +138,13 @@ The IPC feature offers the API listed below to execute a callback in a High Prio
See :idf_file:`examples/system/ipc/ipc_isr/xtensa/main/main.c` for an example of its use.
The High Priority Interrupt IPC API also provides the following convenience functions that can stall/resume the target CPU. These API utilize the High Priority Interrupt IPC, but supply their own internal callbacks:
The High Priority Interrupt IPC API also provides the following convenience functions that can stall/resume the target core. These APIs utilize the High Priority Interrupt IPC, but supply their own internal callbacks:
.. list::
:CONFIG_IDF_TARGET_ARCH_RISCV: - :cpp:func:`esp_ipc_isr_stall_other_cpu` stalls the target CPU. The calling CPU disables interrupts of level 3 and lower while the target CPU will busy-wait with all interrupts disabled. The target CPU will busy-wait until :cpp:func:`esp_ipc_isr_release_other_cpu` is called.
:CONFIG_IDF_TARGET_ARCH_XTENSA: - :cpp:func:`esp_ipc_isr_stall_other_cpu` stalls the target CPU. The calling CPU disables interrupts of level 3 and lower while the target CPU will busy-wait with interrupts of level 5 and lower disabled. The target CPU will busy-wait until :cpp:func:`esp_ipc_isr_release_other_cpu` is called.
- :cpp:func:`esp_ipc_isr_release_other_cpu` resumes the target CPU.
:CONFIG_IDF_TARGET_ARCH_RISCV: - :cpp:func:`esp_ipc_isr_stall_other_cpu` stalls the target core. The calling core disables interrupts of level 3 and lower, while the target core will busy-wait with all interrupts disabled. The target core will busy-wait until :cpp:func:`esp_ipc_isr_release_other_cpu` is called.
:CONFIG_IDF_TARGET_ARCH_XTENSA: - :cpp:func:`esp_ipc_isr_stall_other_cpu` stalls the target core. The calling core disables interrupts of level 3 and lower while the target core will busy-wait with interrupts of level 5 and lower disabled. The target core will busy-wait until :cpp:func:`esp_ipc_isr_release_other_cpu` is called.
- :cpp:func:`esp_ipc_isr_release_other_cpu` resumes the target core.
API Reference
-------------

View File

@ -1 +1,154 @@
.. include:: ../../../en/api-reference/system/ipc.rst
处理器间调用 (IPC)
====================
:link_to_translation:`en:[English]`
.. note::
IPC 指 **处理器间调用** (Inter-Processor Call),而不是其他操作系统中所指的 **进程间通信** (Inter-Process Communication)。
概述
--------
由于 {IDF_TARGET_NAME} 的双核特性,在某些情况下,某个回调必须在特定的内核上下文中运行。例如:
- 为特定内核的中断源分配 ISR或释放特定内核的中断源时
- 在特定芯片(如 ESP32上访问某个内核独有的内存如 RTC Fast Memory 时
- 读取另一个内核的寄存器或状态时
IPC 功能允许一个特定的内核(下文称“调用内核”)触发另一个内核(下文称“目标内核”)的回调函数执行,并允许目标内核在任务上下文或中断上下文中执行回调函数。在不同的上下文中,回调函数的实现限制有所不同。
任务上下文中的 IPC
-------------------
在应用程序启动时IPC 功能为每个内核创建一个 IPC 任务,从而在任务上下文中执行回调。当调用内核需要在目标内核中执行回调时,回调将在目标内核的 IPC 任务的上下文中执行。
在任务上下文中使用 IPC 功能时,需考虑以下几点:
- IPC 回调应该尽可能简短。 **IPC 回调决不能阻塞或让出**
- IPC 任务是以尽可能高的优先级创建的(即 ``configMAX_PRIORITIES - 1``)。
- 如果启用了 :ref:`CONFIG_ESP_IPC_USES_CALLERS_PRIORITY`,执行回调前会降低目标内核的 IPC 任务优先级,使其等于调用内核的优先级。
- 如果禁用了 :ref:`CONFIG_ESP_IPC_USES_CALLERS_PRIORITY`,目标内核将始终以尽可能高的优先级执行回调。
- 如果回调较为复杂,用户可能需要通过 :ref:`CONFIG_ESP_IPC_TASK_STACK_SIZE` 来配置 IPC 任务的堆栈大小。
- IPC 功能受内部互斥锁保护。因此,如果同时收到来自两个或多个调用内核的 IPC 请求,将按照“先到先得”的原则按顺序处理。
API 用法
^^^^^^^^^
任务上下文中的 IPC 回调具有以下限制:
- 回调类型必须是 :cpp:type:`esp_ipc_func_t`
- 回调 **决不能阻塞或让出**,以免导致目标内核的 IPC 任务阻塞或让出。
- 回调必须避免改变 IPC 任务的任何状态,例如,不能调用 ``vTaskPrioritySet(NULL, x)``
IPC 功能提供了以下 API用于在目标内核的任务上下文中执行回调。这两个 API 允许调用内核在回调执行完成前处于阻塞,或者在回调开始执行后立即返回。
- :cpp:func:`esp_ipc_call` 会在目标内核上触发一个 IPC 调用。在目标内核的 IPC 任务 **开始** 执行回调前,此函数会一直处于阻塞状态。
- :cpp:func:`esp_ipc_call_blocking` 会在目标内核上触发一个 IPC。在目标内核的 IPC 任务 **完成** 回调执行前,此函数会一直处于阻塞状态。
中断上下文中的 IPC
------------------------
在某些情况下我们需要快速获取另一个内核的状态如在核心转储、GDB Stub、各种单元测试和绕过硬件错误的过程中。IPC ISR 功能会在每个内核上保留一个高优先级中断供 IPC 使用,从而在高优先级中断上下文中执行回调。当调用内核需要在目标内核上执行回调时,该回调将在目标内核的高优先级中断的上下文中执行。
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
在这种情况下IPC ISR 功能支持在 :doc:`高优先级中断 </api-guides/hlinterrupts>` 上下文中执行回调。
在高优先级中断上下文中使用 IPC 时,需要考虑以下几点:
.. list::
:CONFIG_IDF_TARGET_ARCH_XTENSA: - 由于回调是在高优先级中断上下文中执行的,因此,回调必须完全用汇编语言编写。如需了解更多关于用汇编语言编写回调的内容,请参阅下文的 API 使用介绍。
- 保留的高优先级中断的优先级取决于 :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` 选项。
当回调执行时,需考虑以下几点:
.. list::
- 调用内核会禁用 3 级及以下优先级的中断。
:CONFIG_IDF_TARGET_ARCH_XTENSA: - 虽然保留中断的优先级取决于 :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`,但是在执行 IPC ISR 回调期间,无论 :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` 如何设置,目标内核都会禁用 5 级及以下优先级的中断。
:CONFIG_IDF_TARGET_ARCH_RISCV: - 虽然保留中断的优先级取决于 :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`,但是在执行 IPC ISR 回调期间,目标内核会禁用所有的中断。
API 用法
^^^^^^^^^
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
高优先级中断的 IPC 回调具有以下限制:
- 回调必须是 :cpp:type:`esp_ipc_isr_func_t` 类型,但必须完全用汇编语言实现。
- 回调通过 ``CALLX0`` 指令调用,同时禁用寄存器窗口,因此,该回调:
- 不得调用任何与寄存器窗口相关的指令,例如 ``entry````retw``
- 由于禁用了寄存器窗口,不得调用其他 C 函数。
- 回调应放在 4 字节对齐的 IRAM 地址上。
- 在调用或返回回调后,寄存器 ``a2````a3``,和 ``a4`` 会被自动保存或恢复,从而在回调中使用。回调 **只能使用这些寄存器**
- ``a2`` 包含回调的 ``void *arg``
- ``a3/a4`` 可以作为临时寄存器使用。
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
高优先级中断 IPC 回调函数的类型必须是 :cpp:type:`esp_ipc_isr_func_t`,其限制条件与常规中断处理程序相同。回调函数可以用 C 语言编写。
IPC 功能提供了下列 API以在高优先级中断的上下文中执行回调
- :cpp:func:`esp_ipc_isr_call` 能够在目标内核上触发一个 IPC 调用。在目标内核 **开始** 执行回调前,此函数将一直处于忙等待。
- :cpp:func:`esp_ipc_isr_call_blocking` 能够在目标内核上触发一个 IPC 调用。在目标内核 **完成** 回调执行前,此函数将一直处于忙等待。
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
以下示例代码用汇编语言编写了一个高优先级中断 IPC 回调,该回调的作用为读取目标内核的周期计数:
.. code-block:: asm
/* esp_test_ipc_isr_get_cycle_count_other_cpu(void *arg) */
// 此函数读取目标内核的 CCOUNT并将其存储到 arg 中。
// 此处仅使用 a2、a3 和 a4 寄存器。
.section .iram1, "ax"
.align 4
.global esp_test_ipc_isr_get_cycle_count_other_cpu
.type esp_test_ipc_isr_get_cycle_count_other_cpu, @function
// Args:
// a2 - void* arg
esp_test_ipc_isr_get_cycle_count_other_cpu:
rsr.ccount a3
s32i a3, a2, 0
ret
.. code-block:: c
unit32_t cycle_count;
esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)cycle_count);
.. note::
对于大多数简单用例,可用的临时寄存器数量是足够的。如果需要在回调函数中使用更多的临时寄存器,可以用 ``void *arg`` 指向一个用作寄存器保存区域的 buffer使回调函数保存或恢复更多的寄存器。前往 :example:`system/ipc/ipc_isr` 查看示例。
.. note::
如需查看更多高优先级中断 IPC 回调的示例,请前往 :idf_file:`components/esp_system/port/arch/xtensa/esp_ipc_isr_routines.S` 和 :idf_file:`components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/xtensa/test_ipc_isr.S`
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
请前往 :idf_file:`examples/system/ipc/ipc_isr/riscv/main/main.c` 查看使用示例。
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
请前往 :idf_file:`examples/system/ipc/ipc_isr/xtensa/main/main.c` 查看使用示例。
高优先级中断 IPC API 还提供了以下便利函数,这些函数可以暂停或恢复目标内核的执行。这些 API 利用高优先级中断 IPC但同时提供了自己的内部回调函数
.. list::
:CONFIG_IDF_TARGET_ARCH_RISCV: - :cpp:func:`esp_ipc_isr_stall_other_cpu`:暂停目标内核。调用内核禁用 3 级及以下级别的中断,而目标内核将在所有中断被禁用的情况下进入忙等待。在调用 :cpp:func:`esp_ipc_isr_release_other_cpu` 前,目标内核会保持忙等待。
:CONFIG_IDF_TARGET_ARCH_XTENSA: - :cpp:func:`esp_ipc_isr_stall_other_cpu`:暂停目标内核。调用内核禁用 3 级及以下级别的中断,而目标内核将在 5 级及以下的中断被禁用的情况下进入忙等待。在调用 :cpp:func:`esp_ipc_isr_release_other_cpu` 前,目标内核会保持忙等待。
- :cpp:func:`esp_ipc_isr_release_other_cpu`:恢复目标内核。
API 参考
-------------
.. include-build-file:: inc/esp_ipc.inc
.. include-build-file:: inc/esp_ipc_isr.inc