Merge branch 'feature/lp_core_interrupts' into 'master'

feat(ulp): support interrupts for C6/P4 LP core

Closes IDFGH-11986 and IDF-7200

See merge request espressif/esp-idf!30399
This commit is contained in:
Marius Vikhammer
2024-04-29 14:36:54 +08:00
34 changed files with 796 additions and 32 deletions

View File

@@ -101,7 +101,7 @@ if(ULP_COCPU_IS_RISCV)
elseif(ULP_COCPU_IS_LP_CORE)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/start.S"
"${IDF_PATH}/components/ulp/lp_core/lp_core/vector.S"
"${IDF_PATH}/components/ulp/lp_core/lp_core/port/${IDF_TARGET}/vector.S"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_timer_shared.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_startup.c"
@@ -111,6 +111,7 @@ elseif(ULP_COCPU_IS_LP_CORE)
"${IDF_PATH}/components/hal/uart_hal.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_uart.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_print.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_interrupt.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c")
target_link_options(${ULP_APP_NAME} PRIVATE "-nostartfiles")

View File

@@ -63,6 +63,14 @@ esp_err_t ulp_lp_core_load_binary(const uint8_t* program_binary, size_t program_
*/
void ulp_lp_core_stop(void);
/**
* @brief Trigger a SW interrupt to the LP CPU from the PMU
*
* @note This is the same SW trigger that is used to wake up the LP CPU
*
*/
void ulp_lp_core_sw_intr_trigger(void);
#ifdef __cplusplus
}
#endif

View File

