summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMin Xu <min.xu@min-info.net>2014-10-25 21:30:23 +0200
committerHarald Welte <laforge@gnumonks.org>2014-11-11 22:30:55 +0100
commit8701086cacca088ae34580908cec45f77042b94e (patch)
tree0755b6b6439acf52ed66ef9b8d1c093247137a64
parent6bafd0cfb40c2d201f8723a3678dd4f04b380842 (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.c18
-rw-r--r--firmware/src/simtrace/main_simtrace.c16
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();
personal git repositories of Harald Welte. Your mileage may vary