Merge pull request #982 from martinling/bug-180
by Michael Ossmann 3 years 9 months
Merge pull request #982 from martinling/bug-180

Firmware sample buffer management overhaul, including safe handling of TX underruns
3344ea8f
Fix overlapping register allocations.
by Martin Ling 3 years 9 months
ad321643
Correct order of requested mode and flag.
by Martin Ling 3 years 9 months
d755f7a5
Merge pull request #1045 from martinling/usb-isr
by Michael Ossmann 3 years 10 months
Merge pull request #1045 from martinling/usb-isr

Move transceiver mode changes out of USB ISR.
de76404e
Make M0 state retrieval endian-safe.
by Martin Ling 3 years 10 months
779483b9
Rename m0_state.{c,h} to usb_api_m0_state.{c,h}
by Martin Ling 3 years 10 months
1fe06b42
Replace direct setting of M0 mode with a request/a...
by Martin Ling 3 years 10 months
Replace direct setting of M0 mode with a request/ack mechanism.

This change avoids various possible races in which an autonomous mode
change by the M0 might clobber a mode change made from the M4, as well
as related races on other state fields that can be written by the M4.

The previous mode field is replaced by two separate ones:

- active_mode, which is written only by the M0, and indicates the
current operating mode.

- requested_mode, which is written by the M4 to request a change.
This field includes both the requested mode, and a flag bit. The M4
writes the field with the flag bit set, and must then wait for the
M0 to signal completion of the request by clearing the flag bit.

Whilst the M4 is blocked waiting for the flag bit to be cleared, the
M0 can safely make all the required changes to the state that are
needed for the transition to the requested mode. Once the transition
is complete, the M0 clears the flag bit and the M4 continues execution.

Request handling is implemented in the idle loop. To handle requests,
mode-specific loops simply need to check the request flag and branch to
idle if it is set.

A request from the M4 to change modes will always require passing
through the idle loop, and is not subject to timing guarantees. Only
transitions made autonomously by the M0 have guaranteed timing
constraints.

The work previously done in reset_counts is now implemented as part of
the request handling, so the tx_start, rx_start and wait_start labels
are no longer required.

An extra two cycles are required in the TX shortfall path because we
must now load the active mode to check whether we are in TX_START.

Two cycles are saved in the normal TX path because updating the active
mode to TX_RUN can now be done without checking the previous value.
f3633e28
Make an error code available when a shortfall limi...
by Martin Ling 3 years 10 months
Make an error code available when a shortfall limit is hit.

Previously, finding the M0 in IDLE mode was ambiguous; it could indicate
either a normal outcome, or a shortfall limit having being hit.

To disambiguate, we add an error field to the M0 state. The errors
currently possible are an RX timeout or a TX timeout, both of which
can be obtained efficiently from the current operating mode due to
the values used.

This adds 3 cycles to both shortfall paths, in order to shift down
the mode to obtain the error code, and store it to the M0 state.
137f2481
Add some additional commentary.
by Martin Ling 3 years 10 months
8bd37452
Rewrite sweep mode using timed operations.
by Martin Ling 3 years 10 months
Rewrite sweep mode using timed operations.

The previous implementation of sweep mode had the M0 continuing to
receive and buffer samples during retuning. To avoid using data affected
by retuning, the code discarded two 16K blocks of samples after
retuning, before transferring one 16K block to the host.

However, retuning has to be done with the USB IRQ masked. The M4 byte
count cannot be advanced by the bulk transfer completion callback whilst
retuning is ongoing. This makes an RX buffer overrun likely, and
overruns now stall the M0, causing sweep timing to become inconsistent.

It makes much more sense to stop the M0 receiving data during retuning.
Using scheduled M0 mode changes between the RX and WAIT modes, it's now
possible to do this whilst retaining consistent sweep timing. The
comment block added to the start of the `sleep_mode()` function explains
the new implementation.

The new scheme substantially reduces the timing constraints on the host
retrieving the data. Previously, the host had to retrieve each sample
block before the M0 overwrote it, which would occur midway through
retuning for the next sweep, with samples that were going to be
discarded anyway.

With the new scheme, buffer space is used efficiently. No data is
written to the buffer which will be discarded. The host does not need to
finish retrieving each 16K block until its buffer space is due to be
reused, which is not until two sweep steps later. A great deal more
jitter in the bulk transfer timing can therefore now be tolerated,
without affecting sweep timing.

If the host does delay the retrieval of a block enough that its buffer
space is about to be reused, the M0 now stalls. This in turn will stall
the M4 sweep loop, causing the sweep to be paused until there is enough
buffer space to continue. Previously, sweeping continued regardless, and
the host received corrupted data if it did not keep up.
9f79a16b
Report a bug