Add an M0 TX_START mode, in which zeroes are sent until data is ready.
In TX_START mode, a lack of data to send is not treated as a shortfall. Zeroes are written to SGPIO, but no shortfall is recorded in the stats. Using this mode helps avoid spurious shortfalls at startup. As soon as there is data to transmit, the M0 switches to TX_RUN mode. This change adds five cycles to the normal TX path, in order to check for TX_START mode before sending data, and to switch to TX_RUN in that case. It also adds two cycles to the TX shortfall path, to check for TX_START mode and skip shortfall processing in that mode. Note the allocation of r3 to store the mode setting, such that this value is still available after the tx_zeros routine.
This commit is contained in:
@ -37,7 +37,8 @@ struct m0_state {
|
||||
enum m0_mode {
|
||||
M0_MODE_IDLE = 0,
|
||||
M0_MODE_RX = 1,
|
||||
M0_MODE_TX = 2,
|
||||
M0_MODE_TX_START = 2,
|
||||
M0_MODE_TX_RUN = 3,
|
||||
};
|
||||
|
||||
/* Address of m0_state is set in ldscripts. If you change the name of this
|
||||
|
@ -68,8 +68,8 @@ There are four key code paths, with the following worst-case timings:
|
||||
|
||||
RX, normal: 147 cycles
|
||||
RX, overrun: 76 cycles
|
||||
TX, normal: 133 cycles
|
||||
TX, underrun: 140 cycles
|
||||
TX, normal: 138 cycles
|
||||
TX, underrun: 142 cycles
|
||||
|
||||
Design
|
||||
======
|
||||
@ -118,7 +118,8 @@ registers and fixed memory addresses.
|
||||
// Operating modes.
|
||||
.equ MODE_IDLE, 0
|
||||
.equ MODE_RX, 1
|
||||
.equ MODE_TX, 2
|
||||
.equ MODE_TX_START, 2
|
||||
.equ MODE_TX_RUN, 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
|
||||
@ -179,7 +180,7 @@ main:
|
||||
|
||||
idle:
|
||||
// Wait for RX or TX mode to be set.
|
||||
mode .req r0
|
||||
mode .req r3
|
||||
ldr mode, [state, #MODE] // mode = state.mode // 2
|
||||
cmp mode, #MODE_IDLE // if mode == IDLE: // 1
|
||||
beq idle // goto idle // 1 thru, 3 taken
|
||||
@ -230,7 +231,7 @@ loop:
|
||||
add buf_ptr, buf_base // buf_ptr += buf_base // 1
|
||||
|
||||
// Load mode.
|
||||
mode .req r0
|
||||
mode .req r3
|
||||
ldr mode, [state, #MODE] // mode = state.mode // 2
|
||||
|
||||
// Branch according to mode setting.
|
||||
@ -255,6 +256,15 @@ direction_tx:
|
||||
sub buf_margin, #32 // buf_margin -= 32 // 1
|
||||
bmi tx_zeros // if buf_margin < 0: goto tx_zeros // 1 thru, 3 taken
|
||||
|
||||
// At this point we know there is TX data available.
|
||||
// If still in TX start mode, switch to TX run.
|
||||
cmp mode, #MODE_TX_START // if mode != TX_START: // 1
|
||||
bne tx_write // goto tx_write // 1 thru, 3 taken
|
||||
mov mode, #MODE_TX_RUN // mode = TX_RUN // 1
|
||||
str mode, [state, #MODE] // state.mode = mode // 2
|
||||
|
||||
tx_write:
|
||||
|
||||
// Write data to SGPIO.
|
||||
ldm buf_ptr!, {r0-r3} // r0-r3 = buf_ptr[0:16]; buf_ptr += 16 // 5
|
||||
str r0, [sgpio_data, #SLICE0] // SGPIO_REG_SS[SLICE0] = r0 // 8
|
||||
@ -282,6 +292,10 @@ tx_zeros:
|
||||
str zero, [sgpio_data, #SLICE6] // SGPIO_REG_SS[SLICE6] = zero // 8
|
||||
str zero, [sgpio_data, #SLICE7] // SGPIO_REG_SS[SLICE7] = zero // 8
|
||||
|
||||
// If in TX start mode, don't count this as a shortfall.
|
||||
cmp mode, #MODE_TX_START // if mode == TX_START: // 1
|
||||
beq loop // goto loop // 1 thru, 3 taken
|
||||
|
||||
shortfall:
|
||||
|
||||
// Get current shortfall length from high register.
|
||||
|
@ -296,7 +296,7 @@ void transceiver_startup(const transceiver_mode_t mode) {
|
||||
led_off(LED2);
|
||||
led_on(LED3);
|
||||
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_TX);
|
||||
m0_state.mode = M0_MODE_TX;
|
||||
m0_state.mode = M0_MODE_TX_START;
|
||||
m0_state.shortfall_limit = _tx_underrun_limit;
|
||||
break;
|
||||
default:
|
||||
|
@ -378,7 +378,7 @@ int write_register(hackrf_device* device, uint8_t part,
|
||||
}
|
||||
|
||||
static void print_state(hackrf_m0_state *state) {
|
||||
const char *mode_names[] = {"IDLE", "RX", "TX"};
|
||||
const char *mode_names[] = {"IDLE", "RX", "TX_START", "TX_RUN"};
|
||||
const uint32_t num_modes = sizeof(mode_names) / sizeof(mode_names[0]);
|
||||
printf("M0 state:\n");
|
||||
printf("Mode: %u (%s)\n",
|
||||
|
Reference in New Issue
Block a user