|
|
@@ -14,11 +14,7 @@ Due to the dual core nature of the {IDF_TARGET_NAME}, there are instances where
|
|
|
- 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.
|
|
|
|
|
|
-
|
|
|
-.. only:: not esp32p4
|
|
|
-
|
|
|
- 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 a High Priority Interrupt context (see :doc:`/api-guides/hlinterrupts` for more details). 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 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.
|
|
|
|
|
|
IPC in Task Context
|
|
|
-------------------
|
|
|
@@ -46,76 +42,103 @@ The IPC feature offers the API listed below to execute a callback in a task cont
|
|
|
- :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.
|
|
|
|
|
|
-.. only:: not esp32p4
|
|
|
+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.
|
|
|
+
|
|
|
+.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
|
|
|
|
|
|
- IPC in ISR Context
|
|
|
- ------------------
|
|
|
+ For such scenarios, the IPC ISR feature supports execution of callbacks in a :doc:`High Priority Interrupt </api-guides/hlinterrupts>` 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. For such scenarios, the IPC feature supports execution of callbacks in a :doc:`High Priority Interrupt </api-guides/hlinterrupts>` context. The IPC 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.
|
|
|
+When using IPCs in High Priority Interrupt context, users need to consider the following:
|
|
|
|
|
|
- When using IPCs in High Priority Interrupt context, users need to consider the following:
|
|
|
+.. list::
|
|
|
|
|
|
- - Since the callback is executed in a High Priority Interrupt context, the callback must be written entirely in assembly. See the API Usage below for more details regarding writing assembly callbacks.
|
|
|
- - The priority of the reserved High Priority Interrupt is dependent on the :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` option
|
|
|
- - When the callback executes:
|
|
|
+ :CONFIG_IDF_TARGET_ARCH_XTENSA: - Since the callback is executed in a High Priority Interrupt context, the callback must be written entirely in assembly. See the API Usage below for more details regarding writing assembly callbacks.
|
|
|
+ - The priority of the reserved High Priority Interrupt is dependent on the :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` option.
|
|
|
|
|
|
- - The calling CPU will disable interrupts of level 3 and lower
|
|
|
- - Although the priority of the reserved interrupt depends on :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`, during the execution IPC ISR callback, the target CPU will disable interrupts of level 5 and lower regardless of what :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` is set to.
|
|
|
+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.
|
|
|
|
|
|
API Usage
|
|
|
^^^^^^^^^
|
|
|
|
|
|
-High Priority Interrupt IPC callbacks have the following restrictions:
|
|
|
+.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
|
|
|
+
|
|
|
+ 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 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
|
|
|
+
|
|
|
+.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
|
|
|
|
|
-- The callback must be of type ``void func(void *arg)`` 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
|
|
|
+ High Priority Interrupt IPC callbacks 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.
|
|
|
|
|
|
-- :cpp:func:`esp_ipc_isr_asm_call` triggers an IPC call on the target CPU. This function will busy-wait until the target CPU begins execution of the callback.
|
|
|
-- :cpp:func:`esp_ipc_isr_asm_call_blocking` triggers an IPC call on the target CPU. This function will busy-wait until the target CPU completes execution of the callback.
|
|
|
+- :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.
|
|
|
|
|
|
-The following code-blocks demonstrates a High Priority Interrupt IPC callback written in assembly that simply reads the target CPU's cycle count.
|
|
|
+.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
|
|
|
|
|
|
-.. code-block:: asm
|
|
|
+ The following code-blocks demonstrates a High Priority Interrupt IPC callback written in assembly that simply reads the target CPU's cycle count.
|
|
|
|
|
|
- /* esp_test_ipc_isr_get_cycle_count_other_cpu(void *arg) */
|
|
|
- // this function reads CCOUNT of the target CPU and stores it in arg.
|
|
|
- // use only a2, a3 and a4 regs here.
|
|
|
- .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:: asm
|
|
|
|
|
|
-.. code-block:: c
|
|
|
+ /* esp_test_ipc_isr_get_cycle_count_other_cpu(void *arg) */
|
|
|
+ // this function reads CCOUNT of the target CPU and stores it in arg.
|
|
|
+ // use only a2, a3 and a4 regs here.
|
|
|
+ .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
|
|
|
|
|
|
- unit32_t cycle_count;
|
|
|
- esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)cycle_count);
|
|
|
+ .. code-block:: c
|
|
|
|
|
|
-.. note::
|
|
|
+ unit32_t cycle_count;
|
|
|
+ esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)cycle_count);
|
|
|
|
|
|
- The number of scratch registers available for use is sufficient for most simple use cases. But if your callback requires more scratch registers, ``void *arg`` can point to a buffer that is used as a register save area. The callback can then save and restore more registers. See the :example:`system/ipc/ipc_isr`.
|
|
|
+ .. note::
|
|
|
|
|
|
-.. note::
|
|
|
+ The number of scratch registers available for use is sufficient for most simple use cases. But if your callback requires more scratch registers, ``void *arg`` can point to a buffer that is used as a register save area. The callback can then save and restore more registers. See the :example:`system/ipc/ipc_isr`.
|
|
|
+
|
|
|
+ .. note::
|
|
|
+
|
|
|
+ For more examples of High Priority Interrupt IPC callbacks, see :idf_file:`components/esp_system/port/arch/xtensa/esp_ipc_isr_routines.S` and :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, see :idf_file:`components/esp_system/port/arch/xtensa/esp_ipc_isr_routines.S` and :`components/esp_system/test/test_ipc_isr.S`
|
|
|
+.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
|
|
+
|
|
|
+ See :idf_file:`examples/system/ipc/ipc_isr/riscv/main/main.c` for an example of its use.
|
|
|
+
|
|
|
+.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
|
|
|
+
|
|
|
+ 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:
|
|
|
|
|
|
-- :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.
|
|
|
+.. 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.
|
|
|
|
|
|
API Reference
|
|
|
-------------
|