From 7fcc62940d35ae31bdf5e5ebdd5ca55c8f4429c2 Mon Sep 17 00:00:00 2001 From: Min Xu Date: Sat, 25 Oct 2014 20:13:23 +0200 Subject: simtrace: Add heartbeat message to debug console --- firmware/src/simtrace/iso7816_uart.c | 10 ++++++++++ firmware/src/simtrace/iso7816_uart.h | 1 + firmware/src/simtrace/main_simtrace.c | 9 +++++++++ 3 files changed, 20 insertions(+) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/iso7816_uart.c b/firmware/src/simtrace/iso7816_uart.c index 52522c0..611ccfb 100644 --- a/firmware/src/simtrace/iso7816_uart.c +++ b/firmware/src/simtrace/iso7816_uart.c @@ -125,6 +125,14 @@ static const u_int8_t di_table[] = { 12, 20, 2, 4, 8, 16, 32, 64, }; +void iso_uart_report_overrun(void) +{ + static unsigned lastOverrun = 0; + if (isoh.stats.overrun != lastOverrun) { + DEBUGPCR("UART overrun: %u", lastOverrun = isoh.stats.overrun); + } +} + void iso_uart_stats_dump(void) { DEBUGPCRF("no_rctx: %u, rctx_sent: %u, rst: %u, pps: %u, bytes: %u, " @@ -675,6 +683,8 @@ void iso_uart_init(void) { DEBUGPCR("USART Initializing"); + memset(&isoh, 0, sizeof(isoh)); + refill_rctx(&isoh); /* make sure we get clock from the power management controller */ diff --git a/firmware/src/simtrace/iso7816_uart.h b/firmware/src/simtrace/iso7816_uart.h index beb0b23..070d92a 100644 --- a/firmware/src/simtrace/iso7816_uart.h +++ b/firmware/src/simtrace/iso7816_uart.h @@ -6,3 +6,4 @@ void iso_uart_rst(unsigned int state); void iso_uart_rx_mode(void); void iso_uart_clk_master(unsigned int master); void iso_uart_init(void); +void iso_uart_report_overrun(void); diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index 6f82d96..ca4e646 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -218,6 +218,8 @@ int _main_dbgu(char key) void _main_func(void) { + static unsigned loopLow = 0, loopHigh = 0; + /* first we try to get rid of pending to-be-sent stuff */ usb_out_process(); @@ -225,4 +227,11 @@ void _main_func(void) usb_in_process(); udp_unthrottle(); + + if ((loopLow & 0xFFFF) == 0) { + DEBUGPCR("Heart beat %08X", loopHigh++); + } + loopLow++; + + iso_uart_report_overrun(); } -- cgit v1.2.3 From 9bd1b003a63d61e91db3827c2b66290abc1adf13 Mon Sep 17 00:00:00 2001 From: Min Xu Date: Sat, 25 Oct 2014 20:54:09 +0200 Subject: iso7816_uart.h: add missing #ifdef/endif to avoid multiple inclusion --- firmware/src/simtrace/iso7816_uart.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/iso7816_uart.h b/firmware/src/simtrace/iso7816_uart.h index 070d92a..1a2b202 100644 --- a/firmware/src/simtrace/iso7816_uart.h +++ b/firmware/src/simtrace/iso7816_uart.h @@ -1,3 +1,5 @@ +#ifndef SIMTRACE_ISO7816_UART_H +#define SIMTRACE_ISO7816_UART_H struct simtrace_stats *iso_uart_stats_get(void); void iso_uart_stats_dump(void); @@ -7,3 +9,5 @@ void iso_uart_rx_mode(void); void iso_uart_clk_master(unsigned int master); void iso_uart_init(void); void iso_uart_report_overrun(void); + +#endif -- cgit v1.2.3 From ab325fc295a23d04f27cc7300b12d2564e4d83e6 Mon Sep 17 00:00:00 2001 From: Min Xu Date: Sat, 25 Oct 2014 20:55:01 +0200 Subject: Ensure to transmit current req_ctx on RESET/VCC events When any of the following events occur: * VCC_PHONE off * nRST * RST we tranmsit the current req_ctx, if there is data pending. This ensures that for any successive data, the ATR flag in the next req_ctx containing the data, not in the previous req_ctx. It also ensures that the ATR is aligned at 0 offset in the new req_ctx, which is an assumption the host software makes but the previous code didn't ensure. Furthermore, we introduce a periodic flushing of any pending but incomplete req_ctx. --- firmware/src/simtrace/iso7816_uart.c | 21 +++++++++++++++++++++ firmware/src/simtrace/iso7816_uart.h | 2 ++ firmware/src/simtrace/main_simtrace.c | 3 +++ firmware/src/simtrace/sim_switch.c | 7 +++++-- 4 files changed, 31 insertions(+), 2 deletions(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/iso7816_uart.c b/firmware/src/simtrace/iso7816_uart.c index 611ccfb..780340f 100644 --- a/firmware/src/simtrace/iso7816_uart.c +++ b/firmware/src/simtrace/iso7816_uart.c @@ -575,6 +575,23 @@ void iso7816_wtime_expired(void) set_state(&isoh, ISO7816_S_WAIT_APDU); } +void iso_uart_flush(void) +{ + send_rctx(&isoh); +} + +void iso_uart_idleflush(void) +{ + static struct req_ctx *last_req = NULL; + static u_int16_t last_len = 0; + + if (last_req == isoh.rctx || last_len == isoh.rctx->tot_len) { + send_rctx(&isoh); + } + last_req = isoh.rctx; + last_len = isoh.rctx->tot_len; +} + static __ramfunc void usart_irq(void) { u_int32_t csr = usart->US_CSR; @@ -618,9 +635,13 @@ static __ramfunc void usart_irq(void) static void reset_pin_irq(u_int32_t pio) { if (!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, pio)) { + /* make sure to flush pending req_ctx */ + iso_uart_flush(); DEBUGPCR("nRST"); set_state(&isoh, ISO7816_S_RESET); } else { + /* make sure to flush pending req_ctx */ + iso_uart_flush(); DEBUGPCR("RST"); set_state(&isoh, ISO7816_S_WAIT_ATR); isoh.stats.rst++; diff --git a/firmware/src/simtrace/iso7816_uart.h b/firmware/src/simtrace/iso7816_uart.h index 1a2b202..c5790c8 100644 --- a/firmware/src/simtrace/iso7816_uart.h +++ b/firmware/src/simtrace/iso7816_uart.h @@ -9,5 +9,7 @@ void iso_uart_rx_mode(void); void iso_uart_clk_master(unsigned int master); void iso_uart_init(void); void iso_uart_report_overrun(void); +void iso_uart_flush(void); +void iso_uart_idleflush(void); #endif diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index ca4e646..6bad290 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -231,6 +231,9 @@ void _main_func(void) if ((loopLow & 0xFFFF) == 0) { DEBUGPCR("Heart beat %08X", loopHigh++); } + if ((loopLow & 0x3FF) == 0) { + iso_uart_idleflush(); + } loopLow++; iso_uart_report_overrun(); diff --git a/firmware/src/simtrace/sim_switch.c b/firmware/src/simtrace/sim_switch.c index faf48f0..90067ac 100644 --- a/firmware/src/simtrace/sim_switch.c +++ b/firmware/src/simtrace/sim_switch.c @@ -59,9 +59,12 @@ static void sw_sim_irq(u_int32_t pio) static void vcc_phone_irq(u_int32_t pio) { - if (!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_PHONE)) + if (!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_PHONE)) { DEBUGPCR("VCC_PHONE off"); - else + /* flush any pending req_ctx to make sure the next ATR + * will be aligned to position 0 */ + iso_uart_flush(); + } else DEBUGPCR("VCC_PHONE on"); } -- cgit v1.2.3 From 7e3c9959e1e140753738be9b6d4142f6c2068e3d Mon Sep 17 00:00:00 2001 From: Min Xu Date: Sat, 25 Oct 2014 21:18:03 +0200 Subject: iso_uart: Print more errors, not just overruns --- firmware/src/simtrace/iso7816_uart.c | 10 ++++++++-- firmware/src/simtrace/iso7816_uart.h | 2 +- firmware/src/simtrace/main_simtrace.c | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/iso7816_uart.c b/firmware/src/simtrace/iso7816_uart.c index 780340f..e37deba 100644 --- a/firmware/src/simtrace/iso7816_uart.c +++ b/firmware/src/simtrace/iso7816_uart.c @@ -125,12 +125,18 @@ static const u_int8_t di_table[] = { 12, 20, 2, 4, 8, 16, 32, 64, }; -void iso_uart_report_overrun(void) +void iso_uart_report_errors(void) { - static unsigned lastOverrun = 0; + static unsigned lastOverrun = 0, lastParity = 0, lastFrame = 0; if (isoh.stats.overrun != lastOverrun) { DEBUGPCR("UART overrun: %u", lastOverrun = isoh.stats.overrun); } + if (isoh.stats.frame_err != lastFrame) { + DEBUGPCR("UART frame error: %u", lastFrame = isoh.stats.frame_err); + } + if (isoh.stats.parity_err != lastParity) { + DEBUGPCR("UART parity error: %u", lastParity = isoh.stats.parity_err); + } } void iso_uart_stats_dump(void) diff --git a/firmware/src/simtrace/iso7816_uart.h b/firmware/src/simtrace/iso7816_uart.h index c5790c8..969e6f9 100644 --- a/firmware/src/simtrace/iso7816_uart.h +++ b/firmware/src/simtrace/iso7816_uart.h @@ -2,13 +2,13 @@ #define SIMTRACE_ISO7816_UART_H struct simtrace_stats *iso_uart_stats_get(void); +void iso_uart_report_errors(void); void iso_uart_stats_dump(void); void iso_uart_dump(void); void iso_uart_rst(unsigned int state); void iso_uart_rx_mode(void); void iso_uart_clk_master(unsigned int master); void iso_uart_init(void); -void iso_uart_report_overrun(void); void iso_uart_flush(void); void iso_uart_idleflush(void); diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index 6bad290..b3f2665 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -236,5 +236,5 @@ void _main_func(void) } loopLow++; - iso_uart_report_overrun(); + iso_uart_report_errors(); } -- cgit v1.2.3 From 6bafd0cfb40c2d201f8723a3678dd4f04b380842 Mon Sep 17 00:00:00 2001 From: Min Xu Date: Sat, 25 Oct 2014 21:25:54 +0200 Subject: Don't split req_ctx with ATR payload The codnition for flushing a req_ctx on UART idle is fixed to flush only if 1) There has been no new data since last check, and 2) There are no req_ctx currently pending to be transmitted to USB, and 3) We did NOT just got a reset and waiting for ATR I saw an ATR split in two different req_ctx prior, presumably flush decided to send req_ctx after ATR but got a new character just before sent). If we did get a RESET, let original logic decide to send the req_ctx -- presumably when ATR data is fully received. --- firmware/src/simtrace/iso7816_uart.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/iso7816_uart.c b/firmware/src/simtrace/iso7816_uart.c index e37deba..9e8ace9 100644 --- a/firmware/src/simtrace/iso7816_uart.c +++ b/firmware/src/simtrace/iso7816_uart.c @@ -591,7 +591,10 @@ void iso_uart_idleflush(void) static struct req_ctx *last_req = NULL; static u_int16_t last_len = 0; - if (last_req == isoh.rctx || last_len == isoh.rctx->tot_len) { + if (last_req == isoh.rctx && + last_len == isoh.rctx->tot_len && + req_ctx_count(RCTX_STATE_UDP_EP2_PENDING) == 0 && + (isoh.sh.flags & SIMTRACE_FLAG_ATR) == 0) { send_rctx(&isoh); } last_req = isoh.rctx; -- cgit v1.2.3 From 8701086cacca088ae34580908cec45f77042b94e Mon Sep 17 00:00:00 2001 From: Min Xu Date: Sat, 25 Oct 2014 21:30:23 +0200 Subject: 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. --- firmware/src/simtrace/main_simtrace.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'firmware/src/simtrace') 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(); -- cgit v1.2.3 From b6caca4b64a73d8d3ab4ce6b51cea71b8f1a54b0 Mon Sep 17 00:00:00 2001 From: Min Xu Date: Sat, 25 Oct 2014 22:08:04 +0200 Subject: improve handling of spurious IRQs rather than printing directly from the interrupt handler, just increment the number and print it from the main loop function instead. --- firmware/src/simtrace/main_simtrace.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index b84525f..8069349 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -134,16 +134,30 @@ static int simtrace_usb_in(struct req_ctx *rctx) req_ctx_set_state(rctx, RCTX_STATE_FREE); break; } + return 0; } -void custom_spurious_handler(unsigned previous_pc) +static volatile unsigned spuirq_pc, spuirq_count = 0; + +static void check_spurious_irq() +{ + static unsigned last_count = 0; + if (last_count != spuirq_count) { + DEBUGPCR("SPURRIOUS IRQ %i [Old PC = %08X]", spuirq_count, spuirq_pc); + last_count = spuirq_count; + } +} + +static 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); + unsigned flags; + local_irq_save(flags); + spuirq_pc = previous_pc; + spuirq_count++; + local_irq_restore(flags); } -void custom_spurious_entry(void) +static void custom_spurious_entry(void) { register unsigned *previous_pc asm("r0"); asm("ADD R1, SP, #16; LDR R0, [R1]"); @@ -247,10 +261,11 @@ void _main_func(void) if ((loopLow & 0xFFFF) == 0) { DEBUGPCR("Heart beat %08X", loopHigh++); } - if ((loopLow & 0x3FF) == 0) { + if ((loopLow & 0x3F) == 0) { iso_uart_idleflush(); } loopLow++; iso_uart_report_errors(); + check_spurious_irq(); } -- cgit v1.2.3