From cdc3efa942bf31bc34cc154c6f2baf297d1df9f7 Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Tue, 26 Nov 2024 19:07:36 +0000 Subject: [PATCH] Detect whether the M0 missed its deadline. --- firmware/hackrf_usb/sgpio_m0.s | 39 ++++++++++++++++++++++------ host/hackrf-tools/src/hackrf_debug.c | 6 ++++- host/libhackrf/src/hackrf.h | 2 +- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/firmware/hackrf_usb/sgpio_m0.s b/firmware/hackrf_usb/sgpio_m0.s index 4de55470d..b36e8331e 100644 --- a/firmware/hackrf_usb/sgpio_m0.s +++ b/firmware/hackrf_usb/sgpio_m0.s @@ -100,10 +100,10 @@ shadow registers. There are four key code paths, with the following worst-case timings: -RX, normal: 152 cycles -RX, overrun: 76 cycles -TX, normal: 140 cycles -TX, underrun: 145 cycles +RX, normal: 150 cycles +RX, overrun: 74 cycles +TX, normal: 138 cycles +TX, underrun: 143 cycles Design ====== @@ -239,6 +239,7 @@ The rest of this file is organised as follows: .equ ERROR_NONE, 0 .equ ERROR_RX_TIMEOUT, 1 .equ ERROR_TX_TIMEOUT, 2 +.equ ERROR_MISSED_DEADLINE, 3 // Our slice chain is set up as follows (ascending data age; arrows are reversed for flow): // L -> F -> K -> C -> J -> E -> I -> A @@ -289,11 +290,17 @@ buf_ptr .req r4 // relying on any assumptions about the timing details of a read over // the SGPIO to AHB bridge. + // Test the exchange interrupt status, shifting the slice A flag to the carry flag. + // If the flag is already set, we missed our deadline. + ldr int_status, [sgpio_int, #INT_STATUS] // int_status = SGPIO_STATUS_1 // 10 + lsr scratch, int_status, #1 // scratch = int_status >> 1 // 1 + bcs missed_deadline // if carry: goto missed_deadline // 1 + \name\()_int_wait: - // Spin on the exchange interrupt status, shifting the slice A flag to the carry flag. - ldr int_status, [sgpio_int, #INT_STATUS] // int_status = SGPIO_STATUS_1 // 10, twice - lsr scratch, int_status, #1 // scratch = int_status >> 1 // 1, twice - bcc \name\()_int_wait // if !carry: goto int_wait // 3, then 1 + // Test the flag again, and if it's still unset, repeat until it's set. + ldr int_status, [sgpio_int, #INT_STATUS] // int_status = SGPIO_STATUS_1 // 10 + lsr scratch, int_status, #1 // scratch = int_status >> 1 // 1 + bcc \name\()_int_wait // if !carry: goto int_wait // 1 // Clear the interrupt pending bits that were set. str int_status, [sgpio_int, #INT_CLEAR] // SGPIO_CLR_STATUS_1 = int_status // 8 @@ -440,14 +447,19 @@ checked_rollback idle tx_loop tx_zeros checked_rollback wait_loop + missed_deadline rx_loop wait_loop tx_loop + missed_deadline rx_loop +missed_deadline + rx_loop checked_rollback tx_loop wait_loop + missed_deadline rx_shortfall rx_shortfall rx_loop @@ -654,6 +666,17 @@ wait_loop: // Jump to next mode if threshold reached, or back to wait loop start. jump_next_mode wait // jump_next_mode() // 15 +missed_deadline: + + // The deadline was missed. Record an error and return to idle state. + error .req r2 + mode .req r3 + mov error, #ERROR_MISSED_DEADLINE // error = ERROR_MISSED_DEADLINE // 1 + mov mode, #MODE_IDLE // mode = MODE_IDLE // 1 + str error, [state, #ERROR] // state.error = error // 2 + str mode, [state, #ACTIVE_MODE] // state.active_mode = mode // 2 + b idle // goto idle // 3 + rx_loop: // Wait for and clear SGPIO interrupt. diff --git a/host/hackrf-tools/src/hackrf_debug.c b/host/hackrf-tools/src/hackrf_debug.c index 397fc50ec..aa4a0182e 100644 --- a/host/hackrf-tools/src/hackrf_debug.c +++ b/host/hackrf-tools/src/hackrf_debug.c @@ -428,7 +428,11 @@ static const char* mode_name(uint32_t mode) static const char* error_name(uint32_t error) { - const char* error_names[] = {"NONE", "RX_TIMEOUT", "TX_TIMEOUT"}; + const char* error_names[] = { + "NONE", + "RX_TIMEOUT", + "TX_TIMEOUT", + "MISSED_DEADLINE"}; const uint32_t num_errors = sizeof(error_names) / sizeof(error_names[0]); if (error < num_errors) { return error_names[error]; diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index ecfc9569a..faa3d4027 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -975,7 +975,7 @@ typedef struct { uint32_t threshold; /** Mode which will be switched to when threshold is reached. Possible values are the same as in @ref hackrf_m0_state.requested_mode */ uint32_t next_mode; - /** Error, if any, that caused the M0 to revert to IDLE mode. Possible values are 0 (NONE), 1 (RX_TIMEOUT) and 2(TX_TIMEOUT)*/ + /** Error, if any, that caused the M0 to revert to IDLE mode. Possible values are 0 (NONE), 1 (RX_TIMEOUT) 2 (TX_TIMEOUT) or 3 (MISSED_DEADLINE) */ uint32_t error; } hackrf_m0_state;