forked from espressif/esp-idf
feat(esp_system): Support IPC_ISR for ESP32P4
This commit is contained in:
@@ -530,19 +530,19 @@ menu "ESP System Settings"
|
|||||||
prompt "Interrupt level to use for Interrupt Watchdog and other system checks"
|
prompt "Interrupt level to use for Interrupt Watchdog and other system checks"
|
||||||
default ESP_SYSTEM_CHECK_INT_LEVEL_4
|
default ESP_SYSTEM_CHECK_INT_LEVEL_4
|
||||||
help
|
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
|
config ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
bool "Level 5 interrupt"
|
bool "Level 5 interrupt"
|
||||||
depends on IDF_TARGET_ESP32
|
depends on IDF_TARGET_ESP32
|
||||||
help
|
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
|
config ESP_SYSTEM_CHECK_INT_LEVEL_4
|
||||||
bool "Level 4 interrupt"
|
bool "Level 4 interrupt"
|
||||||
depends on !BTDM_CTRL_HLI
|
depends on !BTDM_CTRL_HLI
|
||||||
help
|
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
|
endchoice
|
||||||
|
|
||||||
# Insert chip-specific system config
|
# Insert chip-specific system config
|
||||||
@@ -595,11 +595,10 @@ menu "IPC (Inter-Processor Call)"
|
|||||||
|
|
||||||
config ESP_IPC_ISR_ENABLE
|
config ESP_IPC_ISR_ENABLE
|
||||||
bool
|
bool
|
||||||
default n if IDF_TARGET_ESP32P4 # TODO: IDF-7769
|
|
||||||
default y if !FREERTOS_UNICORE
|
default y if !FREERTOS_UNICORE
|
||||||
help
|
help
|
||||||
The IPC ISR feature is similar to the IPC feature except that the callback function is executed in the
|
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 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
|
callbacks must be written with particular restrictions (see "IPC" and "High-Level Interrupt" docs for more
|
||||||
details).
|
details).
|
||||||
|
@@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -17,31 +17,44 @@ extern "C" {
|
|||||||
/**
|
/**
|
||||||
* @brief IPC ISR Callback
|
* @brief IPC ISR Callback
|
||||||
*
|
*
|
||||||
* A callback of this type should be provided as an argument when calling esp_ipc_isr_asm_call() or
|
* The callback must be written:
|
||||||
* esp_ipc_isr_asm_call_blocking().
|
* - 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);
|
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.
|
* 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
|
* - 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
|
* - The callback must be written:
|
||||||
* registers. See docs for more details
|
* - 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.
|
* @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] 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
|
* @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.
|
* the callback completes.
|
||||||
*
|
*
|
||||||
* @note This function is not available in single-core mode.
|
* @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] 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
|
* @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
|
* @brief Stall the other CPU
|
||||||
|
@@ -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
|
* - 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.
|
* the CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL option.
|
||||||
* - Callbacks written in assembly can then run in context of the registered High Priority Interrupts
|
* - 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);
|
void esp_ipc_isr_init(void);
|
||||||
|
|
||||||
|
@@ -17,11 +17,16 @@ if(CONFIG_ESP_CONSOLE_USB_CDC)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CONFIG_ESP_IPC_ISR_ENABLE)
|
if(CONFIG_ESP_IPC_ISR_ENABLE)
|
||||||
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
|
list(APPEND srcs "esp_ipc_isr.c")
|
||||||
list(APPEND srcs "arch/xtensa/esp_ipc_isr.c"
|
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
|
||||||
"arch/xtensa/esp_ipc_isr_handler.S"
|
list(APPEND srcs "arch/xtensa/esp_ipc_isr_port.c"
|
||||||
"arch/xtensa/esp_ipc_isr_routines.S")
|
"arch/xtensa/esp_ipc_isr_handler.S"
|
||||||
endif()
|
"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()
|
endif()
|
||||||
|
|
||||||
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
|
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
|
||||||
|
78
components/esp_system/port/arch/riscv/esp_ipc_isr_handler.S
Normal file
78
components/esp_system/port/arch/riscv/esp_ipc_isr_handler.S
Normal 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
|
48
components/esp_system/port/arch/riscv/esp_ipc_isr_port.c
Normal file
48
components/esp_system/port/arch/riscv/esp_ipc_isr_port.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
12
components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c
Normal file
12
components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c
Normal 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) { };
|
||||||
|
}
|
36
components/esp_system/port/arch/xtensa/esp_ipc_isr_port.c
Normal file
36
components/esp_system/port/arch/xtensa/esp_ipc_isr_port.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -10,19 +10,12 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_attr.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/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/portmacro.h"
|
#include "freertos/portmacro.h"
|
||||||
#include "esp_intr_alloc.h"
|
|
||||||
#include "esp_private/esp_ipc_isr.h"
|
#include "esp_private/esp_ipc_isr.h"
|
||||||
|
#include "esp_private/esp_ipc_isr_port.h"
|
||||||
#include "esp_ipc_isr.h"
|
#include "esp_ipc_isr.h"
|
||||||
#include "xtensa/core-macros.h"
|
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
static portMUX_TYPE s_ipc_isr_mux = portMUX_INITIALIZER_UNLOCKED;
|
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)
|
void esp_ipc_isr_init(void)
|
||||||
{
|
{
|
||||||
const uint32_t cpuid = xPortGetCoreID();
|
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_ipc_isr_port_init(cpuid);
|
||||||
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);
|
|
||||||
|
|
||||||
if (cpuid != 0) {
|
if (cpuid != 0) {
|
||||||
s_stall_state = STALL_STATE_RUNNING;
|
s_stall_state = STALL_STATE_RUNNING;
|
||||||
@@ -76,14 +66,14 @@ void esp_ipc_isr_init(void)
|
|||||||
|
|
||||||
/* Public API functions */
|
/* 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();
|
IPC_ISR_ENTER_CRITICAL();
|
||||||
esp_ipc_isr_call_and_wait(func, arg, IPC_ISR_WAIT_FOR_START);
|
esp_ipc_isr_call_and_wait(func, arg, IPC_ISR_WAIT_FOR_START);
|
||||||
IPC_ISR_EXIT_CRITICAL();
|
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();
|
IPC_ISR_ENTER_CRITICAL();
|
||||||
esp_ipc_isr_call_and_wait(func, arg, IPC_ISR_WAIT_FOR_END);
|
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_start_fl = 0;
|
||||||
esp_ipc_isr_end_fl = 0;
|
esp_ipc_isr_end_fl = 0;
|
||||||
|
|
||||||
if (cpu_id == 0) {
|
// Trigger an interrupt on the opposite core.
|
||||||
// it runs an interrupt on cpu1
|
esp_ipc_isr_port_int_trigger(!cpu_id);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPC_ISR handler will be called and `...isr_start` and `...isr_end` will be updated there
|
// IPC_ISR handler will be called and `...isr_start` and `...isr_end` will be updated there
|
||||||
|
|
||||||
if (wait_for == IPC_ISR_WAIT_FOR_START) {
|
if (wait_for == IPC_ISR_WAIT_FOR_START) {
|
@@ -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
|
@@ -16,7 +16,12 @@ set(SRC "test_app_main.c"
|
|||||||
"test_task_wdt.c")
|
"test_task_wdt.c")
|
||||||
|
|
||||||
if(CONFIG_ESP_IPC_ISR_ENABLE)
|
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()
|
endif()
|
||||||
|
|
||||||
idf_component_register(SRCS ${SRC}
|
idf_component_register(SRCS ${SRC}
|
||||||
|
@@ -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
|
@@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -13,18 +13,18 @@
|
|||||||
#include <xtensa/config/system.h>
|
#include <xtensa/config/system.h>
|
||||||
#include <xtensa/hal.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.
|
* 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.
|
* Only these registers [a2, a3, a4] can be used here.
|
||||||
*/
|
*/
|
||||||
.section .iram1, "ax"
|
.section .iram1, "ax"
|
||||||
.align 4
|
.align 4
|
||||||
.global esp_test_ipc_isr_asm
|
.global esp_test_ipc_isr_callback
|
||||||
.type esp_test_ipc_isr_asm, @function
|
.type esp_test_ipc_isr_callback, @function
|
||||||
// Args:
|
// Args:
|
||||||
// a2 - void* arg
|
// a2 - void* arg
|
||||||
esp_test_ipc_isr_asm:
|
esp_test_ipc_isr_callback:
|
||||||
movi a3, 0xa5a5
|
movi a3, 0xa5a5
|
||||||
s32i a3, a2, 0
|
s32i a3, a2, 0
|
||||||
ret
|
ret
|
@@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -17,12 +17,18 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_ESP_IPC_ISR_ENABLE
|
#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]")
|
TEST_CASE("Test ipc_isr blocking IPC function calls a ASM function", "[ipc]")
|
||||||
{
|
{
|
||||||
int val = 0x5a5a;
|
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);
|
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]")
|
TEST_CASE("Test ipc_isr blocking IPC function calls get_other_core_id", "[ipc]")
|
||||||
{
|
{
|
||||||
int val = 0x5a5a;
|
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);
|
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)
|
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_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]",
|
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_asm_call_blocking,
|
do_esp_ipc_isr_call_blocking,
|
||||||
check_reset_reason_panic)
|
check_reset_reason_panic)
|
||||||
|
|
||||||
void esp_test_ipc_isr_get_cycle_count_other_cpu(void* arg);
|
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]")
|
TEST_CASE("Test ipc_isr blocking IPC function calls get_cycle_count_other_cpu", "[ipc]")
|
||||||
{
|
{
|
||||||
int val = 0x5a5a;
|
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 CPU0 = %d\n", esp_cpu_get_cycle_count());
|
||||||
esp_rom_printf("CCOUNT CPU1 = %d\n", val);
|
esp_rom_printf("CCOUNT CPU1 = %d\n", val);
|
||||||
}
|
}
|
||||||
@@ -70,12 +76,12 @@ static void task_asm(void *arg)
|
|||||||
printf("task_asm\n");
|
printf("task_asm\n");
|
||||||
while (s_stop == false) {
|
while (s_stop == false) {
|
||||||
val = 0x5a5a;
|
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);
|
TEST_ASSERT_EQUAL_HEX(val, 0xa5a5);
|
||||||
++counter;
|
++counter;
|
||||||
}
|
}
|
||||||
printf("task_asm counter = %d\n", counter);
|
printf("task_asm counter = %d\n", counter);
|
||||||
TEST_ASSERT_GREATER_THAN(10000, counter);
|
TEST_ASSERT_GREATER_THAN(1000, counter);
|
||||||
xSemaphoreGive(*sema);
|
xSemaphoreGive(*sema);
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,12 @@
|
|||||||
#define MEMPROT_ISR _interrupt_handler
|
#define MEMPROT_ISR _interrupt_handler
|
||||||
#endif // CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
|
#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. */
|
/* The system interrupts are not used for now, so trigger a panic every time one occurs. */
|
||||||
#define _system_int_handler _panic_handler
|
#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 _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 MEMPROT_ISR /* 42: ETS_MEMPROT_ERR_INUM (+16) handler (soc-level panic) */
|
||||||
.word _interrupt_handler /* 43: Free interrupt number */
|
.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 /* 45: Free interrupt number */
|
||||||
.word _interrupt_handler /* 46: Free interrupt number */
|
.word _interrupt_handler /* 46: Free interrupt number */
|
||||||
.word _interrupt_handler /* 47: Free interrupt number */
|
.word _interrupt_handler /* 47: Free interrupt number */
|
||||||
|
@@ -5,7 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "soc/soc.h"
|
#include "soc/soc.h"
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@@ -234,6 +234,7 @@
|
|||||||
#define ETS_T1_WDT_INUM 24
|
#define ETS_T1_WDT_INUM 24
|
||||||
#define ETS_CACHEERR_INUM 25
|
#define ETS_CACHEERR_INUM 25
|
||||||
#define ETS_MEMPROT_ERR_INUM 26
|
#define ETS_MEMPROT_ERR_INUM 26
|
||||||
|
#define ETS_IPC_ISR_INUM 28
|
||||||
//CPU0 Max valid interrupt number
|
//CPU0 Max valid interrupt number
|
||||||
#define ETS_MAX_INUM 31
|
#define ETS_MAX_INUM 31
|
||||||
|
|
||||||
|
@@ -183,7 +183,6 @@ api-reference/system/bootloader_image_format.rst
|
|||||||
api-reference/system/inc/power_management_esp32p4.rst
|
api-reference/system/inc/power_management_esp32p4.rst
|
||||||
api-reference/system/heap_debug.rst
|
api-reference/system/heap_debug.rst
|
||||||
api-reference/system/mm.rst
|
api-reference/system/mm.rst
|
||||||
api-reference/system/ipc.rst
|
|
||||||
api-reference/system/esp_https_ota.rst
|
api-reference/system/esp_https_ota.rst
|
||||||
api-reference/system/ulp-risc-v.rst
|
api-reference/system/ulp-risc-v.rst
|
||||||
api-reference/system/esp_err.rst
|
api-reference/system/esp_err.rst
|
||||||
|
@@ -24,7 +24,7 @@ System API
|
|||||||
heap_debug
|
heap_debug
|
||||||
esp_timer
|
esp_timer
|
||||||
internal-unstable
|
internal-unstable
|
||||||
:not CONFIG_FREERTOS_UNICORE or esp32p4: ipc
|
:not CONFIG_FREERTOS_UNICORE: ipc
|
||||||
intr_alloc
|
intr_alloc
|
||||||
log
|
log
|
||||||
misc_system_api
|
misc_system_api
|
||||||
|
@@ -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).
|
- 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.
|
- Reading the registers/state of another CPU.
|
||||||
|
|
||||||
|
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.
|
||||||
.. 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.
|
|
||||||
|
|
||||||
|
|
||||||
IPC in Task Context
|
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` 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_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.
|
When using IPCs in High Priority Interrupt context, users need to consider the following:
|
||||||
- The priority of the reserved High Priority Interrupt is dependent on the :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` option
|
|
||||||
- When the callback executes:
|
|
||||||
|
|
||||||
- The calling CPU will disable interrupts of level 3 and lower
|
.. list::
|
||||||
- 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_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
|
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
|
High Priority Interrupt IPC callbacks have the following restrictions:
|
||||||
- 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``).
|
- The callback must be of type ``void func(void *arg)`` but implemented entirely in assembly
|
||||||
- Must not call other C functions as register windowing is disabled
|
- The callback is invoked via the ``CALLX0`` instruction with register windowing disabled, thus the callback:
|
||||||
- The callback should be placed in IRAM at a 4-byte aligned address
|
- Must not call any register window related instructions (e.g., ``entry`` and ``retw``).
|
||||||
- (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.
|
- Must not call other C functions as register windowing is disabled
|
||||||
- ``a2`` contains the ``void *arg`` of the callback
|
- The callback should be placed in IRAM at a 4-byte aligned address
|
||||||
- ``a3/a4`` are free to use as scratch registers
|
- (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.
|
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_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_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) */
|
.. code-block:: asm
|
||||||
// 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:: 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;
|
.. code-block:: c
|
||||||
esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)cycle_count);
|
|
||||||
|
|
||||||
.. 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:
|
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.
|
.. list::
|
||||||
- :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 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
|
API Reference
|
||||||
-------------
|
-------------
|
||||||
|
@@ -80,11 +80,21 @@ examples/system/himem:
|
|||||||
temporary: true
|
temporary: true
|
||||||
reason: the other targets are not tested yet
|
reason: the other targets are not tested yet
|
||||||
|
|
||||||
examples/system/ipc/ipc_isr:
|
examples/system/ipc/ipc_isr/riscv:
|
||||||
enable:
|
enable:
|
||||||
- if: IDF_TARGET == "esp32" or IDF_TARGET == "esp32s3"
|
- if: IDF_TARGET_ARCH_RISCV == 1 and ESP_IPC_ISR_ENABLE == 1
|
||||||
temporary: true
|
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:
|
examples/system/light_sleep:
|
||||||
disable:
|
disable:
|
||||||
|
56
examples/system/ipc/ipc_isr/riscv/README.md
Normal file
56
examples/system/ipc/ipc_isr/riscv/README.md
Normal 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
|
||||||
|
```
|
3
examples/system/ipc/ipc_isr/riscv/main/CMakeLists.txt
Normal file
3
examples/system/ipc/ipc_isr/riscv/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
idf_component_register(SRCS "main.c"
|
||||||
|
"callbacks.c"
|
||||||
|
INCLUDE_DIRS ".")
|
22
examples/system/ipc/ipc_isr/riscv/main/callbacks.c
Normal file
22
examples/system/ipc/ipc_isr/riscv/main/callbacks.c
Normal 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]));
|
||||||
|
}
|
15
examples/system/ipc/ipc_isr/riscv/main/callbacks.h
Normal file
15
examples/system/ipc/ipc_isr/riscv/main/callbacks.h
Normal 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);
|
43
examples/system/ipc/ipc_isr/riscv/main/main.c
Normal file
43
examples/system/ipc/ipc_isr/riscv/main/main.c
Normal 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");
|
||||||
|
}
|
20
examples/system/ipc/ipc_isr/riscv/pytest_ipc_isr_riscv.py
Normal file
20
examples/system/ipc/ipc_isr/riscv/pytest_ipc_isr_riscv.py
Normal 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')
|
6
examples/system/ipc/ipc_isr/xtensa/CMakeLists.txt
Normal file
6
examples/system/ipc/ipc_isr/xtensa/CMakeLists.txt
Normal 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)
|
@@ -53,7 +53,7 @@ I (324) example: in[0] = 0x1
|
|||||||
I (334) example: in[1] = 0x2
|
I (334) example: in[1] = 0x2
|
||||||
I (334) example: in[2] = 0x3
|
I (334) example: in[2] = 0x3
|
||||||
I (334) example: out[0] = (in[0] | in[1] | 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[2] = in[2] = 0x3
|
||||||
I (354) example: out[3] = PS of other cpu = 0x25
|
I (354) example: out[3] = PS of other cpu = 0x25
|
||||||
I (364) example: End
|
I (364) example: End
|
@@ -1,16 +1,12 @@
|
|||||||
/* ipc_isr example
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
*
|
||||||
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "esp_timer.h"
|
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_ipc_isr.h"
|
#include "esp_ipc_isr.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
@@ -36,7 +32,7 @@ void app_main(void)
|
|||||||
ESP_LOGI(TAG, "Start");
|
ESP_LOGI(TAG, "Start");
|
||||||
uint32_t ps_other_cpu = 0;
|
uint32_t ps_other_cpu = 0;
|
||||||
ESP_LOGI(TAG, "call get_ps_other_cpu");
|
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_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_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);
|
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[0] = 0x%"PRIx32, arg.in[0]);
|
||||||
ESP_LOGI(TAG, "in[1] = 0x%"PRIx32, arg.in[1]);
|
ESP_LOGI(TAG, "in[1] = 0x%"PRIx32, arg.in[1]);
|
||||||
ESP_LOGI(TAG, "in[2] = 0x%"PRIx32, arg.in[2]);
|
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]);
|
ESP_LOGI(TAG, "out[0] = (in[0] | in[1] | in[2]) = 0x%"PRIx32, arg.out[0]);
|
||||||
assert(0x03 == 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]);
|
assert(0x06 == arg.out[1]);
|
||||||
ESP_LOGI(TAG, "out[2] = in[2] = 0x%"PRIx32, arg.out[2]);
|
ESP_LOGI(TAG, "out[2] = in[2] = 0x%"PRIx32, arg.out[2]);
|
||||||
assert(0x03 == arg.out[2]);
|
assert(0x03 == arg.out[2]);
|
@@ -18,7 +18,7 @@ def test_ipc_isr(dut: Dut) -> None:
|
|||||||
dut.expect_exact('example: in[1] = 0x2')
|
dut.expect_exact('example: in[1] = 0x2')
|
||||||
dut.expect_exact('example: in[2] = 0x3')
|
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[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[2] = in[2] = 0x3')
|
||||||
dut.expect_exact('example: out[3] = PS of other cpu = 0x25')
|
dut.expect_exact('example: out[3] = PS of other cpu = 0x25')
|
||||||
dut.expect_exact('example: End')
|
dut.expect_exact('example: End')
|
@@ -1271,7 +1271,6 @@ examples/system/gcov/main/gcov_example_main.c
|
|||||||
examples/system/gdbstub/main/gdbstub_main.c
|
examples/system/gdbstub/main/gdbstub_main.c
|
||||||
examples/system/heap_task_tracking/main/heap_task_tracking_main.c
|
examples/system/heap_task_tracking/main/heap_task_tracking_main.c
|
||||||
examples/system/himem/main/himem_example_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/advanced_https_ota/main/advanced_https_ota_example.c
|
||||||
examples/system/ota/native_ota_example/main/native_ota_example.c
|
examples/system/ota/native_ota_example/main/native_ota_example.c
|
||||||
examples/system/ota/otatool/main/otatool_main.c
|
examples/system/ota/otatool/main/otatool_main.c
|
||||||
|
Reference in New Issue
Block a user