Skip to content

Commit

Permalink
applications: sdp: mspi: add trap handler for SDP app
Browse files Browse the repository at this point in the history
Implementation of trap handler. Signals status to host
and sends dump of most important registers at the time of error.

Signed-off-by: Jakub Zymelka <[email protected]>
  • Loading branch information
jaz1-nordic authored and carlescufi committed Mar 4, 2025
1 parent e86a306 commit a5db2e6
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 10 deletions.
10 changes: 7 additions & 3 deletions applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@
#size-cells = <1>;

sram_tx: memory@2003c000 {
reg = <0x2003c000 0x0800>;
reg = <0x2003c000 0x07f0>;
};

sram_rx: memory@2003c800 {
reg = <0x2003c800 0x0800>;
sram_rx: memory@2003c7f0 {
reg = <0x2003c7f0 0x07f0>;
};

cpuflpr_error_code: memory@2003cfe0 {
reg = <0x2003cfe0 0x0020>; /* 32bytes */
};
};
};
Expand Down
100 changes: 97 additions & 3 deletions applications/sdp/mspi/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ static atomic_t ipc_atomic_sem = ATOMIC_INIT(0);
#if defined(CONFIG_SDP_MSPI_FAULT_TIMER)
static NRF_TIMER_Type *fault_timer;
#endif
static volatile uint32_t *cpuflpr_error_ctx_ptr =
(uint32_t *)DT_REG_ADDR(DT_NODELABEL(cpuflpr_error_code));

static void adjust_tail(volatile hrt_xfer_data_t *xfer_data, uint16_t frame_width,
uint32_t data_length)
Expand Down Expand Up @@ -368,15 +370,14 @@ static void ep_recv(const void *data, size_t len, void *priv)

(void)priv;
(void)len;
nrfe_mspi_flpr_response_msg_t response;
uint8_t opcode = *(uint8_t *)data;
uint32_t num_bytes = 0;

#if defined(CONFIG_SDP_MSPI_FAULT_TIMER)
if (fault_timer != NULL) {
nrf_timer_task_trigger(fault_timer, NRF_TIMER_TASK_START);
}
#endif
response.opcode = opcode;

switch (opcode) {
#if defined(CONFIG_SDP_MSPI_FAULT_TIMER)
Expand Down Expand Up @@ -513,10 +514,103 @@ __attribute__((interrupt)) void hrt_handler_write(void)
hrt_write((hrt_xfer_t *)&xfer_params);
}

/**
* @brief Trap handler for SDP application.
*
* @details
* This function is called on unhandled CPU exceptions. It's a good place to
* handle critical errors and notify the core that the SDP application has
* crashed.
*
* @param mcause - cause of the exception (from mcause register)
* @param mepc - address of the instruction that caused the exception (from mepc register)
* @param mtval - additional value (e.g. bad address)
* @param context - pointer to the saved context (only some registers are saved - ra, t0, t1, t2)
*/
void trap_handler(uint32_t mcause, uint32_t mepc, uint32_t mtval, void *context)
{
const uint8_t fault_opcode = NRFE_MSPI_SDP_APP_HARD_FAULT;

/* It can be distinguish whether the exception was caused by an interrupt or an error:
* On RV32, bit 31 of the mcause register indicates whether the event is an interrupt.
*/
if (mcause & 0x80000000) {
/* Interrupt – can be handled or ignored */
} else {
/* Exception – critical error */
}

cpuflpr_error_ctx_ptr[0] = mcause;
cpuflpr_error_ctx_ptr[1] = mepc;
cpuflpr_error_ctx_ptr[2] = mtval;
cpuflpr_error_ctx_ptr[3] = (uint32_t)context;

ipc_service_send(&ep, &fault_opcode, sizeof(fault_opcode));

while (1) {
/* Loop forever */
}
}

