Merge branch 'feature/adds_ipc_isr_safe_api_v6.1' into 'release/v6.1'

feat(ipc_isr): Adds IPC ISR safe API to stall other CPU (v6.1)

See merge request espressif/esp-idf!50963
This commit is contained in:
Marius Vikhammer
2026-08-27 16:27:54 +08:00
10 changed files with 499 additions and 64 deletions

View File

@@ -97,6 +97,11 @@ The IPC feature offers the API listed below to execute a callback in a High Prio
- :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.
These functions interrupt the other CPU and execute the callback in the context of a High Priority Interrupt. There are two common usage patterns:
- For simple callbacks that do not enter critical sections shared with the other CPU, call :cpp:func:`esp_ipc_isr_call` or :cpp:func:`esp_ipc_isr_call_blocking` directly.
- If the calling CPU may enter critical sections used by the other CPU, or if several callbacks must run while the other CPU remains stopped, first stall the other CPU using :cpp:func:`esp_ipc_isr_stall_other_cpu` or :cpp:func:`esp_ipc_isr_stall_other_cpu_safe`. Then use :cpp:func:`esp_ipc_isr_call` or :cpp:func:`esp_ipc_isr_call_blocking` to execute callbacks. After the operation is complete, release the other CPU with :cpp:func:`esp_ipc_isr_release_other_cpu`.
.. 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 core's cycle count:
@@ -117,10 +122,23 @@ The IPC feature offers the API listed below to execute a callback in a High Prio
s32i a3, a2, 0
ret
The callback can be called directly when no shared critical section can deadlock:
.. code-block:: c
unit32_t cycle_count;
esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)cycle_count);
uint32_t cycle_count;
esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)&cycle_count);
Alternatively, safely stall the other CPU before making one or more IPC calls:
.. code-block:: c
while (esp_ipc_isr_stall_other_cpu_safe() != ESP_OK) {
// Optionally, add a timeout or yield to avoid infinite loop
}
uint32_t cycle_count;
esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)&cycle_count);
esp_ipc_isr_release_other_cpu();
.. note::
@@ -144,6 +162,7 @@ The High Priority Interrupt IPC API also provides the following convenience func
: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_stall_other_cpu_safe` attempts to stall the other core only if it is not in a critical section or ISR context. If the other core is in such a state, the function considers it unsafe to stall, releases the core, and returns an error.
- :cpp:func:`esp_ipc_isr_release_other_cpu` resumes the target core.
Application Examples

View File

@@ -97,6 +97,11 @@ IPC 功能提供了下列 API以在高优先级中断的上下文中执行回
- :cpp:func:`esp_ipc_isr_call` 能够在目标内核上触发一个 IPC 调用。在目标内核 **开始** 执行回调前,此函数将一直处于忙等待。
- :cpp:func:`esp_ipc_isr_call_blocking` 能够在目标内核上触发一个 IPC 调用。在目标内核 **完成** 回调执行前,此函数将一直处于忙等待。
这些函数会中断另一 CPU并在高优先级中断的上下文中执行回调。常见用法有两种
- 对于不会进入与另一 CPU 共享的临界区的简单回调,可以直接调用 :cpp:func:`esp_ipc_isr_call`:cpp:func:`esp_ipc_isr_call_blocking`
- 如果调用 CPU 可能进入另一 CPU 使用的临界区,或者需要在另一 CPU 保持停止时执行多个回调,则应先使用 :cpp:func:`esp_ipc_isr_stall_other_cpu`:cpp:func:`esp_ipc_isr_stall_other_cpu_safe` 暂停另一 CPU。然后使用 :cpp:func:`esp_ipc_isr_call`:cpp:func:`esp_ipc_isr_call_blocking` 执行回调。操作完成后,使用 :cpp:func:`esp_ipc_isr_release_other_cpu` 释放另一 CPU。
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
以下示例代码用汇编语言编写了一个高优先级中断 IPC 回调,该回调的作用为读取目标内核的周期计数:
@@ -117,10 +122,23 @@ IPC 功能提供了下列 API以在高优先级中断的上下文中执行回
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);
uint32_t cycle_count;
esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)&cycle_count);
或者,也可以在进行一次或多次 IPC 调用之前,安全地暂停另一 CPU
.. code-block:: c
while (esp_ipc_isr_stall_other_cpu_safe() != ESP_OK) {
// 在生产代码中,可按需添加超时或 yield以避免无限循环。
}
uint32_t cycle_count;
esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)&cycle_count);
esp_ipc_isr_release_other_cpu();
.. note::
@@ -144,6 +162,7 @@ IPC 功能提供了下列 API以在高优先级中断的上下文中执行回
: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_stall_other_cpu_safe`:仅当另一内核不在临界区或 ISR 上下文中时,才尝试暂停该内核。如果另一内核处于此类状态,则认为暂停不安全,会释放该内核并返回错误。
- :cpp:func:`esp_ipc_isr_release_other_cpu`:恢复目标内核。
应用示例