I found 4 alternatives:
In the end the option most attractive to me at this point is to add debugging drivers to my code.
But I'll list the other options first...
Hardware:There are a few variants out there, costing ctom $10-$100+:
Atmega328P Xplained Mini, AVR Dragon, JTAGICE2, AVR One, JTAGICE3
The cheapest one is the Atmega328P Xplained Mini at ~$10. Unfortunately, it seems very tied to the Atmel Studio which is only supported on Windows.
Emulators:I found 2 emulators, each with similar feature sets, but one seems a bit legacy at this point:
Both emulators have the option to sample the output pins, and log the values into a .vcd file, which can be displayed with gtkwave.
It's of course important to mention that you can do print debugging too when you need it
Drivers:After stumbling across this post by Jan Dolinay, I wanted to see it it worked for my cheap arduino.
I turned out it was farily easy to build it. There was a few caveats (mentioned by Jan in his post) regarding the serial interface, but in essence, you cannot use the Serial class since the debugger uses the serial port. But there is a debug_message(const char* msg) that can be used instead.
- Add the avr8-stub.c to your build, add avr8-stub.h to your main.cpp
- Overwrite the WInterrupts.c in your core library
- Call debug_init() in your setup() function
- [Optional] Set programmatic breakpoints using breakpoint()
- Add flags "-Og" and "-gdwarf-2"
Once you've built the .hex file and uploaded it, it's time to run avr-gdb:
- Upload the myprog.hex file with avrdude
- Run debugger with, connecting to your serial port:
- avr-gdb -ex "target remote /dev/cu.wchusbserial1410" -b 115200 myprog.elf
And, that's it! Now you can debug using breakpoints as usual.