Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Flashing & Debugging

Ariel OS makes it easy to flash and debug applications, by unifying the different existing flashing mechanisms and debug interface protocols and selecting the most suitable one, based on the target board and development and production requirements.

Note

The terms “debug”, “debugging”, and “debugger” tend to refer to a wide array of overlapping concepts. In the following, we define and use phrases that use narrower meanings, with the hope to make these clearer.

Debug Interfaces, Protocols, and Probes

Debug interface protocols allow reading and writing from and to system memory and processor registers, setting breakpoints, and stepping through the program execution, among other things. The two debug interface protocols supported by Ariel OS tooling are JTAG and Serial Wire Debug (SWD): SWD is a variant of JTAG with a reduced pin count but, being an Arm technology, it is only found on Arm-based microcontrollers, while JTAG is vendor-agnostic. Besides being a debug interface protocol, JTAG is actually more generic and, in particular, also enables boundary scans (automatically checking the traces of a PCB by taking direct control of the chip pins present on the board), which were originally its primary purpose.

Debug interface protocols interact with the microcontroller through a debug interface, which may be a physical interface or an interface internal to the microcontroller, connected to the processor and/or the microcontroller buses.

As host computers do not have support for these debug interface protocols, a debug probe is necessary. Debug probes are USB devices that allow using these debug interface protocols, either with standard (e.g., CMSIS-DAP) or vendor-specific USB classes. In some cases, debug probes can also be built into the microcontrollers themselves, behind a USB interface.

Ariel OS currently uses probe-rs to interact with debug probes. probe-rs supports both SWD and JTAG, and allows to flash firmware, to reboot into it, and to fetch the debug channel from the running application over the debug interface protocol. When multiple host tools are available for a board, Ariel OS attempts to make the best choice, based on functionality and flashing performance. However, to specifically choose probe-rs as the host tool, the probe-rs laze module can be selected.

Note

probe-rs is currently focused on debug interface protocols only. It does not support other serial protocols used for flashing through bootloaders.

Flashing a Board

In general, there are two ways of writing the firmware to the flash memory (or memories) where the processor(s) execute(s) from—i.e., to flash the board: either by using a debug interface protocol, or by booting into a bootloader available on the board and then using one of its supported methods.

Flashing Trough Debug Interface Protocols

As debug interface protocols allow arbitrarily writing to system memory, they allow downloading the firmware into the flash memory, at the necessary location. When the debug interface is available (e.g., during development), this is generally the preferred option, unless flashing through the bootloader is faster in practice. After flashing has completed, debug interface protocols allow rebooting the microcontroller into the newly-flashed firmware. Alternatively, debug probes also often feature a wire that allows asserting the reset signal of the microcontroller, thus triggering a hardware reset.

Ariel OS provides the laze tasks listed in the following table:

laze tasksDescription
runCompiles, flashes, and runs an application. The debug channel output is printed in the terminal.
flashCompiles and flashes an application, before rebooting the target.
flash-erase-allErases the entire flash memory, including user data. Unlocks it if locked.
resetReboots the target.

Tip

Debug interface protocols also allow writing the firmware to RAM (instead of flash) and rebooting from there, which could be useful during development as flash endurance is limited. However, as microcontrollers have much less RAM than flash, this is not often applicable, and not currently supported by Ariel OS.

Tip

As debug interface protocols offer more functionality than bootloaders, and are usually easier to use in an automated fashion, they are generally preferred as the flashing method. However, sometimes they simply cannot be used, e.g., because the debug interface has been disabled in hardware or is not physically accessible. Additionally, in some cases, flashing through the bootloader may be faster than using the debug interface protocol, in which case it may be preferable to use the faster method.

Flashing Through Bootloaders

Alternatively, boards can also be flashed through their bootloaders, if they have one. Microcontrollers can have their own vendor-provided bootloaders, and/or be flashed with custom bootloaders. Bootloaders thus allow to use various standard or vendor-specific serial protocols to flash firmware.

Depending on the microcontroller family and on the bootloader, the most common options are (in no particular order):

Other serial protocols may also be supported by bootloaders.

Depending on the serial protocol used and on the bootloader, the host tool may be able to trigger entering the bootloader automatically, or it may require a manual action on the board. It also may or may not be possible to reboot the microcontroller automatically after flashing has completed.

Ariel OS provides the laze tasks listed in the following table:

laze tasksAvailabilityDescription
runESP32 devicesCompiles, flashes, and runs an application. Logs (not the debug channel output) are printed in the terminal. Currently uses espflash.
flashESP32 devicesCompiles and flashes an application, before rebooting the target. Currently uses espflash.
flash-dfuseDfuSe devices, i.e., STM32 devicesCompiles and flashes an application via DfuSe, the non-standard ST protocol based on USB DFU, before rebooting the target. Requires bootloader support for DfuSe in the microcontroller, and dfu-util on the host.
resetESP32 devicesReboots the target. Currently uses espflash.

Debug Channel Transports

Debug interface protocols as introduced above also allow providing an additional piece of functionality: a debug channel, that allows moving sequential data from the target to the host, through the debug interface. Two main techniques exist to implement such debug channel over debug interface protocols: semihosting, and Real Time Transfer (RTT). Even though originally vendor-specific technologies, they have been extended to other architectures and vendors (e.g., semihosting on RISC-V), and can be used on every microcontroller currently supported by Ariel OS.

Semihosting

Semihosting provides various operations to interact with the host from the firmware running on the target. A semihosting operation involves triggering a specific exception (e.g., with a breakpoint) after having set the arguments required for by operation in the appropriate processor registers. This functionally behaves as a remote syscall interface: see for instance the documentation of the SYS_WRITE0 operation, which allows sending a string to the host for the host to print it as debug channel output.

Note

Due to how semihosting works, it is extremely slow as a debug channel, and semihosting is currently unsupported as a debug channel in Ariel OS.

Tip

probe-rs automatically prints the semihosting output when used in the firmware.

Real Time Transfer (RTT)

RTT output relies on in-memory buffers which are written to by the firmware on the target and read, in the background (when the microcontroller supports it), by the debug probe. RTT supports having multiple such buffers, allowing to implement multiple channels. In addition, RTT supports channels in both directions: from the target to the host (“up channels”), and from the host to the target (“down channels”), but the latter are not used for the debug channel. RTT also requires an in-memory RTT Control Block, which stores the locations of the in-memory channel buffers. The RTT-enabled host tool either knows the location of the control block in memory, or scans the memory to find the magic bytes (“ID”) the control block starts with.

Ariel OS sets RTT into non-blocking, trimming mode by default: that is, new data will fill up the RTT up buffers as much as possible (and may be truncated), and excess data will be discarded, but execution will not block when the up buffers are full. RTT-enabled host tools may change the mode when attached, to enable blocking mode and avoid losing data; however that means that the execution may freeze if they get detached without resetting the mode to non-blocking.

Tip

probe-rs automatically prints the RTT output when used in the firmware. It sets the mode to blocking when attached to the target.

On top of providing a debug channel, semihosting also allows the implementation of other I/O and host-related functionality. In particular, ariel_os::debug::exit() is currently implemented through semihosting on embedded platforms.

Tip

Currently, Ariel OS uses the semihosting crate, which provides support for semihosting on every architecture currently supported by Ariel OS.