This document should help the reader to get a better understanding of the nomagic_probe fimrware. It shall explain the reasoning behind the design descisions and give an overview about the major parts that together make up the nomagic_probe firmware.
The guiding strategies explain the strategy of the firmware. It is also these guedlines that differentiatiate nomagic_probe from alternative solutions.
No solution can be perfect in all circumstances. The consequence of these simple truth is to either specialize on a very narrow field of application, or to accept the presence of issues. If one accept the presence of issues then one should also make it easy for the user to identify the issues, work aourond them or fix them. This way the firmware can still be of use and might even become better over time with increaed use.
If a firmware relies on magic black boxes, that contain functionality and that are expected to just work, can be very efficient. But it also makes it impossible to fix issues caused by or that arrise from these black boxes.
The nomagic_probe firmware tries to be as pefect as it can be. It also tries to be easy to understand for users that want to look "under the hood". And it avoids using magic black boxes as hard as it can.
Soem people think that adding more and more features on a firmware just make it better and better. But every new feature comes with some hidden cost. Over time the complexity of the firmware rises and rises with each new feature until it becomes unmanageable.
To be able to include as many useful functions as possible nomagic_probe firmware will focus on supporting only one taget at a time. If the user wants to use nomagic_probe firmware with a different target chip then a change in configuration will be necesary.
When bringing new members into a project or when going back to a project finished long ago there is a learning curve and setup cost to get the environment set up. The nomagic_probe firmware tries to decrease the burden in this sitiuation.
The recommendation is to add the frimware (*.elf or *.uf2 file) a well as any necessary target configuration files to the project source code repository. This way the setup for debugging is a two step procedure. First flashing the nomagic_probe firmware and then applying the configuration.
the following sections describe the methods used to achive the targets.
The complete firmware code is copied to RAM and only after that the firmware starts executing. Thsi is done to prevent loading code from QSPI and the QSPI cache to influence the timing of the firmware. This also frees up the QSPI interface for data storage.
The RP2040 has no internal non volatile memory (flash). That makes booting it a bit more complex. Is has to happen in several stages that execute one after the other.
On power on the RP2040 starts executing code from addres 0. That is the boot loader from the read only memeory (ROM). The bootloader uses a standard method of reading from the QSPI flash to read the first 256 bytes. It then checks if the last 4 bytes are a valid checksum (CRC32) over those bytes. If so then it starts executing these bytes, the so called second stage boot loader. If the CRC check fails then the RP2040 boots as USB mass storage device and allows to flash a firmware by storing an *.uf2 file on it.
As the boot loader is a ROM embedded in the chip there is no way to change this part of the boot up behaviour.
Nothing much can be accomplished in 252 bytes of code. The intention is that this code configures the RP2040 to the specific QSPI flash that is connected. This then allows for higher speeds. It then calles into the firmware.
The third stage boot loader is the Reset_Handler() function. This third stage is not necessary. And instead of it the firmware could start executing. Top improve the timing the complete firmware should be excuted from RAM. Therefore the firmware code needs to be copied to RAM. Some basic initialization and the copying of the code is done in the Reset_Handler() function. Once done the main function is called.
This chapter describes the structure of the component that make up the firmware, as well as their interactions.
These are the modules that make up the firmware: - swd - target - gdbserver - file system
The swd module provides the functionality of the SWD Interface (defined in probe_api/swd.h) to the target module.
The target module executes the functionality requested by the gdbserver module.
The gdbserver module implements the GDB-Server protocoll and uses the target module to aquire the requested information and to execute the commanded actions.
The file system provides the mass storage interface.
The SWD module implements the ARM specified two wire debug protocol. It does this in a layered approach.
The first and lowest layer is the bit layer. It is implemented in swd_gpio.c and deals with the SWDIO and SWCLK signals. It handles the single bits on the wires. So high, Low Input Output,..
The second layer is the packet layer it sits on top of the bit layer. It is implemented in swd_packets.c and handles packets. It knows how SWD packets lok like and sends the requested packets over the line. It does this asynchronous to the API function being called in the tick function. It uses a queue. The API call enters the request for a packet to be send into the queue. In the tick call the queu is checked and if it contains a request then one packet will be send. This process makes it necessary to collect the result of a read packet from a result queue.
On top of the packet layer is the protocol layer. It is implemented in swd_protocol.c and swd_engine.c. It provides an API(defined in probe_api/swd.h) for other modules (mainly the target module) to use. It also put the requested actions into a queue and executes them once the tick function gets called.
The file system module provides the USB Mass Storage device as well as the real and faked files inside it.
The following lists all the folders and gives an overview what they contain.
implementation of functionality usually provided by a "standard library". printf(), strlen(), atoi(), memcpy(),…
the TinyUSB stack. The folder contains all files from TinyUSB. Only a small fraction of the files are actually used in this firmware. Having them all available helps if the functionality needs to be extended and with tinyUS updates.