After the positive simavr reception, I decided to keep exploring methods to enhance even more the coding experience with Arduino and AVR in general. As software can’t simulate hardware at 100% and sometimes there is no choice but to develop and test using the real thing, then the lack of proper debugging tools returns.
That’s why I’m going to explain another tool or better said library I found interesting. This library already had support for Arduino so I went ahead and registered it on PlatformIO, if it gets accepted then it will be available under the name avr-debugger. The library doesn’t have any dependencies, however, it needs the ISRs enabled, which Arduino already does by default, but a bare-metal configuration would need the sei()
command.
The library has two relevant functions, debug_init()
and breakpoint()
, and as their name suggests the former will configure the related hardware and the later is only needed to add fixed breakpoints. So a main.cpp and platformio.ini would look like this:
The library has a couple of options that configure the mechanism used for debugging and also for enabling some extra capabilities, those are found here
#define AVR8_BREAKPOINT_MODE (1) // Selects RAM of Flash breakpoints
#define AVR8_SWINT_SOURCE (0) // Select ISR source, 0 -> INT0
#define AVR8_LOAD_SUPPORT (0) // Enables load command for GDB, requieres modified bootloader
#define AVR8_USER_BAUDRATE (115200) // Changes the baudrate of the GDB server
This library has two mechanisms to determine if a breakpoint was reached.
The first and default one, called RAM breakpoint mode, enables an ISR like INT0, configs it to trigger at a low level, and then puts the related pin at a low level. That will trigger the ISR constantly, however, the AVR core will always execute one instruction in the main code before jumping into ISR even if the interrupt is pending, allowing to step instructions. Its main drawback is that execution will be slower.
The second mechanism, called Flash breakpoint mode, is very similar to the technique that uses the debugWIRE protocol to set breakpoints, which involves the re-writing of the instruction where the breakpoint is set with the break instruction, and then the debugger regularly verifies if the CPU was stopped. The main difference with debugWire is that as there is no external hardware that can detect said condition then it uses the clever idea of enabling the watchdog and uses a jump instruction that jumps to itself where the breakpoint was placed, creating an infinite loop that hangs the program.
The second mechanism would have no performance penalty and give the same results as if a real external debugger was connected, however, it would also have its same drawbacks, like the faster wearing of the Flash memory.
I haven’t tested the Flash breakpoint mode yet, but for what I’ve read it would involve replacing the bootloader and having to change some fuses that enable the re-writing of flash memory.