/* The trap_entry function is the entry point for exception handling.
* The naked attribute prevents the compiler from generating an automatic prologue/epilogue.
*/
__attribute__((naked)) void trap_entry(void)
{
__asm__ volatile(
/* Reserve space on the stack:
* 16 bytes for 4 registers context (ra, t0, t1, t2).
*/
"addi sp, sp, -16\n"
"sw ra, 12(sp)\n"
"sw t0, 8(sp)\n"
"sw t1, 4(sp)\n"
"sw t2, 0(sp)\n"

/* Read CSR: mcause, mepc, mtval */
"csrr t0, mcause\n" /* t0 = mcause */
"csrr t1, mepc\n" /* t1 = mepc */
"csrr t2, mtval\n" /* t2 = mtval */

/* Prepare arguments for trap_handler function:
* a0 = mcause (t0), a1 = mepc (t1), a2 = mtval (t2), a3 = sp (pointer on context).
*/
"mv a0, t0\n"
"mv a1, t1\n"
"mv a2, t2\n"
"mv a3, sp\n"

"call trap_handler\n"

/* Restore registers values */
"lw ra, 12(sp)\n"
"lw t0, 8(sp)\n"
"lw t1, 4(sp)\n"
"lw t2, 0(sp)\n"
"addi sp, sp, 16\n"

"mret\n");
}

void init_trap_handler(void)
{
/* Write the address of the trap_entry function into the mtvec CSR.
* Note: On RV32, the address must be aligned to 4 bytes.
*/
uintptr_t trap_entry_addr = (uintptr_t)&trap_entry;

__asm__ volatile("csrw mtvec, %0\n"
: /* no outs */
: "r"(trap_entry_addr));
}

int main(void)
{
int ret = backend_init();
int ret = 0;

init_trap_handler();

ret = backend_init();
if (ret < 0) {
return 0;
}
Expand Down
17 changes: 17 additions & 0 deletions drivers/mspi/mspi_nrfe.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ SDP_MSPI_PINCTRL_DT_DEFINE(MSPI_NRFE_NODE);
static struct ipc_ept ep;
static size_t ipc_received;
static uint8_t *ipc_receive_buffer;
static volatile uint32_t *cpuflpr_error_ctx_ptr =
(uint32_t *)DT_REG_ADDR(DT_NODELABEL(cpuflpr_error_code));

#if defined(CONFIG_MULTITHREADING)
static K_SEM_DEFINE(ipc_sem, 0, 1);
Expand Down Expand Up @@ -168,6 +170,21 @@ static void ep_recv(const void *data, size_t len, void *priv)
#endif
break;
}
case NRFE_MSPI_SDP_APP_HARD_FAULT: {

volatile uint32_t cause = cpuflpr_error_ctx_ptr[0];
volatile uint32_t pc = cpuflpr_error_ctx_ptr[1];
volatile uint32_t bad_addr = cpuflpr_error_ctx_ptr[2];
volatile uint32_t *ctx = (volatile uint32_t *)cpuflpr_error_ctx_ptr[3];

LOG_ERR(">>> SDP APP FATAL ERROR");
LOG_ERR("Faulting instruction address (mepc): 0x%08x", pc);
LOG_ERR("mcause: 0x%08x, mtval: 0x%08x, ra: 0x%08x", cause, bad_addr, ctx[0]);
LOG_ERR(" t0: 0x%08x, t1: 0x%08x, t2: 0x%08x", ctx[1], ctx[2], ctx[3]);

LOG_ERR("SDP application halted...");
break;
}
default: {
LOG_ERR("Invalid response opcode: %d", response->opcode);
break;
Expand Down
1 change: 1 addition & 0 deletions include/drivers/mspi/nrfe_mspi.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ typedef enum {
NRFE_MSPI_CONFIG_XFER, /* nrfe_mspi_xfer_config_msg_t */
NRFE_MSPI_TX, /* nrfe_mspi_xfer_packet_msg_t + data buffer at the end */
NRFE_MSPI_TXRX,
NRFE_MSPI_SDP_APP_HARD_FAULT,
NRFE_MSPI_WRONG_OPCODE,
NRFE_MSPI_ALL_OPCODES = NRFE_MSPI_WRONG_OPCODE,
} nrfe_mspi_opcode_t;
Expand Down
11 changes: 7 additions & 4 deletions snippets/sdp/mspi/soc/nrf54l15_cpuapp.overlay
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
};

sram_rx: memory@2003c000 {
reg = <0x2003c000 0x0800>;
reg = <0x2003c000 0x07f0>;
};

sram_tx: memory@2003c800 {
reg = <0x2003c800 0x0800>;
sram_tx: memory@2003c7f0 {
reg = <0x2003c7f0 0x07f0>;
};
};

cpuflpr_error_code: memory@2003cfe0 {
reg = <0x2003cfe0 0x0020>; /* 32bytes */
};
};

cpuflpr_sram_code_data: memory@2003d000 {
compatible = "mmio-sram";
Expand Down

0 comments on commit a5db2e6

Please sign in to comment.