Embedded Debugging

Every time a program is written, some unintended behavior will result when running the program. Finding the root causes for such unintended behavior is called debugging. For programs written on a desktop computer, this can be done using a source-level debugger such as GDB, often integrated into an IDE. Such debuggers allow you to set breakpoints, single-step through your code, and inspect and modify program variables.

Challenges

Debugging embedded systems is much more challenging for two reasons. First, dynamic behavior plays a much more significant role. For example, are all interrupt requests serviced in an acceptable time? Second, the host computer on which the program is developed usually differs from the target system. For this reason, the above-mentioned source-level debuggers are not of much help because they cannot inspect the internal state of the target system.Logic analyzers or special tracing tools can address the first issue. The OCD, the on-chip debugging module on the target chip, addresses the second issue.

Protocol translations

While the OCD is one key element in making embedded debugging possible, more ingredients are needed. The protocol of the OCD, in our case, the debugWIRE protocol, is nothing that your host computer will understand. For this reason, you need a device in the middle, the hardware debugger, which translates debugWIRE (or any other OCD protocol) into one that the computer understands. For example, this could be CMSIS-DAP (developed by ARM) or the remote serial protocol of GDB (GDB RSP). In the former case, you need a gdbserver program on the host that provides the interface to the GDB debugger by translating CMSIS-DAP into GDB RSP.

With all that in place, you can start GDB giving the name of the executable file as an argument. With the command

target remote <serial line or IP port> 

you can then connect to the target and start debugging.

Poor man’s embedded debugging

There actually exists a cheaper solution to embedded debugging. One could link a remote stub to the program that needs to be debugged. This stub is a set of special purpose subroutines that control the program’s execution and communicate with the host using GDB RSP over the serial line. In this case, we can get rid of the “middle man” in the above picture.

An example is the avr_debug Arduino library, which works on ATmega328(P) (Arduino Uno), ATmega1280/2560 (Arduino Mega), and ATmega1284(P). While it sounds like a good idea and saves money, some drawbacks exist. The stub needs some of the target’s resources. In the case of avr_debug, this is roughly 4.5 kB of flash memory, 0.5 kB of RAM, one serial port, a timer interrupt, and one external interrupt.