Merge pull request #1510 from martinling/sgpio-deadline-check
SGPIO deadline check
This commit is contained in:
@ -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
|
||||
@ -430,12 +437,31 @@ as follows:
|
||||
|
||||
Routine: Uses conditional branches to:
|
||||
|
||||
idle tx_loop, wait_loop
|
||||
idle tx_loop
|
||||
wait_loop
|
||||
|
||||
tx_zeros tx_loop
|
||||
|
||||
checked_rollback idle
|
||||
tx_loop tx_zeros, checked_rollback, rx_loop, wait_loop
|
||||
wait_loop rx_loop, tx_loop
|
||||
rx_loop rx_shortfall, checked_rollback, tx_loop, wait_loop
|
||||
|
||||
tx_loop tx_zeros
|
||||
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
|
||||
|
||||
If any of these routines are reordered, or made longer, you may get an error
|
||||
@ -578,7 +604,7 @@ checked_rollback:
|
||||
tx_loop:
|
||||
|
||||
// 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.
|
||||
// If so, we may need to roll back shortfall stats.
|
||||
@ -628,7 +654,7 @@ tx_loop:
|
||||
wait_loop:
|
||||
|
||||
// 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.
|
||||
// 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_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.
|
||||
await_sgpio rx // await_sgpio() // 34
|
||||
await_sgpio rx // await_sgpio() // 32
|
||||
|
||||
// Check if there is a mode change request.
|
||||
// If so, we may need to roll back shortfall stats.
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user