feat(esp_system): Support IPC_ISR for ESP32P4

This commit is contained in:
KonstantinKondrashov 2023-09-06 19:33:39 +08:00
parent addfc0d870
commit 7a878bdc50
37 changed files with 591 additions and 133 deletions

View File

@ -530,19 +530,19 @@ menu "ESP System Settings"
prompt "Interrupt level to use for Interrupt Watchdog and other system checks"
default ESP_SYSTEM_CHECK_INT_LEVEL_4
help
Interrupt level to use for Interrupt Watchdog and other system checks.
Interrupt level to use for Interrupt Watchdog, IPC_ISR and other system checks.
config ESP_SYSTEM_CHECK_INT_LEVEL_5
bool "Level 5 interrupt"
depends on IDF_TARGET_ESP32
help
Using level 5 interrupt for Interrupt Watchdog and other system checks.
Using level 5 interrupt for Interrupt Watchdog, IPC_ISR and other system checks.
config ESP_SYSTEM_CHECK_INT_LEVEL_4
bool "Level 4 interrupt"
depends on !BTDM_CTRL_HLI
help
Using level 4 interrupt for Interrupt Watchdog and other system checks.
Using level 4 interrupt for Interrupt Watchdog, IPC_ISR and other system checks.
endchoice
# Insert chip-specific system config
@ -595,11 +595,10 @@ menu "IPC (Inter-Processor Call)"
config ESP_IPC_ISR_ENABLE
bool
default n if IDF_TARGET_ESP32P4 # TODO: IDF-7769
default y if !FREERTOS_UNICORE
help
The IPC ISR feature is similar to the IPC feature except that the callback function is executed in the
context of a High Priority Interrupt. The IPC ISR feature is itended for low latency execution of simple
context of a High Priority Interrupt. The IPC ISR feature is intended for low latency execution of simple
callbacks written in assembly on another CPU. Due to being run in a High Priority Interrupt, the assembly
callbacks must be written with particular restrictions (see "IPC" and "High-Level Interrupt" docs for more
details).

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -17,31 +17,44 @@ extern "C" {
/**
* @brief IPC ISR Callback
*
* A callback of this type should be provided as an argument when calling esp_ipc_isr_asm_call() or
* esp_ipc_isr_asm_call_blocking().
* The callback must be written:
* - in assembly for XTENSA chips (such as ESP32, ESP32S3).
* - in C or assembly for RISCV chips (such as ESP32P4).
*
* A callback of this type should be provided as an argument when calling esp_ipc_isr_call() or
* esp_ipc_isr_call_blocking().
*/
typedef void (*esp_ipc_isr_func_t)(void* arg);
/**
* @brief Execute an assembly callback on the other CPU
* @brief Execute an ISR callback on the other CPU
*
* Execute a given callback on the other CPU in the context of a High Priority Interrupt.
*
* - This function will busy-wait in a critical section until the other CPU has started execution of the callback
* - The callback must be written in assembly, is invoked using a CALLX0 instruction, and has a2, a3, a4 as scratch
* registers. See docs for more details
* - The callback must be written:
* - in assembly for XTENSA chips (such as ESP32, ESP32S3).
* The function is invoked using a CALLX0 instruction and can use only a2, a3, a4 registers.
* See :doc:`IPC in Interrupt Context </api-reference/system/ipc>` doc for more details.
* - in C or assembly for RISCV chips (such as ESP32P4).
*
* @note This function is not available in single-core mode.
*
* @param[in] func Pointer to a function of type void func(void* arg) to be executed
* @param[in] arg Arbitrary argument of type void* to be passed into the function
*/
void esp_ipc_isr_asm_call(esp_ipc_isr_func_t func, void* arg);
void esp_ipc_isr_call(esp_ipc_isr_func_t func, void* arg) ;
/**
* @brief Execute an assembly callback on the other CPU and busy-wait until it completes
* @brief Execute an ISR callback on the other CPU
* See esp_ipc_isr_call().
*/
#define esp_ipc_isr_asm_call(func, arg) esp_ipc_isr_call(func, arg)
/**
* @brief Execute an ISR callback on the other CPU and busy-wait until it completes
*
* This function is identical to esp_ipc_isr_asm_call() except that this function will busy-wait until the execution of
* This function is identical to esp_ipc_isr_call() except that this function will busy-wait until the execution of
* the callback completes.
*
* @note This function is not available in single-core mode.
@ -49,7 +62,13 @@ void esp_ipc_isr_asm_call(esp_ipc_isr_func_t func, void* arg);
* @param[in] func Pointer to a function of type void func(void* arg) to be executed
* @param[in] arg Arbitrary argument of type void* to be passed into the function
*/
void esp_ipc_isr_asm_call_blocking(esp_ipc_isr_func_t func, void* arg);
void esp_ipc_isr_call_blocking(esp_ipc_isr_func_t func, void* arg);
/**
* @brief Execute an ISR callback on the other CPU and busy-wait until it completes
* See esp_ipc_isr_call_blocking().
*/
#define esp_ipc_isr_asm_call_blocking(func, arg) esp_ipc_isr_call_blocking(func, arg)
/**
* @brief Stall the other CPU

View File

@ -26,7 +26,7 @@ extern "C" {
* - This function will register a High Priority Interrupt for a CPU where it is called. The priority of the interrupts is dependent on
* the CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL option.
* - Callbacks written in assembly can then run in context of the registered High Priority Interrupts
* - Callbacks can be executed by calling esp_ipc_isr_asm_call() or esp_ipc_isr_asm_call_blocking()
* - Callbacks can be executed by calling esp_ipc_isr_call() or esp_ipc_isr_call_blocking()
*/
void esp_ipc_isr_init(void);

View File

@ -17,11 +17,16 @@ if(CONFIG_ESP_CONSOLE_USB_CDC)
endif()
if(CONFIG_ESP_IPC_ISR_ENABLE)
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
list(APPEND srcs "arch/xtensa/esp_ipc_isr.c"
"arch/xtensa/esp_ipc_isr_handler.S"
"arch/xtensa/esp_ipc_isr_routines.S")
endif()
list(APPEND srcs "esp_ipc_isr.c")
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
list(APPEND srcs "arch/xtensa/esp_ipc_isr_port.c"
"arch/xtensa/esp_ipc_isr_handler.S"
"arch/xtensa/esp_ipc_isr_routines.S")
elseif(CONFIG_IDF_TARGET_ARCH_RISCV)
list(APPEND srcs "arch/riscv/esp_ipc_isr_port.c"
"arch/riscv/esp_ipc_isr_handler.S"
"arch/riscv/esp_ipc_isr_routines.c")
endif()
endif()
if(CONFIG_IDF_TARGET_ARCH_XTENSA)

View File

@ -0,0 +1,78 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/hp_system_reg.h"
/* IPC_ISR handler */
.equ SAVE_REGS, 16 /* count of saving regs: a0 - a7, t0 - t6, ra */
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
.section .iram1,"ax"
.global esp_ipc_isr_handler
.type esp_ipc_isr_handler,@function
esp_ipc_isr_handler:
/* save a0 - a7, t0 - t6, ra */
addi sp, sp, -(CONTEXT_SIZE)
sw a0, 0(sp)
sw a1, 4(sp)
sw a2, 8(sp)
sw a3, 12(sp)
sw a4, 16(sp)
sw a5, 20(sp)
sw a6, 24(sp)
sw a7, 28(sp)
sw t0, 32(sp)
sw t1, 36(sp)
sw t2, 40(sp)
sw t3, 44(sp)
sw t4, 48(sp)
sw t5, 52(sp)
sw t6, 56(sp)
sw ra, 60(sp)
/* MIE is cleared, so nested interrupts are disabled */
/* Reset isr interrupt flags */
li a1, HP_SYSTEM_CPU_INT_FROM_CPU_2_REG
csrr a0, mhartid # Get CORE_ID
beqz a0, 1f
li a1, HP_SYSTEM_CPU_INT_FROM_CPU_3_REG
1:
sw zero, (a1)
/* Set the start flag */
la a0, esp_ipc_isr_start_fl
sw a0, 0(a0)
/* Call the esp_ipc_func(void* esp_ipc_func_arg) */
lw a1, (esp_ipc_func)
lw a0, (esp_ipc_func_arg)
jalr a1
/* Set the end flag */
la a0, esp_ipc_isr_end_fl
sw a0, 0(a0)
/* Restore a0 - a7, t0 - t6, ra */
lw a0, 0(sp)
lw a1, 4(sp)
lw a2, 8(sp)
lw a3, 12(sp)
lw a4, 16(sp)
lw a5, 20(sp)
lw a6, 24(sp)
lw a7, 28(sp)
lw t0, 32(sp)
lw t1, 36(sp)
lw t2, 40(sp)
lw t3, 44(sp)
lw t4, 48(sp)
lw t5, 52(sp)
lw t6, 56(sp)
lw ra, 60(sp)
addi sp, sp, (CONTEXT_SIZE)
mret

View File

@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc.h"
#include "soc/interrupts.h"
#include "soc/hp_system_reg.h"
#include "esp_intr_alloc.h"
#include "riscv/interrupt.h"
#include "esp_rom_sys.h"
#include "esp_cpu.h"
#include "esp_attr.h"
#include "sdkconfig.h"
void esp_ipc_isr_port_init(const int cpuid)
{
uint32_t intr_source = ETS_FROM_CPU_INTR2_SOURCE + cpuid; // ETS_FROM_CPU_INTR2_SOURCE and ETS_FROM_CPU_INTR3_SOURCE
esp_intr_disable_source(ETS_IPC_ISR_INUM);
esp_rom_route_intr_matrix(cpuid, intr_source, ETS_IPC_ISR_INUM);
esp_cpu_intr_set_type(ETS_IPC_ISR_INUM, INTR_TYPE_LEVEL);
#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
esp_cpu_intr_set_priority(ETS_IPC_ISR_INUM, 5);
#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
esp_cpu_intr_set_priority(ETS_IPC_ISR_INUM, 4);
#else
#error "CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL is not defined!"
#endif
esp_intr_enable_source(ETS_IPC_ISR_INUM);
}
IRAM_ATTR void esp_ipc_isr_port_int_trigger(const int cpuid)
{
if (cpuid == 0) {
// it runs an interrupt on cpu0
REG_WRITE(HP_SYSTEM_CPU_INT_FROM_CPU_2_REG, HP_SYSTEM_CPU_INT_FROM_CPU_2);
} else {
// it runs an interrupt on cpu1
REG_WRITE(HP_SYSTEM_CPU_INT_FROM_CPU_3_REG, HP_SYSTEM_CPU_INT_FROM_CPU_3);
}
}

View File

@ -0,0 +1,12 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "stdint.h"
void esp_ipc_isr_waiting_for_finish_cmd(void* ipc_isr_finish_cmd)
{
while (*(volatile uint32_t*)ipc_isr_finish_cmd == 0) { };
}

View File

@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc.h"
#include "soc/interrupts.h"
#include "soc/dport_reg.h"
#ifndef CONFIG_IDF_TARGET_ESP32
#include "soc/system_reg.h"
#endif
#include "esp_rom_sys.h"
#include "esp_intr_alloc.h"
#include "esp_attr.h"
#include "sdkconfig.h"
void esp_ipc_isr_port_init(const int cpuid)
{
uint32_t intr_source = ETS_FROM_CPU_INTR2_SOURCE + cpuid; // ETS_FROM_CPU_INTR2_SOURCE and ETS_FROM_CPU_INTR3_SOURCE
ESP_INTR_DISABLE(ETS_IPC_ISR_INUM);
esp_rom_route_intr_matrix(cpuid, intr_source, ETS_IPC_ISR_INUM);
ESP_INTR_ENABLE(ETS_IPC_ISR_INUM);
}
IRAM_ATTR void esp_ipc_isr_port_int_trigger(const int cpuid)
{
if (cpuid == 0) {
// it runs an interrupt on cpu0
DPORT_REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_2_REG, SYSTEM_CPU_INTR_FROM_CPU_2);
} else {
// it runs an interrupt on cpu1
DPORT_REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_3_REG, SYSTEM_CPU_INTR_FROM_CPU_3);
}
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -10,19 +10,12 @@
#include <assert.h>
#include "esp_err.h"
#include "esp_attr.h"
#include "soc/soc.h"
#include "soc/dport_reg.h"
#ifndef CONFIG_IDF_TARGET_ESP32
#include "soc/periph_defs.h"
#include "soc/system_reg.h"
#endif
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/portmacro.h"
#include "esp_intr_alloc.h"
#include "esp_private/esp_ipc_isr.h"
#include "esp_private/esp_ipc_isr_port.h"
#include "esp_ipc_isr.h"
#include "xtensa/core-macros.h"
#include "sdkconfig.h"
static portMUX_TYPE s_ipc_isr_mux = portMUX_INITIALIZER_UNLOCKED;
@ -61,10 +54,7 @@ static void esp_ipc_isr_call_and_wait(esp_ipc_isr_func_t func, void* arg, esp_ip
void esp_ipc_isr_init(void)
{
const uint32_t cpuid = xPortGetCoreID();
uint32_t intr_source = ETS_FROM_CPU_INTR2_SOURCE + cpuid; // ETS_FROM_CPU_INTR2_SOURCE and ETS_FROM_CPU_INTR3_SOURCE
ESP_INTR_DISABLE(ETS_IPC_ISR_INUM);
esp_rom_route_intr_matrix(cpuid, intr_source, ETS_IPC_ISR_INUM);
ESP_INTR_ENABLE(ETS_IPC_ISR_INUM);
esp_ipc_isr_port_init(cpuid);
if (cpuid != 0) {
s_stall_state = STALL_STATE_RUNNING;
@ -76,14 +66,14 @@ void esp_ipc_isr_init(void)
/* Public API functions */
void IRAM_ATTR esp_ipc_isr_asm_call(esp_ipc_isr_func_t func, void* arg)
void IRAM_ATTR esp_ipc_isr_call(esp_ipc_isr_func_t func, void* arg)
{
IPC_ISR_ENTER_CRITICAL();
esp_ipc_isr_call_and_wait(func, arg, IPC_ISR_WAIT_FOR_START);
IPC_ISR_EXIT_CRITICAL();
}
void IRAM_ATTR esp_ipc_isr_asm_call_blocking(esp_ipc_isr_func_t func, void* arg)
void IRAM_ATTR esp_ipc_isr_call_blocking(esp_ipc_isr_func_t func, void* arg)
{
IPC_ISR_ENTER_CRITICAL();
esp_ipc_isr_call_and_wait(func, arg, IPC_ISR_WAIT_FOR_END);
@ -201,14 +191,8 @@ static void IRAM_ATTR esp_ipc_isr_call_and_wait(esp_ipc_isr_func_t func, void* a
esp_ipc_isr_start_fl = 0;
esp_ipc_isr_end_fl = 0;
if (cpu_id == 0) {
// it runs an interrupt on cpu1
DPORT_REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_3_REG, SYSTEM_CPU_INTR_FROM_CPU_3);
} else {
// it runs an interrupt on cpu0
DPORT_REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_2_REG, SYSTEM_CPU_INTR_FROM_CPU_2);
}
// Trigger an interrupt on the opposite core.
esp_ipc_isr_port_int_trigger(!cpu_id);
// IPC_ISR handler will be called and `...isr_start` and `...isr_end` will be updated there
if (wait_for == IPC_ISR_WAIT_FOR_START) {

View File

@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_ESP_IPC_ISR_ENABLE
/**
* @brief Initialize the IPC ISR interrupt for a specific CPU.
*
* This function initializes the IPC ISR (Inter-Processor Communication Interrupt)
* for a specific CPU core. It configures the interrupt source and enables the
* IPC ISR interrupt for the specified CPU.
*
* @param[in] cpuid The ID of the CPU core to initialize IPC ISR for.
*/
void esp_ipc_isr_port_init(const int cpuid);
/**
* @brief Trigger an interrupt on a specific CPU core.
*
* @param[in] cpuid The ID of the CPU core to trigger the interrupt on (0 or 1).
*/
void esp_ipc_isr_port_int_trigger(const int cpuid);
#endif // CONFIG_ESP_IPC_ISR_ENABLE
#ifdef __cplusplus
}
#endif

View File

@ -16,7 +16,12 @@ set(SRC "test_app_main.c"
"test_task_wdt.c")
if(CONFIG_ESP_IPC_ISR_ENABLE)
list(APPEND SRC "test_ipc_isr.c" "test_ipc_isr.S")
list(APPEND SRC "test_ipc_isr.c")
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
list(APPEND SRC "port/arch/xtensa/test_ipc_isr.S")
elseif(CONFIG_IDF_TARGET_ARCH_RISCV)
list(APPEND SRC "port/arch/riscv/test_ipc_isr.c")
endif()
endif()
idf_component_register(SRCS ${SRC}

View File

@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdkconfig.h"
#if CONFIG_ESP_IPC_ISR_ENABLE
void esp_test_ipc_isr_callback(void *arg) {
uint32_t value = 0xa5a5;
*(volatile uint32_t*)arg = value;
}
void esp_test_ipc_isr_get_other_core_id(void *arg) {
uint32_t core_id;
__asm volatile("csrr %0, mhartid" : "=r"(core_id));
*(volatile uint32_t*)arg = core_id;
}
void esp_test_ipc_isr_get_cycle_count_other_cpu(void *arg) {
uint32_t cycle_count;
__asm volatile("rdcycle %0;" : "=r"(cycle_count));
*(volatile uint32_t*)arg = cycle_count;
}
#endif // CONFIG_ESP_IPC_ISR_ENABLE

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -13,18 +13,18 @@
#include <xtensa/config/system.h>
#include <xtensa/hal.h>
/* esp_test_ipc_isr_asm(void *arg)
/* esp_test_ipc_isr_callback(void *arg)
*
* It should be called by the CALLX0 command from the handler of High-priority interrupt.
* Only these registers [a2, a3, a4] can be used here.
*/
.section .iram1, "ax"
.align 4
.global esp_test_ipc_isr_asm
.type esp_test_ipc_isr_asm, @function
.global esp_test_ipc_isr_callback
.type esp_test_ipc_isr_callback, @function
// Args:
// a2 - void* arg
esp_test_ipc_isr_asm:
esp_test_ipc_isr_callback:
movi a3, 0xa5a5
s32i a3, a2, 0
ret

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -17,12 +17,18 @@
#ifdef CONFIG_ESP_IPC_ISR_ENABLE
void esp_test_ipc_isr_asm(void* arg);
#if CONFIG_IDF_TARGET_ARCH_RISCV
#define STORE_ERROR "Store access fault"
#else
#define STORE_ERROR "StoreProhibited"
#endif
void esp_test_ipc_isr_callback(void* arg);
TEST_CASE("Test ipc_isr blocking IPC function calls a ASM function", "[ipc]")
{
int val = 0x5a5a;
esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_asm, &val);
esp_ipc_isr_call_blocking(esp_test_ipc_isr_callback, &val);
TEST_ASSERT_EQUAL_HEX(val, 0xa5a5);
}
@ -32,13 +38,13 @@ void esp_test_ipc_isr_get_other_core_id(void* arg);
TEST_CASE("Test ipc_isr blocking IPC function calls get_other_core_id", "[ipc]")
{
int val = 0x5a5a;
esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_get_other_core_id, &val);
esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_other_core_id, &val);
TEST_ASSERT_EQUAL_HEX(val, 1);
}
static void do_esp_ipc_isr_asm_call_blocking(void)
static void do_esp_ipc_isr_call_blocking(void)
{
esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_asm, NULL);
esp_ipc_isr_call_blocking(esp_test_ipc_isr_callback, NULL);
}
static void check_reset_reason_panic(void)
@ -46,8 +52,8 @@ static void check_reset_reason_panic(void)
TEST_ASSERT_EQUAL(ESP_RST_PANIC, esp_reset_reason());
}
TEST_CASE_MULTIPLE_STAGES("Test ipc_isr exception in asm func leads to StoreProhibited not to Unhandled debug exception", "[ipc][reset=StoreProhibited,SW_CPU_RESET]",
do_esp_ipc_isr_asm_call_blocking,
TEST_CASE_MULTIPLE_STAGES("Test ipc_isr exception in asm func leads to StoreProhibited not to Unhandled debug exception", "[ipc][reset="STORE_ERROR",SW_CPU_RESET]",
do_esp_ipc_isr_call_blocking,
check_reset_reason_panic)
void esp_test_ipc_isr_get_cycle_count_other_cpu(void* arg);
@ -55,7 +61,7 @@ void esp_test_ipc_isr_get_cycle_count_other_cpu(void* arg);
TEST_CASE("Test ipc_isr blocking IPC function calls get_cycle_count_other_cpu", "[ipc]")
{
int val = 0x5a5a;
esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, &val);
esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, &val);
esp_rom_printf("CCOUNT CPU0 = %d\n", esp_cpu_get_cycle_count());
esp_rom_printf("CCOUNT CPU1 = %d\n", val);
}
@ -70,12 +76,12 @@ static void task_asm(void *arg)
printf("task_asm\n");
while (s_stop == false) {
val = 0x5a5a;
esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_asm, &val);
esp_ipc_isr_call_blocking(esp_test_ipc_isr_callback, &val);
TEST_ASSERT_EQUAL_HEX(val, 0xa5a5);
++counter;
}
printf("task_asm counter = %d\n", counter);
TEST_ASSERT_GREATER_THAN(10000, counter);
TEST_ASSERT_GREATER_THAN(1000, counter);
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}

