Debugging embedded firmware is generally difficult and slow, as target hardware limitations usually prevent meaningful logging or the ability to connect a debugger and use real-time software breakpoints. Developing embedded firmware without access to a simulator means all firmware needs to be flashed and run on the target hardware, which becomes cumbersome.
For these reasons, the threeboard project includes a fully functional terminal-based threeboard simulator for Linux and macOS, built on top of the simavr project. The simulator enables running and debugging of the threeboard AVR firmware on the same x86 platform used for development, which greatly improves development speed and makes debugging far easier and more accessible. Most importantly, the firmware being simulated is the same firmware binary that runs on physical hardware: no simulator-specific code paths exist in the firmware, although UART-based logging is disabled when building for physical hardware.
The simulator runs a terminal-based graphical emulator of the threeboard hardware, designed to look as similar as possible to the actual threeboard hardware, with the LEDs and key switches laid out almost identically.
Other simulator features include:
g
) the server runs locally on port 1234.LOG()
and LOG_ONCE()
macros in the firmware produce logs that are transmitted to this mock data receiver in the simulator. These macros are only enabled when building the firmware for the simulator, because the threeboard firmware doesn’t correctly initialise the UART pins or clock, it takes advantage of simavr’s UART implementation to transmit data instantaneously from the firmware to the simulator.RUNNING
, SLEEPING
and CRASHED
. The threeboard simulator includes a visualisation of the amount of time spent in each state while running the simulator, which is useful when trying to optimise power usage or detect infinite or expensive loops in firmware..data
and .bss
segments) and dynamic memory usage. Since the threeboard hardware constraints forbid dynamic memory allocation, the dynamic memory usage is an indication of stack use.The simulator is effectively a wrapper around simavr, an exceptionally good AVR simulator that supports lots of features of many AVR microcontrollers, and is easy to configure with new MCUs and features. Simavr does most of the difficult work of simulating the firmware: given the threeboard firmware binary file, simavr parses it, determines the properties of the MCU being simulated based on headers in the binary, and can execute the instructions one cycle at a time. It supports interrupts and timing, and has full support for the atmega32u4’s USB controller.
Events are issued and handled in simavr using IOCTL calls. These allow a way of triggering arbitrary functionality and message passing within simavr, which enables its configurability.
The simulator is comprised of several interoperating modules which emulate the properties of different hardware components on the threeboard. Modules are needed for external components (EEPROMs and UART) and for emulating a USB host machine to send keypress information.
The UI module is responsible for translating the state of the simulator into a visualisation of the result of that state on the threeboard’s hardware, in particular its LEDs. It’s a purely text-based user interface implemented using ncurses. The static outlines and frames of the UI are drawn once, and the dynamic components are redrawn at a rate of 200Hz.
The USB host component is far from a standards-compliant host implementation. It contains the least amount of logic required to make the threeboard firmware believe it is communicating with a real USB host. It simply polls the USB controller in firmware by triggering USB general interrupts which cause the firmware to periodically send its HID state over USB.