@@ -36,6 +36,8 @@ const static char* TAG = "ulp-lp-core";
#define WAKEUP_SOURCE_MAX_NUMBER 5
#define RESET_HANDLER_ADDR (intptr_t)(&_rtc_ulp_memory_start + 0x80 / 4) // Placed after the 0x80 byte long vector table
/* Maps the flags defined in ulp_lp_core.h e.g. ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU to their actual HW values */
static uint32_t wakeup_src_sw_to_hw_flag_lookup[WAKEUP_SOURCE_MAX_NUMBER] = {
LP_CORE_LL_WAKEUP_SOURCE_HP_CPU,
@@ -68,7 +70,7 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg)
/* If we have a LP ROM we boot from it, before jumping to the app code */
intptr_t boot_addr;
if (cfg->skip_lp_rom_boot) {
boot_addr = (intptr_t)(&_rtc_ulp_memory_start);
boot_addr = RESET_HANDLER_ADDR;
} else {
boot_addr = SOC_LP_ROM_LOW;
/* Disable UART init in ROM, it defaults to XTAL clk src
@@ -80,7 +82,8 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg)
}
lp_core_ll_set_boot_address(boot_addr);
lp_core_ll_set_app_boot_address((intptr_t)(&_rtc_ulp_memory_start));
lp_core_ll_set_app_boot_address(RESET_HANDLER_ADDR);
#endif //ESP_ROM_HAS_LP_ROM
LP_CORE_RCC_ATOMIC() {
@@ -161,3 +164,8 @@ void ulp_lp_core_stop(void)
lp_core_ll_set_wakeup_source(0);
lp_core_ll_request_sleep();
}
void ulp_lp_core_sw_intr_trigger(void)
{
lp_core_ll_hp_wake_lp();
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -10,6 +10,7 @@
extern "C" {
#endif
#include "soc/soc_caps.h"
#include "hal/gpio_types.h"
#include "hal/rtc_io_ll.h"
@@ -25,8 +26,27 @@ typedef enum {
LP_IO_NUM_5 = 5, /*!< GPIO5, input and output */
LP_IO_NUM_6 = 6, /*!< GPIO6, input and output */
LP_IO_NUM_7 = 7, /*!< GPIO7, input and output */
#if SOC_RTCIO_PIN_COUNT > 8
LP_IO_NUM_8 = 8, /*!< GPIO8, input and output */
LP_IO_NUM_9 = 9, /*!< GPIO9, input and output */
LP_IO_NUM_10 = 10, /*!< GPIO10, input and output */
LP_IO_NUM_11 = 11, /*!< GPIO11, input and output */
LP_IO_NUM_12 = 12, /*!< GPIO12, input and output */
LP_IO_NUM_13 = 13, /*!< GPIO13, input and output */
LP_IO_NUM_14 = 14, /*!< GPIO14, input and output */
LP_IO_NUM_15 = 15, /*!< GPIO15, input and output */
#endif
} lp_io_num_t;
typedef enum {
LP_IO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt */
LP_IO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */
LP_IO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */
LP_IO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge */
LP_IO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger */
LP_IO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger */
} lp_io_intr_type_t;
/**
* @brief Initialize a rtcio pin
*
@@ -153,6 +173,26 @@ static inline void ulp_lp_core_gpio_pulldown_disable(lp_io_num_t lp_io_num)
rtcio_ll_pulldown_disable(lp_io_num);
}
/**
* @brief Enable interrupt for lp io pin
*
* @param lp_io_num The lp io pin to enable interrupt for
* @param intr_type The interrupt type to enable
*/
static inline void ulp_lp_core_gpio_intr_enable(lp_io_num_t lp_io_num, lp_io_intr_type_t intr_type)
{
rtcio_ll_intr_enable(lp_io_num, intr_type);
}
/**
* @brief Clear interrupt status for all lp io
*
*/
static inline void ulp_lp_core_gpio_clear_intr_status(void)
{
rtcio_ll_clear_interrupt_status();
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,59 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32C6
#define LP_CORE_ISR_ATTR // On C6 registers are saved by us before calling the ISR
#else
#define LP_CORE_ISR_ATTR __attribute__((interrupt))
#endif
/**
* Available interrupt handlers for the low power core are as follows:
*
* ulp_lp_core_lp_io_intr_handler(void);
* ulp_lp_core_lp_i2c_intr_handler(void);
* ulp_lp_core_lp_uart_intr_handler(void);
* ulp_lp_core_lp_timer_intr_handler(void);
* ulp_lp_core_lp_pmu_intr_handler(void);
* ulp_lp_core_lp_spi_intr_handler(void);
* ulp_lp_core_trng_intr_handler(void);
* ulp_lp_core_lp_adc_intr_handler(void);
* ulp_lp_core_lp_touch_intr_handler(void);
* ulp_lp_core_tsens_intr_handler(void);
* ulp_lp_core_efuse_intr_handler(void);
* ulp_lp_core_lp_sysreg_intr_handler(void);
* ulp_lp_core_lp_ana_peri_intr_handler(void);
* ulp_lp_core_mailbox_intr_handler(void);
* ulp_lp_core_lp_wdt_intr_handler(void);
* ulp_lp_core_lp_rtc_intr_handler(void);
* ulp_lp_core_sw_intr_handler(void);
*
* Not all handlers are available on all chips. Please refer to the Technical Reference Manual for your chip for more information.
*/
/**
* @brief Enables interrupts globally for the low power core
*
*/
void ulp_lp_core_intr_enable(void);
/**
* @brief Disables interrupts globally for the low power core
*
*/
void ulp_lp_core_intr_disable(void);
#ifdef __cplusplus
}
#endif

View File