View File

@ -14,6 +14,12 @@
#define MEMPROT_ISR _interrupt_handler
#endif // CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
#if CONFIG_ESP_IPC_ISR_ENABLE
#define IPC_ISR_HANDLER esp_ipc_isr_handler
#else
#define IPC_ISR_HANDLER _interrupt_handler
#endif // CONFIG_ESP_IPC_ISR_ENABLE
/* The system interrupts are not used for now, so trigger a panic every time one occurs. */
#define _system_int_handler _panic_handler
@ -104,7 +110,7 @@ _mtvt_table:
.word _panic_handler /* 41: ETS_CACHEERR_INUM (+16) panic-interrupt (soc-level panic) */
.word MEMPROT_ISR /* 42: ETS_MEMPROT_ERR_INUM (+16) handler (soc-level panic) */
.word _interrupt_handler /* 43: Free interrupt number */
.word _interrupt_handler /* 44: Free interrupt number */
.word IPC_ISR_HANDLER /* 44: ETS_IPC_ISR_INUM (+16) handler*/
.word _interrupt_handler /* 45: Free interrupt number */
.word _interrupt_handler /* 46: Free interrupt number */
.word _interrupt_handler /* 47: Free interrupt number */

View File

@ -5,7 +5,6 @@
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#ifdef __cplusplus
extern "C" {

View File

@ -234,6 +234,7 @@
#define ETS_T1_WDT_INUM 24
#define ETS_CACHEERR_INUM 25
#define ETS_MEMPROT_ERR_INUM 26
#define ETS_IPC_ISR_INUM 28
//CPU0 Max valid interrupt number
#define ETS_MAX_INUM 31

View File

@ -183,7 +183,6 @@ api-reference/system/bootloader_image_format.rst
api-reference/system/inc/power_management_esp32p4.rst
api-reference/system/heap_debug.rst
api-reference/system/mm.rst
api-reference/system/ipc.rst
api-reference/system/esp_https_ota.rst
api-reference/system/ulp-risc-v.rst
api-reference/system/esp_err.rst

View File

@ -24,7 +24,7 @@ System API
heap_debug
esp_timer
internal-unstable
:not CONFIG_FREERTOS_UNICORE or esp32p4: ipc
:not CONFIG_FREERTOS_UNICORE: ipc
intr_alloc
log
misc_system_api

View File

@ -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
------------------------
IPC in ISR 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 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.
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
When using IPCs in High Priority Interrupt context, users need to consider the following:
For such scenarios, the IPC ISR feature supports execution of callbacks in a :doc:`High Priority Interrupt </api-guides/hlinterrupts>` context.
- 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:
When using IPCs in High Priority Interrupt context, users need to consider the following:
- 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.
.. list::
: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.
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
- 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 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
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`.
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`
.. 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`.
.. 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
-------------

View File

@ -80,11 +80,21 @@ examples/system/himem:
temporary: true
reason: the other targets are not tested yet
examples/system/ipc/ipc_isr:
examples/system/ipc/ipc_isr/riscv:
enable:
- if: IDF_TARGET == "esp32" or IDF_TARGET == "esp32s3"
- if: IDF_TARGET_ARCH_RISCV == 1 and ESP_IPC_ISR_ENABLE == 1
temporary: true
reason: the other targets are not tested yet
reason: The test is intended only for multi-core chips
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
examples/system/ipc/ipc_isr/xtensa:
enable:
- if: IDF_TARGET_ARCH_XTENSA == 1 and ESP_IPC_ISR_ENABLE == 1
temporary: true
reason: The test is intended only for multi-core chips
examples/system/light_sleep:
disable:

View File

@ -0,0 +1,56 @@
| Supported Targets | ESP32P4 |
| ----------------- | ------- |
# IPC ISR Example
This example demonstrates how to use the IPC ISR feature (which allows an IPC to run in the context of a High Priority Interrupt). The level of the IPC ISR interrupt depends on the `CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` option. The IPC ISR feature can be useful in cases where users need to quickly get the state of the other CPU (consult the [IPC documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/ipc.html)). Unlike ESP32 or ESP32S3, for this chip, the callback function can be written in C.
The first callback `get_mstatus_other_cpu()` demonstrates a callback that simply returns the `MSTATUS` register of other core.
The second callback `extended_ipc_isr_func()` demonstrates how to return multiple values from the callback. The callback's `void *arg` points to a structure that contains the following:
- `uint32_t in[];` that gives the callback multiple input arguments
- `uint32_t out[];` that gives the callback multiple output arguments
The `extended_ipc_isr_func()` callback uses the `in[]` arguments does some work and then writes to `out[]`.
## How to use example
### Hardware Required
Example should be able to run on any commonly available ESP32P4 development board. The chip should have two cores.
### Configure the project
- `CONFIG_FREERTOS_UNICORE` - disabled,
- `CONFIG_ESP_IPC_ISR_ENABLE` - enabled.
```
idf.py menuconfig
```
### Build and Flash
```
idf.py build flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example output
```
I (411) example: Start
I (421) example: call get_mstatus_other_cpu
I (421) example: MSTATUS = 0x3880
I (421) example: call extended_ipc_isr_func
I (431) example: in[0] = 0x1
I (431) example: in[1] = 0x2
I (441) example: in[2] = 0x3
I (441) example: out[0] = (in[0] | in[1] | in[2]) = 0x3
I (451) example: out[1] = (in[0] + in[1] + in[2]) = 0x6
I (451) example: out[2] = MCAUSE of other cpu = 0xb800002c
I (461) example: out[3] = MSTATUS of other cpu = 0x3880
I (461) example: End
```

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "main.c"
"callbacks.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "callbacks.h"
void get_mstatus_other_cpu(void *arg) {
uint32_t mstatus_value;
asm volatile ("csrr %0, mstatus" : "=r" (mstatus_value));
*(volatile uint32_t*)arg = mstatus_value;
}
void extended_ipc_isr_func(void* arg) {
arg_data_t *a = (arg_data_t *)arg;
a->out[0] = a->in[0] | a->in[1] | a->in[2];
a->out[1] = a->in[0] + a->in[1] + a->in[2];
asm volatile ("csrr %0, mcause" : "=r" (a->out[2]));
asm volatile ("csrr %0, mstatus" : "=r" (a->out[3]));
}

View File

@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
typedef struct {
uint32_t in[3];
uint32_t out[4];
} arg_data_t;
void get_mstatus_other_cpu(void *arg);
void extended_ipc_isr_func(void* arg);

View File

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "esp_log.h"
#include "esp_ipc_isr.h"
#include "callbacks.h"
#include "sdkconfig.h"
static const char* TAG = "example";
void app_main(void)
{
ESP_LOGI(TAG, "Start");
uint32_t mstatus_other_cpu = 0;
ESP_LOGI(TAG, "call get_mstatus_other_cpu");
esp_ipc_isr_call_blocking(get_mstatus_other_cpu, &mstatus_other_cpu);
ESP_LOGI(TAG, "MSTATUS = 0x%"PRIx32, mstatus_other_cpu);
ESP_LOGI(TAG, "call extended_ipc_isr_func");
arg_data_t arg = { 0 };
arg.in[0] = 0x01;
arg.in[1] = 0x02;
arg.in[2] = 0x03;
ESP_LOGI(TAG, "in[0] = 0x%"PRIx32, arg.in[0]);
ESP_LOGI(TAG, "in[1] = 0x%"PRIx32, arg.in[1]);
ESP_LOGI(TAG, "in[2] = 0x%"PRIx32, arg.in[2]);
esp_ipc_isr_call_blocking(extended_ipc_isr_func, (void*)&arg);
ESP_LOGI(TAG, "out[0] = (in[0] | in[1] | in[2]) = 0x%"PRIx32, arg.out[0]);
assert(0x03 == arg.out[0]);
ESP_LOGI(TAG, "out[1] = (in[0] + in[1] + in[2]) = 0x%"PRIx32, arg.out[1]);
assert(0x06 == arg.out[1]);
ESP_LOGI(TAG, "out[2] = MCAUSE of other cpu = 0x%"PRIx32, arg.out[2]);
assert(0xb800002c == arg.out[2]);
ESP_LOGI(TAG, "out[3] = MSTATUS of other cpu = 0x%"PRIx32, arg.out[3]);
assert(mstatus_other_cpu == arg.out[3]);
ESP_LOGI(TAG, "End");
}

View File

@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32p4
@pytest.mark.generic
def test_ipc_isr(dut: Dut) -> None:
dut.expect_exact('example: Start')
dut.expect_exact('example: MSTATUS = 0x3880')
dut.expect_exact('example: in[0] = 0x1')
dut.expect_exact('example: in[1] = 0x2')
dut.expect_exact('example: in[2] = 0x3')
dut.expect_exact('example: out[0] = (in[0] | in[1] | in[2]) = 0x3')
dut.expect_exact('example: out[1] = (in[0] + in[1] + in[2]) = 0x6')
dut.expect_exact('example: out[2] = MCAUSE of other cpu = 0xb800002c')
dut.expect_exact('example: out[3] = MSTATUS of other cpu = 0x3880')
dut.expect_exact('example: End')

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ipc_isr)

