Merge pull request #1510 from martinling/sgpio-deadline-check

SGPIO deadline check
This commit is contained in:
Michael Ossmann
2024-12-05 11:30:06 -05:00
committed by GitHub
3 changed files with 58 additions and 17 deletions

View File

@ -100,10 +100,10 @@ shadow registers.
There are four key code paths, with the following worst-case timings: There are four key code paths, with the following worst-case timings:
RX, normal: 152 cycles RX, normal: 150 cycles
RX, overrun: 76 cycles RX, overrun: 74 cycles
TX, normal: 140 cycles TX, normal: 138 cycles
TX, underrun: 145 cycles TX, underrun: 143 cycles
Design Design
====== ======
@ -239,6 +239,7 @@ The rest of this file is organised as follows:
.equ ERROR_NONE, 0 .equ ERROR_NONE, 0
.equ ERROR_RX_TIMEOUT, 1 .equ ERROR_RX_TIMEOUT, 1
.equ ERROR_TX_TIMEOUT, 2 .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): // Our slice chain is set up as follows (ascending data age; arrows are reversed for flow):
// L -> F -> K -> C -> J -> E -> I -> A // 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 // relying on any assumptions about the timing details of a read over
// the SGPIO to AHB bridge. // 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: \name\()_int_wait:
// Spin on the exchange interrupt status, shifting the slice A flag to the carry flag. // 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, twice ldr int_status, [sgpio_int, #INT_STATUS] // int_status = SGPIO_STATUS_1 // 10
lsr scratch, int_status, #1 // scratch = int_status >> 1 // 1, twice lsr scratch, int_status, #1 // scratch = int_status >> 1 // 1
bcc \name\()_int_wait // if !carry: goto int_wait // 3, then 1 bcc \name\()_int_wait // if !carry: goto int_wait // 1
// Clear the interrupt pending bits that were set. // Clear the interrupt pending bits that were set.
str int_status, [sgpio_int, #INT_CLEAR] // SGPIO_CLR_STATUS_1 = int_status // 8 str int_status, [sgpio_int, #INT_CLEAR] // SGPIO_CLR_STATUS_1 = int_status // 8
@ -430,12 +437,31 @@ as follows:
Routine: Uses conditional branches to: Routine: Uses conditional branches to:
idle tx_loop, wait_loop idle tx_loop
wait_loop
tx_zeros tx_loop tx_zeros tx_loop
checked_rollback idle checked_rollback idle
tx_loop tx_zeros, checked_rollback, rx_loop, wait_loop
wait_loop rx_loop, tx_loop tx_loop tx_zeros
rx_loop rx_shortfall, checked_rollback, tx_loop, wait_loop checked_rollback
wait_loop
missed_deadline
rx_loop
wait_loop tx_loop
missed_deadline
rx_loop
missed_deadline <none>
rx_loop checked_rollback
tx_loop
wait_loop
missed_deadline
rx_shortfall
rx_shortfall rx_loop rx_shortfall rx_loop
If any of these routines are reordered, or made longer, you may get an error If any of these routines are reordered, or made longer, you may get an error
@ -578,7 +604,7 @@ checked_rollback:
tx_loop: tx_loop:
// Wait for and clear SGPIO interrupt. // Wait for and clear SGPIO interrupt.
await_sgpio tx // await_sgpio() // 34 await_sgpio tx // await_sgpio() // 32
// Check if there is a mode change request. // Check if there is a mode change request.
// If so, we may need to roll back shortfall stats. // If so, we may need to roll back shortfall stats.
@ -628,7 +654,7 @@ tx_loop:
wait_loop: wait_loop:
// Wait for and clear SGPIO interrupt. // Wait for and clear SGPIO interrupt.
await_sgpio wait // await_sgpio() // 34 await_sgpio wait // await_sgpio() // 32
// Check if there is a mode change request. // Check if there is a mode change request.
// If so, return to idle. // If so, return to idle.
@ -640,10 +666,21 @@ wait_loop:
// Jump to next mode if threshold reached, or back to wait loop start. // Jump to next mode if threshold reached, or back to wait loop start.
jump_next_mode wait // jump_next_mode() // 15 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: rx_loop:
// Wait for and clear SGPIO interrupt. // Wait for and clear SGPIO interrupt.
await_sgpio rx // await_sgpio() // 34 await_sgpio rx // await_sgpio() // 32
// Check if there is a mode change request. // Check if there is a mode change request.
// If so, we may need to roll back shortfall stats. // If so, we may need to roll back shortfall stats.

View File

@ -428,7 +428,11 @@ static const char* mode_name(uint32_t mode)
static const char* error_name(uint32_t error) 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]); const uint32_t num_errors = sizeof(error_names) / sizeof(error_names[0]);
if (error < num_errors) { if (error < num_errors) {
return error_names[error]; return error_names[error];

View File

@ -975,7 +975,7 @@ typedef struct {
uint32_t threshold; 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 */ /** 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; 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; uint32_t error;
} hackrf_m0_state; } hackrf_m0_state;