@@ -3,6 +3,8 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
/**
@@ -17,7 +19,7 @@
*/
#if CONFIG_ULP_ROM_PRINT_ENABLE
extern int ets_printf(const char* format, ...);
int (*lp_core_printf)(const char* format, ...) = ets_printf;
#define lp_core_printf ets_printf
#else
//TODO: Change return type from void to int in IDF 6.0
void lp_core_printf(const char* format, ...);
@@ -33,5 +35,5 @@ void lp_core_printf(const char* format, ...);
* powered down during sleep.
*/
extern void ets_install_uart_printf(void);
void (*lp_core_install_uart_printf)(void) = ets_install_uart_printf;
#define lp_core_install_uart_print ets_install_uart_printf
#endif /* CONFIG_ULP_ROM_PRINT_ENABLE */

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -12,6 +12,7 @@ extern "C" {
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
/**
* @brief Traverse all possible wake-up sources and update the wake-up cause so that
@@ -72,6 +73,22 @@ __attribute__((__noreturn__)) void ulp_lp_core_halt(void);
*/
__attribute__((__noreturn__)) void ulp_lp_core_stop_lp_core(void);
/**
* @brief Enable the SW triggered interrupt from the PMU
*
* @note This is the same SW trigger interrupt that is used to wake up the LP CPU
*
* @param enable true to enable, false to disable
*
*/
void ulp_lp_core_sw_intr_enable(bool enable);
/**
* @brief Clear the interrupt status for the SW triggered interrupt from the PMU
*
*/
void ulp_lp_core_sw_intr_clear(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,92 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdkconfig.h"
#include "hal/lp_core_ll.h"
#include "riscv/rv_utils.h"
#if CONFIG_IDF_TARGET_ESP32C6
/* Enable interrupt 30, which all external interrupts are routed to*/
#define MIE_ALL_INTS_MASK (1 << 30)
#else
/* Enable all external interrupts routed to CPU, expect HP_INTR,
as this would trigger an LP core interrupt for every single interrupt
that triggers on HP Core.
*/
#define MIE_ALL_INTS_MASK 0x3FFF0888
#endif
void ulp_lp_core_intr_enable(void)
{
/* Enable interrupt globally */
RV_SET_CSR(mstatus, MSTATUS_MIE);
RV_SET_CSR(mie, MIE_ALL_INTS_MASK);
}
void ulp_lp_core_intr_disable(void)
{
RV_CLEAR_CSR(mie, MIE_ALL_INTS_MASK);
/* Disable interrupts globally */
RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
}
static void ulp_lp_core_default_intr_handler(void)
{
abort();
}
/* Default ISR handlers, intended to be overwritten by users */
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_io_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_i2c_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_uart_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_timer_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_pmu_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_spi_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_trng_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_adc_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_touch_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_tsens_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_efuse_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_sysreg_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_ana_peri_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_mailbox_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_wdt_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_rtc_intr_handler(void);
void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_sw_intr_handler(void);
void ulp_lp_core_panic_handler(void)
{
abort();
}
#if CONFIG_IDF_TARGET_ESP32C6
static void* s_intr_handlers[] = {
ulp_lp_core_lp_io_intr_handler,
ulp_lp_core_lp_i2c_intr_handler,
ulp_lp_core_lp_uart_intr_handler,
ulp_lp_core_lp_timer_intr_handler,
0, // Reserved / Unused
ulp_lp_core_lp_pmu_intr_handler,
};
void __attribute__((weak)) ulp_lp_core_intr_handler(void)
{
uint8_t intr_source = lp_core_ll_get_triggered_interrupt_srcs();
for (int i = 0; i < sizeof(s_intr_handlers) / 4; i++) {
if (intr_source & (1 << i)) {
void (*handler)(void) = s_intr_handlers[i];
if (handler) {
handler();
}
}
}
}
#endif

View File

@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdarg.h>
#include "sdkconfig.h"
#include "ulp_lp_core_uart.h"
#if !CONFIG_ULP_ROM_PRINT_ENABLE

View File

@@ -135,3 +135,13 @@ void __attribute__((noreturn)) abort(void)
while (1);
}
void ulp_lp_core_sw_intr_enable(bool enable)
{
pmu_ll_lp_enable_sw_intr(&PMU, enable);
}
void ulp_lp_core_sw_intr_clear(void)
{
pmu_ll_lp_clear_sw_intr_status(&PMU);
}

View File

@@ -0,0 +1,138 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "riscv/rvruntime-frames.h"
.equ SAVE_REGS, 32
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
/* Macro which first allocates space on the stack to save general
* purpose registers, and then save them. GP register is excluded.
* The default size allocated on the stack is CONTEXT_SIZE, but it
* can be overridden. */
.macro save_general_regs cxt_size=CONTEXT_SIZE
addi sp, sp, -\cxt_size
sw ra, RV_STK_RA(sp)
sw tp, RV_STK_TP(sp)
sw t0, RV_STK_T0(sp)
sw t1, RV_STK_T1(sp)
sw t2, RV_STK_T2(sp)
sw s0, RV_STK_S0(sp)
sw s1, RV_STK_S1(sp)
sw a0, RV_STK_A0(sp)
sw a1, RV_STK_A1(sp)
sw a2, RV_STK_A2(sp)
sw a3, RV_STK_A3(sp)
sw a4, RV_STK_A4(sp)
sw a5, RV_STK_A5(sp)
sw a6, RV_STK_A6(sp)
sw a7, RV_STK_A7(sp)
sw s2, RV_STK_S2(sp)
sw s3, RV_STK_S3(sp)
sw s4, RV_STK_S4(sp)
sw s5, RV_STK_S5(sp)
sw s6, RV_STK_S6(sp)
sw s7, RV_STK_S7(sp)
sw s8, RV_STK_S8(sp)
sw s9, RV_STK_S9(sp)
sw s10, RV_STK_S10(sp)
sw s11, RV_STK_S11(sp)
sw t3, RV_STK_T3(sp)
sw t4, RV_STK_T4(sp)
sw t5, RV_STK_T5(sp)
sw t6, RV_STK_T6(sp)
.endm
.macro save_mepc
csrr t0, mepc
sw t0, RV_STK_MEPC(sp)
.endm
/* Restore the general purpose registers (excluding gp) from the context on
* the stack. The context is then deallocated. The default size is CONTEXT_SIZE
* but it can be overridden. */
.macro restore_general_regs cxt_size=CONTEXT_SIZE
lw ra, RV_STK_RA(sp)
lw tp, RV_STK_TP(sp)
lw t0, RV_STK_T0(sp)
lw t1, RV_STK_T1(sp)
lw t2, RV_STK_T2(sp)
lw s0, RV_STK_S0(sp)
lw s1, RV_STK_S1(sp)
lw a0, RV_STK_A0(sp)
lw a1, RV_STK_A1(sp)
lw a2, RV_STK_A2(sp)
lw a3, RV_STK_A3(sp)
lw a4, RV_STK_A4(sp)
lw a5, RV_STK_A5(sp)
lw a6, RV_STK_A6(sp)
lw a7, RV_STK_A7(sp)
lw s2, RV_STK_S2(sp)
lw s3, RV_STK_S3(sp)
lw s4, RV_STK_S4(sp)
lw s5, RV_STK_S5(sp)
lw s6, RV_STK_S6(sp)
lw s7, RV_STK_S7(sp)
lw s8, RV_STK_S8(sp)
lw s9, RV_STK_S9(sp)
lw s10, RV_STK_S10(sp)
lw s11, RV_STK_S11(sp)
lw t3, RV_STK_T3(sp)
lw t4, RV_STK_T4(sp)
lw t5, RV_STK_T5(sp)
lw t6, RV_STK_T6(sp)
addi sp,sp, \cxt_size
.endm
.macro restore_mepc
lw t0, RV_STK_MEPC(sp)
csrw mepc, t0
.endm
.section .init.vector,"ax"
.global _vector_table
.type _vector_table, @function
_vector_table:
.option push
.option norvc
.rept 30
j _panic_handler
.endr
j _interrupt_handler // All interrupts are routed to mtvec + 4*30, i.e. the 31st entry
j _panic_handler
.option pop
.size _vector_table, .-_vector_table
/* _panic_handler: handle all exception */
.section .text.handlers,"ax"
.global _panic_handler
.type _panic_handler, @function
_panic_handler:
call ulp_lp_core_panic_handler
_end:
j _end /* loop forever */
/* interrupt_handler: handle all interrupt */
.section .text.handlers,"ax"
.global _interrupt_handler
.type _interrupt_handler, @function
_interrupt_handler:
/* save registers & mepc to stack */
save_general_regs
save_mepc
call ulp_lp_core_intr_handler
/* restore registers & mepc from stack */
restore_mepc
restore_general_regs
/* exit, this will also re-enable the interrupts */
mret

View File

@@ -0,0 +1,59 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
.section .init.vector,"ax"
.global _vector_table
.type _vector_table, @function
_vector_table:
.option push
.option norvc
j _panic_handler
j _panic_handler
j _panic_handler
j ulp_lp_core_sw_intr_handler
j _panic_handler
j _panic_handler
j _panic_handler
j ulp_lp_core_lp_uart_intr_handler
j _panic_handler
j _panic_handler
j _panic_handler
j ulp_lp_core_lp_spi_intr_handler
j _panic_handler
j _panic_handler
j _panic_handler
j _panic_handler
j ulp_lp_core_trng_intr_handler
j ulp_lp_core_lp_i2c_intr_handler
j ulp_lp_core_lp_io_intr_handler
j ulp_lp_core_lp_adc_intr_handler
j ulp_lp_core_lp_touch_intr_handler
j ulp_lp_core_tsens_intr_handler
j ulp_lp_core_efuse_intr_handler
j ulp_lp_core_lp_sysreg_intr_handler
j ulp_lp_core_lp_ana_peri_intr_handler
j ulp_lp_core_lp_pmu_intr_handler
j ulp_lp_core_mailbox_intr_handler
j ulp_lp_core_lp_timer_intr_handler
j ulp_lp_core_lp_wdt_intr_handler
j ulp_lp_core_lp_rtc_intr_handler
j _panic_handler
j _panic_handler
.option pop
.size _vector_table, .-_vector_table
/* _panic_handler: handle all exception */
.section .text.handlers,"ax"
.global _panic_handler
.type _panic_handler, @function
_panic_handler:
call ulp_lp_core_panic_handler
_end:
j _end /* loop forever */

View File

@@ -9,6 +9,11 @@
/* The reset vector, jumps to startup code */
reset_vector:
/* _vector_table: Only 256-byte aligned addresses are allowed */
la t0, _vector_table
csrw mtvec, t0
j __start
__start:

View File

@@ -1,24 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
.section .init.vector,"ax"
/* This is the vector table. It is currently empty, but will be populated
* with exception and interrupt handlers when this is supported
*/
.align 0x4, 0xff
.global _vector_table
.type _vector_table, @function
_vector_table:
.option push
.option norvc
.rept 32
nop
.endr
.option pop
.size _vector_table, .-_vector_table

View File

@@ -34,6 +34,7 @@ set(lp_core_exp_dep_srcs ${app_sources})
ulp_embed_binary(lp_core_test_app "${lp_core_sources}" "${lp_core_exp_dep_srcs}")
ulp_embed_binary(lp_core_test_app_counter "${lp_core_sources_counter}" "${lp_core_exp_dep_srcs}")
ulp_embed_binary(lp_core_test_app_isr "lp_core/test_main_isr.c" "${lp_core_exp_dep_srcs}")
if(CONFIG_SOC_LP_TIMER_SUPPORTED)
ulp_embed_binary(lp_core_test_app_set_timer_wakeup "${lp_core_sources_set_timer_wakeup}" "${lp_core_exp_dep_srcs}")

View File

@@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "ulp_lp_core_utils.h"
#include "ulp_lp_core_interrupts.h"
#include "ulp_lp_core_gpio.h"
#include "hal/pmu_ll.h"
volatile uint32_t io_isr_counter = 0;
volatile uint32_t pmu_isr_counter = 0;
volatile bool isr_test_started;
void LP_CORE_ISR_ATTR ulp_lp_core_lp_io_intr_handler(void)
{
ulp_lp_core_gpio_clear_intr_status();
io_isr_counter++;
}
void LP_CORE_ISR_ATTR ulp_lp_core_lp_pmu_intr_handler(void)
{
ulp_lp_core_sw_intr_clear();
pmu_isr_counter++;
}
int main(void)
{
ulp_lp_core_sw_intr_enable(true);
ulp_lp_core_intr_enable();
isr_test_started = true;
while (1) {
// Busy wait for the interrupts to occur
}
return 0;
}

View File

@@ -11,6 +11,7 @@
#include "esp_rom_caps.h"
#include "lp_core_test_app.h"
#include "lp_core_test_app_counter.h"
#include "lp_core_test_app_isr.h"
#if SOC_LP_TIMER_SUPPORTED
#include "lp_core_test_app_set_timer_wakeup.h"
@@ -26,6 +27,10 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "hal/lp_core_ll.h"
#include "hal/rtc_io_ll.h"
#include "driver/rtc_io.h"
extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_test_app_bin_start");
extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_test_app_bin_end");
@@ -38,6 +43,9 @@ extern const uint8_t lp_core_main_set_timer_wakeup_bin_end[] asm("_binary_lp_c
extern const uint8_t lp_core_main_gpio_bin_start[] asm("_binary_lp_core_test_app_gpio_bin_start");
extern const uint8_t lp_core_main_gpio_bin_end[] asm("_binary_lp_core_test_app_gpio_bin_end");
extern const uint8_t lp_core_main_isr_bin_start[] asm("_binary_lp_core_test_app_isr_bin_start");
extern const uint8_t lp_core_main_isr_bin_end[] asm("_binary_lp_core_test_app_isr_bin_end");
static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end)
{
TEST_ASSERT(ulp_lp_core_load_binary(firmware_start,
@@ -325,3 +333,49 @@ TEST_CASE("LP core gpio tests", "[ulp]")
}
#endif //SOC_LP_TIMER_SUPPORTED
#define ISR_TEST_ITERATIONS 100
#define IO_TEST_PIN 0
#include "lp_core_uart.h"
TEST_CASE("LP core ISR tests", "[ulp]")
{
lp_core_uart_cfg_t ucfg = LP_CORE_UART_DEFAULT_CONFIG();
ESP_ERROR_CHECK(lp_core_uart_init(&ucfg));
/* Load ULP firmware and start the coprocessor */
ulp_lp_core_cfg_t cfg = {
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU,
};
load_and_start_lp_core_firmware(&cfg, lp_core_main_isr_bin_start, lp_core_main_isr_bin_end);
while (!ulp_isr_test_started) {
}
for (int i = 0; i < ISR_TEST_ITERATIONS; i++) {
lp_core_ll_hp_wake_lp();
vTaskDelay(pdMS_TO_TICKS(10));
}
printf("ULP PMU ISR triggered %"PRIu32" times\n", ulp_pmu_isr_counter);
TEST_ASSERT_EQUAL(ISR_TEST_ITERATIONS, ulp_pmu_isr_counter);
/* Test LP IO interrupt */
rtc_gpio_init(IO_TEST_PIN);
rtc_gpio_set_direction(IO_TEST_PIN, RTC_GPIO_MODE_INPUT_ONLY);
TEST_ASSERT_EQUAL(0, ulp_io_isr_counter);
for (int i = 0; i < ISR_TEST_ITERATIONS; i++) {
#if CONFIG_IDF_TARGET_ESP32C6
LP_IO.status_w1ts.val = 0x00000001; // Set GPIO 0 intr status to high
#else
LP_GPIO.status_w1ts.val = 0x00000001; // Set GPIO 0 intr status to high
#endif
vTaskDelay(pdMS_TO_TICKS(10));
}
printf("ULP LP IO ISR triggered %"PRIu32" times\n", ulp_io_isr_counter);
TEST_ASSERT_EQUAL(ISR_TEST_ITERATIONS, ulp_io_isr_counter);
}