mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
feat(ulp): add lp core panic handler
This commit is contained in:
@@ -1466,3 +1466,7 @@ config SOC_PHY_COMBO_MODULE
|
||||
config SOC_CAPS_NO_RESET_BY_ANA_BOD
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR
|
||||
bool
|
||||
default y
|
||||
|
||||
@@ -583,3 +583,7 @@
|
||||
|
||||
/*------------------------------------- No Reset CAPS -------------------------------------*/
|
||||
#define SOC_CAPS_NO_RESET_BY_ANA_BOD (1)
|
||||
|
||||
|
||||
/*------------------------------------- ULP CAPS -------------------------------------*/
|
||||
#define SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR (1) /*!< LP Core interrupts all map to a single entry in vector table */
|
||||
|
||||
@@ -92,4 +92,20 @@ menu "Ultra Low Power (ULP) Co-processor"
|
||||
Note: For LP ROM prints to work properly, make sure that the LP core boots
|
||||
from the LP ROM.
|
||||
|
||||
menu "ULP Debugging Options"
|
||||
config ULP_PANIC_OUTPUT_ENABLE
|
||||
depends on ULP_COPROC_TYPE_LP_CORE && SOC_ULP_LP_UART_SUPPORTED
|
||||
bool
|
||||
prompt "Enable panic handler which outputs over LP UART"
|
||||
default "y" if IDF_TARGET_ESP32P4
|
||||
help
|
||||
Set this option to enable panic handler functionality. If this option is
|
||||
enabled then the LP Core will output a panic dump over LP UART,
|
||||
similar to what the main core does. Output depends on LP UART already being
|
||||
initialized and configured.
|
||||
Disabling this option will reduce the LP core binary size by not
|
||||
linking in panic handler functionality.
|
||||
|
||||
endmenu
|
||||
|
||||
endmenu # Ultra Low Power (ULP) Co-processor
|
||||
|
||||
@@ -101,7 +101,8 @@ 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/port/${IDF_TARGET}/vector.S"
|
||||
"${IDF_PATH}/components/ulp/lp_core/lp_core/vector.S"
|
||||
"${IDF_PATH}/components/ulp/lp_core/lp_core/port/${IDF_TARGET}/vector_table.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 +112,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_panic.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")
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ set(CMAKE_C_COMPILER "riscv32-esp-elf-gcc")
|
||||
set(CMAKE_CXX_COMPILER "riscv32-esp-elf-g++")
|
||||
set(CMAKE_ASM_COMPILER "riscv32-esp-elf-gcc")
|
||||
|
||||
set(CMAKE_C_FLAGS "-Os -march=rv32imac_zicsr_zifencei -mdiv -fdata-sections -ffunction-sections"
|
||||
set(CMAKE_C_FLAGS "-Os -ggdb -march=rv32imac_zicsr_zifencei -mdiv -fdata-sections -ffunction-sections"
|
||||
CACHE STRING "C Compiler Base Flags")
|
||||
set(CMAKE_CXX_FLAGS "-Os -march=rv32imac_zicsr_zifencei -mdiv -fdata-sections -ffunction-sections"
|
||||
set(CMAKE_CXX_FLAGS "-Os -ggdb -march=rv32imac_zicsr_zifencei -mdiv -fdata-sections -ffunction-sections"
|
||||
CACHE STRING "C++ Compiler Base Flags")
|
||||
set(CMAKE_ASM_FLAGS "-march=rv32imac_zicsr_zifencei -x assembler-with-cpp"
|
||||
set(CMAKE_ASM_FLAGS "-Os -ggdb -march=rv32imac_zicsr_zifencei -x assembler-with-cpp"
|
||||
CACHE STRING "Assembler Base Flags")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-march=rv32imac_zicsr_zifencei --specs=nano.specs --specs=nosys.specs"
|
||||
CACHE STRING "Linker Base Flags")
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "hal/lp_core_ll.h"
|
||||
#include "riscv/rv_utils.h"
|
||||
#include "riscv/rvruntime-frames.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C6
|
||||
/* Enable interrupt 30, which all external interrupts are routed to*/
|
||||
@@ -36,6 +37,11 @@ void ulp_lp_core_intr_disable(void)
|
||||
RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
|
||||
}
|
||||
|
||||
void __attribute__((weak)) ulp_lp_core_panic_handler(RvExcFrame *frame, int exccause)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
static void ulp_lp_core_default_intr_handler(void)
|
||||
{
|
||||
abort();
|
||||
@@ -60,11 +66,6 @@ void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_cor
|
||||
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[] = {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "ulp_lp_core_print.h"
|
||||
#include "riscv/rvruntime-frames.h"
|
||||
|
||||
#if CONFIG_ULP_PANIC_OUTPUT_ENABLE
|
||||
|
||||
static void dump_stack(RvExcFrame *frame, int exccause)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t sp = frame->sp;
|
||||
lp_core_printf("\n\nStack memory:\n");
|
||||
const int per_line = 8;
|
||||
for (i = 0; i < 1024; i += per_line * sizeof(uint32_t)) {
|
||||
uint32_t *spp = (uint32_t *)(sp + i);
|
||||
lp_core_printf("%08x: ", sp + i);
|
||||
for (int y = 0; y < per_line; y++) {
|
||||
lp_core_printf("0x%08x%c", spp[y], y == per_line - 1 ? '\n' : ' ');
|
||||
}
|
||||
}
|
||||
lp_core_printf("\n");
|
||||
}
|
||||
|
||||
static const char *desc[] = {
|
||||
"MEPC ", "RA ", "SP ", "GP ", "TP ", "T0 ", "T1 ", "T2 ",
|
||||
"S0/FP ", "S1 ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ",
|
||||
"A6 ", "A7 ", "S2 ", "S3 ", "S4 ", "S5 ", "S6 ", "S7 ",
|
||||
"S8 ", "S9 ", "S10 ", "S11 ", "T3 ", "T4 ", "T5 ", "T6 ",
|
||||
"MSTATUS ", "MTVEC ", "MCAUSE ", "MTVAL ", "MHARTID "
|
||||
};
|
||||
|
||||
static const char *reason[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
"Illegal instruction",
|
||||
"Breakpoint",
|
||||
"Load address misaligned",
|
||||
"Load access fault",
|
||||
"Store address misaligned",
|
||||
"Store access fault",
|
||||
};
|
||||
|
||||
void ulp_lp_core_panic_handler(RvExcFrame *frame, int exccause)
|
||||
{
|
||||
#define DIM(arr) (sizeof(arr)/sizeof(*arr))
|
||||
|
||||
const char *exccause_str = "Unhandled interrupt/Unknown cause";
|
||||
|
||||
if (exccause < DIM(reason) && reason[exccause] != NULL) {
|
||||
exccause_str = reason[exccause];
|
||||
}
|
||||
|
||||
lp_core_printf("Guru Meditation Error: LP Core panic'ed (%s)\n", exccause_str);
|
||||
lp_core_printf("Core 0 register dump:\n");
|
||||
|
||||
uint32_t* frame_ints = (uint32_t*) frame;
|
||||
for (int x = 0; x < DIM(desc); x++) {
|
||||
if (desc[x][0] != 0) {
|
||||
const int not_last = (x + 1) % 4;
|
||||
lp_core_printf("%-8s: 0x%08x %c", desc[x], frame_ints[x], not_last ? ' ' : '\n');
|
||||
}
|
||||
}
|
||||
|
||||
dump_stack(frame, exccause);
|
||||
|
||||
/* idf-monitor uses this string to mark the end of a panic dump */
|
||||
lp_core_printf("ELF file SHA256: No SHA256 Embedded\n");
|
||||
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
||||
#endif //#if CONFIG_ULP_PANIC_OUTPUT_ENABLE
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 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
|
||||
|
||||
.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
|
||||
-10
@@ -47,13 +47,3 @@ _vector_table:
|
||||
|
||||
.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 */
|
||||
+35
-27
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "riscv/rvruntime-frames.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
.equ SAVE_REGS, 32
|
||||
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
|
||||
@@ -92,47 +93,54 @@
|
||||
.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 */
|
||||
save_general_regs RV_STK_FRMSZ
|
||||
save_mepc
|
||||
|
||||
addi t0, sp, RV_STK_FRMSZ /* restore sp with the value when trap happened */
|
||||
|
||||
/* Save CSRs */
|
||||
sw t0, RV_STK_SP(sp)
|
||||
csrr t0, mstatus
|
||||
sw t0, RV_STK_MSTATUS(sp)
|
||||
csrr t0, mcause
|
||||
sw t0, RV_STK_MCAUSE(sp)
|
||||
csrr t0, mtvec
|
||||
sw t0, RV_STK_MTVEC(sp)
|
||||
csrr t0, mhartid
|
||||
sw t0, RV_STK_MHARTID(sp)
|
||||
csrr t0, mtval
|
||||
sw t0, RV_STK_MTVAL(sp)
|
||||
|
||||
csrr a1, mcause /* exception cause */
|
||||
|
||||
mv a0, sp /* RvExcFrame *regs */
|
||||
call ulp_lp_core_panic_handler
|
||||
_end:
|
||||
j _end /* loop forever */
|
||||
|
||||
|
||||
#if SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR
|
||||
|
||||
/* interrupt_handler: handle all interrupt */
|
||||
.section .text.handlers,"ax"
|
||||
.global _interrupt_handler
|
||||
.type _interrupt_handler, @function
|
||||
.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
|
||||
call ulp_lp_core_intr_handler
|
||||
|
||||
/* restore registers & mepc from stack */
|
||||
/* restore registers & mepc from stack */
|
||||
restore_mepc
|
||||
restore_general_regs
|
||||
/* exit, this will also re-enable the interrupts */
|
||||
mret
|
||||
mret
|
||||
|
||||
#endif // SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR
|
||||
@@ -20,12 +20,15 @@ int main(void)
|
||||
ulp_lp_core_gpio_output_enable(LP_IO_NUM_0);
|
||||
|
||||
ulp_lp_core_gpio_set_level(LP_IO_NUM_0, 0);
|
||||
ulp_lp_core_delay_us(100);
|
||||
gpio_test_succeeded = (ulp_lp_core_gpio_get_level(LP_IO_NUM_0) == 0);
|
||||
|
||||
ulp_lp_core_gpio_set_level(LP_IO_NUM_0, 1);
|
||||
ulp_lp_core_delay_us(100);
|
||||
gpio_test_succeeded &= (ulp_lp_core_gpio_get_level(LP_IO_NUM_0) == 1);
|
||||
|
||||
ulp_lp_core_gpio_set_level(LP_IO_NUM_0, 0);
|
||||
ulp_lp_core_delay_us(100);
|
||||
gpio_test_succeeded &= (ulp_lp_core_gpio_get_level(LP_IO_NUM_0) == 0);
|
||||
|
||||
gpio_test_finished = 1;
|
||||
|
||||
@@ -2,4 +2,5 @@ CONFIG_ESP_TASK_WDT_INIT=n
|
||||
|
||||
CONFIG_ULP_COPROC_ENABLED=y
|
||||
CONFIG_ULP_COPROC_TYPE_LP_CORE=y
|
||||
CONFIG_ULP_COPROC_RESERVE_MEM=4096
|
||||
CONFIG_ULP_COPROC_RESERVE_MEM=12000
|
||||
CONFIG_ULP_PANIC_OUTPUT_ENABLE=y
|
||||
|
||||
Reference in New Issue
Block a user