Keeping the base address of this structure in a register allows us to
use offsets to load individual fields from it, without needing their
individual addresses.
However, the ldr instruction can only use immediate offsets relative to
the low registers (r0-r7), or the stack pointer (r13).
Low registers are in short supply and are needed for other instructions
which can only use r0-r7, so we use the stack pointer here.
It's safe to do this because we do not use the stack. There are no
function calls, interrupt handlers or push/pop instructions in the M0
code.
This change saves four cycles by eliminating loads of the addresses for
the offset & tx registers, plus a further two by eliminating the need to
stash one of these addresses in r8.
The high registers (r8-r14) cannot be used directly by most of the
instructions in the Cortex-M0 instruction set.
One of the few instructions that can use them is mov, which can use
any pair of registers.
This allows saving two cycles, by replacing two loads (2 cycles each)
with moves (1 cycle each), after stashing the required values in high
registers at startup.
This allows us to use ldr/str with an immediate offset to access the
SGPIO interrupt registers, rather than first having to load a register
with the specific address we want to access.
This change saves a total of 6 cycles, by eliminating two loads (2
cycles each), one of which could be executed twice.
The current code does reads and writes in two chunks: one of
6 words, followed by one of 2.
Instead, use two chunks of 4 words each. This takes the same number of
total cycles, but frees up two registers for other uses.
Note that we can't do things in one chunk, because we'd need eight
registers to hold the data, plus a ninth to hold the buffer pointer. The
ldm/stm instructions can only use the eight low registers, r0-r7.
So we have to use two chunks, and the most register-efficient way to do
that is to use two equal chunks.
Previously this register was reloaded with the same value during each loop.
Initialising it once, outside the loop, saves two cycles.
Note the separation of the loop start ("loop") from the entry point ("main").
Code between these labels will be run once, at startup.
These variables are already placed together; this commit just groups
them into a struct and declares this in a new header.
This commit should not result in any change to the firmware binary.
Only the names of symbols are changed.
This removes the definition of the offset variable,
volatile uint32_t usb_bulk_buffer_offset = 0;
which is actually superfluous. This variable, along with its neighbour
usb_bulk_buffer_tx, is placed explicitly by the linker script. Its type
is defined by the declaration in usb_bulk_buffer.h.
There is no need to define it here, and doing so gives the misleading
impression that its initial value can be changed by modifying this line!
The initialization to zero never actually takes effect, because the
variable is not placed in the .data or .bss sections which are
initialised by the startup code.
The offset and tx variables are both set in set_transceiver_mode
before SGPIO streaming is started, so the M0 code does not use
them uninitialised.
When switching to frequency mode or modifying the frequency ranges,
ensure that the Opera Cake is switched to the correct port on the very
next tuning.
This uses `add_custom_command` to run a cmake script instead of using
`configure_file` directly, which allows for adding dependencies and
creates an ouput that can be depended on.
It also uses `add_custom_command` instead of `add_custom_target` to
create the M0 binary, since custom targets have no output file to depend
on.
Unfortunately, multiple targets cannot depend on the same generated file
or cmake tries to run the generation multiple times in parallel. So, the
.bin/.s generation is now duplicated for each target so they don't
conflict.
fixes#693
This changes m0_rom_to_ram to read directly from the ROM region, rather
than copying from where .text has been copied to RAM.
Previously the second .text section would be merged with the first one,
so the M0 image would be copied to RAM during `pre_main`. However, on
newer linkers the sections are not merged together so the second .text
section did not get copied to RAM.
fixes#936
Previously, a USB vendor request could interrupt in the middle of
set_freq and make conflicting changes, leaving the HackRF in an
undefined state.
fixes#772
Previously the firmware would re-initialise the bulk endpoints on
every transceiver mode change including a USB data toggle reset,
which could cause the first bulk packet (512-bytes) to be dropped
by the host if the PID no longer matched.
For RX, this replaces received samples with an 8-bit incrementing counter.
This allows for identification of any dropped or repeated samples across the
SGPIO interface.
For TX, this compares transmitted samples against another 8-bit incrementing
counter, and raises pin B2AUX1 if they don't match. This should be used with
a tool on the host-side that transmits a matching counter.