Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SGPIO deadline check #1510

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 52 additions & 15 deletions firmware/hackrf_usb/sgpio_m0.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
======
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down
6 changes: 5 additions & 1 deletion host/hackrf-tools/src/hackrf_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
2 changes: 1 addition & 1 deletion host/libhackrf/src/hackrf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down