diff options
author | Min Xu <min.xu@min-info.net> | 2014-10-25 21:30:23 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2014-11-11 22:30:55 +0100 |
commit | 8701086cacca088ae34580908cec45f77042b94e (patch) | |
tree | 0755b6b6439acf52ed66ef9b8d1c093247137a64 | |
parent | 6bafd0cfb40c2d201f8723a3678dd4f04b380842 (diff) |
Retrieve + print previous PC from stack to debug wdog/spurious IRQ
Retrive previous PC from the stack before entering specific interrupt
handler routines. Allow user to trace where interrupt occured: e.g.
WatchDog and Spurious interrupt
Prior to this change, spurious interrupt would occur so much (observed
via gdb/remote debug) so it appears that the board stalled. Once a
custom spurious interrupt installed, the code continues after the
interrupt instead of re-entering the interrupt.
-rw-r--r-- | firmware/src/os/system_irq.c | 18 | ||||
-rw-r--r-- | firmware/src/simtrace/main_simtrace.c | 16 |
2 files changed, 31 insertions, 3 deletions
diff --git a/firmware/src/os/system_irq.c b/firmware/src/os/system_irq.c index dc787eb..4c1da31 100644 --- a/firmware/src/os/system_irq.c +++ b/firmware/src/os/system_irq.c @@ -25,15 +25,15 @@ #include <os/system_irq.h> #include <os/dbgu.h> +#include <string.h> #include "../openpcd.h" static sysirq_hdlr *sysirq_hdlrs[AT91SAM7_SYSIRQ_COUNT]; -static void sys_irq(void) +void sys_irq(u_int32_t previous_pc) { u_int32_t sr; - DEBUGP("sys_irq "); /* Somehow Atmel decided to do really stupid interrupt sharing * for commonly-used interrupts such as the timer irq */ @@ -139,6 +139,10 @@ static void sys_irq(void) if (*AT91C_WDTC_WDMR & AT91C_WDTC_WDFIEN) { sr = *AT91C_WDTC_WDSR; if (sr) { + char dbg_buf[100]; + sprintf(dbg_buf, "sys_irq [Old PC = %08X]\n\r", previous_pc); + AT91F_DBGU_Frame(dbg_buf); + DEBUGP("WDT("); if (sysirq_hdlrs[AT91SAM7_SYSIRQ_WDT]) { DEBUGP("handler "); @@ -154,6 +158,14 @@ static void sys_irq(void) DEBUGPCR("END"); } +static void sysirq_entry(void) +{ + /* DON'T MODIFY THIS SECTION AND Cstartup.S/IRQ_Handler_Entry */ + register unsigned *previous_pc asm("r0"); + asm("ADD R1, SP, #16; LDR R0, [R1]"); + sys_irq(previous_pc); +} + void sysirq_register(enum sysirqs irq, sysirq_hdlr *hdlr) { if (irq >= AT91SAM7_SYSIRQ_COUNT) @@ -167,6 +179,6 @@ void sysirq_init(void) AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS, OPENPCD_IRQ_PRIO_SYS, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, - &sys_irq); + &sysirq_entry); AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS); } diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index b3f2665..b84525f 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -136,8 +136,24 @@ static int simtrace_usb_in(struct req_ctx *rctx) } } +void custom_spurious_handler(unsigned previous_pc) +{ + char dbg_buf[100]; + sprintf(dbg_buf, "SPURRIOUS IRQ [Old PC = %08X]\n\r", previous_pc); + AT91F_DBGU_Frame(dbg_buf); +} + +void custom_spurious_entry(void) +{ + register unsigned *previous_pc asm("r0"); + asm("ADD R1, SP, #16; LDR R0, [R1]"); + custom_spurious_handler(previous_pc); +} + void _init_func(void) { + AT91C_BASE_AIC->AIC_SPU = (int)custom_spurious_entry; + /* low-level hardware initialization */ pio_irq_init(); iso_uart_init(); |