View File

@ -53,7 +53,7 @@ I (324) example: in[0] = 0x1
I (334) example: in[1] = 0x2
I (334) example: in[2] = 0x3
I (334) example: out[0] = (in[0] | in[1] | in[2]) = 0x3
I (344) example: out[1] = (in[0] & in[1] & in[2]) = 0x6
I (344) example: out[1] = (in[0] + in[1] + in[2]) = 0x6
I (354) example: out[2] = in[2] = 0x3
I (354) example: out[3] = PS of other cpu = 0x25
I (364) example: End

View File

@ -1,16 +1,12 @@
/* ipc_isr example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "esp_timer.h"
#include "esp_log.h"
#include "esp_ipc_isr.h"
#include "sdkconfig.h"
@ -36,7 +32,7 @@ void app_main(void)
ESP_LOGI(TAG, "Start");
uint32_t ps_other_cpu = 0;
ESP_LOGI(TAG, "call get_ps_other_cpu");
esp_ipc_isr_asm_call_blocking(get_ps_other_cpu, &ps_other_cpu);
esp_ipc_isr_call_blocking(get_ps_other_cpu, &ps_other_cpu);
ESP_LOGI(TAG, "PS_INTLEVEL = 0x%"PRIx32, ps_other_cpu & XCHAL_PS_INTLEVEL_MASK);
ESP_LOGI(TAG, "PS_EXCM = 0x%"PRIx32, (ps_other_cpu & XCHAL_PS_EXCM_MASK) >> XCHAL_PS_EXCM_SHIFT);
ESP_LOGI(TAG, "PS_UM = 0x%"PRIx32, (ps_other_cpu & XCHAL_PS_UM_MASK) >> XCHAL_PS_UM_SHIFT);
@ -49,10 +45,10 @@ void app_main(void)
ESP_LOGI(TAG, "in[0] = 0x%"PRIx32, arg.in[0]);
ESP_LOGI(TAG, "in[1] = 0x%"PRIx32, arg.in[1]);
ESP_LOGI(TAG, "in[2] = 0x%"PRIx32, arg.in[2]);
esp_ipc_isr_asm_call_blocking(extended_ipc_isr_asm, (void*)&arg);
esp_ipc_isr_call_blocking(extended_ipc_isr_asm, (void*)&arg);
ESP_LOGI(TAG, "out[0] = (in[0] | in[1] | in[2]) = 0x%"PRIx32, arg.out[0]);
assert(0x03 == arg.out[0]);
ESP_LOGI(TAG, "out[1] = (in[0] & in[1] & in[2]) = 0x%"PRIx32, arg.out[1]);
ESP_LOGI(TAG, "out[1] = (in[0] + in[1] + in[2]) = 0x%"PRIx32, arg.out[1]);
assert(0x06 == arg.out[1]);
ESP_LOGI(TAG, "out[2] = in[2] = 0x%"PRIx32, arg.out[2]);
assert(0x03 == arg.out[2]);

View File

@ -18,7 +18,7 @@ def test_ipc_isr(dut: Dut) -> None:
dut.expect_exact('example: in[1] = 0x2')
dut.expect_exact('example: in[2] = 0x3')
dut.expect_exact('example: out[0] = (in[0] | in[1] | in[2]) = 0x3')
dut.expect_exact('example: out[1] = (in[0] & in[1] & in[2]) = 0x6')
dut.expect_exact('example: out[1] = (in[0] + in[1] + in[2]) = 0x6')
dut.expect_exact('example: out[2] = in[2] = 0x3')
dut.expect_exact('example: out[3] = PS of other cpu = 0x25')
dut.expect_exact('example: End')

View File

@ -1271,7 +1271,6 @@ examples/system/gcov/main/gcov_example_main.c
examples/system/gdbstub/main/gdbstub_main.c
examples/system/heap_task_tracking/main/heap_task_tracking_main.c
examples/system/himem/main/himem_example_main.c
examples/system/ipc/ipc_isr/main/main.c
examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c
examples/system/ota/native_ota_example/main/native_ota_example.c
examples/system/ota/otatool/main/otatool_main.c