Beginner’s Look At On-Chip Debugging

As your embedded applications get more complicated an On-Chip Debugger will save you a lot of time when things don’t run quite right. On-Chip Debugging (OCD) is just what it sounds like — a way to run your program on the target chip that lets you pause execution to examine values and change them if need be. The Arduino has no built-in method of using OCD, but the AVR chips used by the boards do. The caveat is that you need a proper AVR programmer to access the Debug Wire protocol, or a JTAG interface for some of the larger chips. In this case I’m going to be using an STM32 Discovery Board to give you an overview of OCD. But this will work the same way for any chip that has hardware debugging capabilities. Many IDE’s have debugging support built right in so that you can use a nice GUI as you work. But often these are just a front end for the command line tools I’ll be using. Join me after the break and we’ll get started.

Why use On-Chip Debugging?

Recently I was programming a game of Snake on an ARM chip. I had it working and could play for a few minutes but then things would go very wrong. It was most likely a bug in the code, but it could have been a memory problem cause by the startup or linker scripts, a typo, or a bunch of other things. Using OCD I was able to locate and fix the bug in under five minutes. As with software debugging all it took was to put a break point at a part of the program that was my best guess of the problem. This narrowed things down immediately and all I had to do was scan about twenty lines of code to pinpoint my mistake.


In order to do this type of debugging you need three things: a program that controls the chip’s debugging mode, a way to interface with it, and a program which has been compiled with debugging information.

The interface part is easy, we’ll be using GDB (GNU Debugger). In almost every case this program is included in the same toolchain as the GCC compiler. Since GDB is used in almost universal circumstances it’s well worth your time to learn how to use. If you’re a software person it’s likely you already have.

In my case I’m using OpenOCD to control my ARM processor’s debugging features. It provides a port through which GDB connects. The platform supports a huge range of chips so a little searching should lead you to the commands/config files necessary to talk to different chips. In my case the STM32-Discovery F0 board has support built-in.

To compile with debugging information simply add the ‘-g’ compiler flag when using GCC. For me this merely affects the .elf file so I always include this flag in my makefile.

Getting Everything Running

Prerequisites: I won’t cover installing a toolchain or OpenOCD. I did some work putting together a template for developing STM32 F0 projects on Linux. There are instructions in the readme that detail acquiring a toolchain and compiling OpenOCD with ST-LINK support.

Critical Prerequisite: Whenever debugging you need to make sure you have compiled your program using the ‘-g’ flag. This rolls the information GDB needs to associate your C code with the machine code running on the chip.

Launch OpenOCD

With the debugging hardware connected (in the case of a Discovery board just plug it into a USB port) I start OpenOCD, specifying the board specific configuration to use. OpenOCD comes with a lot of board files. It’s going to be very rare for you to be the first one debugging any type of hardware so a ready-made configuration file should be available. Here’s the command I use for the Discovery board:

openocd -f /usr/share/openocd/scripts/board/stm32f0discovery.cfg

OpenOCD should now be running, time to launch GDB.

Launch GDB and connect to OpenOCD

When launching GDB it’s a good idea to tell it which debugging file to use. This will be the ‘.elf’ file generated when you compiled code with the ‘-g’ flag. It is very important that you do not use the simple command ‘gdb’. This will indeed launch the GNU Debugger, but not the one necessary for ARM debugging. For that we need to use the command for the cross compiled toolchain used to compile the ARM code:

arm-none-eabi-gdb main.elf

Once GDB starts up we need to tell it to connect to our target chip. This is done with a couple of keywords, and a port on which OpenOCD has been listening:

target remote :3333

Now we are connected and can use the GDB commands to start debugging.

Using GDB

Theoretically you can make changes to your program and flash it onto the chip while debugging. The software tools I have don’t offer that capability for this hardware (this is a newer chipset and it’s been a long time since I compiled OpenOCD so this may have changed). Here’s some general commands which should work with most chips:

  • file  – tell GDB which file to use for debugging (I passed this as an argument when launching GDB)
  • load – flash the binary onto the chip (doesn’t work for me with the STM32F0Discovery board)
  • monitor – send special commands to the server (OpenOCD)

I use the monitor command to control the chip. To reset the chip (after setting break points, etc) the command ‘monitor reset halt’ tells OpenOCD to reset the ARM processor but do not start program execution yet.

The basic commands you will use while debugging include:

  • continue – start program execution and don’t stop unless a breakpoint/watchpoint/etc. is reached
  • break – add a breakpoint. This can be specified as the name of a function, or a line of code. When execution reaches this point the processor will be halted and you can check on your data
  • print – prints the value of a variable or memory address. Use this to see what’s up with your code
  • display – cause the ‘print’ command to be executed on a specified variable every time a break point is reached

There are just way too many commands to outline here. The majority of GDB commands are platform-agnostic, so searching for tricks and tips should be pretty simple. I find the best tool is this GDB Refcard (PDF). I’ll let you take a look at it yourself, but one important thing to note is the difference between the ‘next’ and ‘step’ commands. Next will let the processor run until the next line of code is reached, honoring function calls if they occur. Step will do the same but it will not follow any function calls.

The best bet is to watch the demo video, then give debugging a try for yourself. Help is just a Google search away, and the tricks of the trade are easy to learn. Good luck!

20 thoughts on “Beginner’s Look At On-Chip Debugging

  1. The video goes smoothly for some time and then stops and then continues. This happens periodically.

    The voice is OK.

    The situation is really disturbing.

    Is it just me or anyone having this issue also?

    Great material btw.

      1. Plays perfectly fine here.
        I beleve the problem is that youtube’s (or flash’s) requrements for the viewer’s computers have gone higher lately, as I have also had that problem with older single core machines, that previously did not have any problems playing 480p and now even 360p is laggy.
        Although it is playing fine on my core2duo, even I see about 40% rise on my cpu usage when I play any youtube video, so it is not very hard to imagine, that if you have an older processor and some more tabs open in Firefox, the cpu usage will max out.

      2. OT: If youre using Chrome, go to about:plugins, click the Details + button and disable one of the TWO INSTANCES OF FLASH Chrome has had installed for the last two or three versions. Restart Chrome, problem solved. Ive done this on about 10 computers now . Its annoying and I havent had the time to track down when/why it started.

      3. I have a 6 core cpu so I don’t think the cpu is the bottleneck :P

        I can play normal 1080p content locally without any glitching, so I suspect this is still something to do with buffering.

    1. UnaB’s fix works :) There is Windows Flash and Chrome has its own. I would recommend keeping chrome’s. As others have noted, flash has been bumped up again and our little single core laptops need some coaxing :) Also double check your power management and make sure the cpu isn’t being throttled. On older laptops that have a 5 min “oh crap” battery, I just set it to desktop/always on and disable speedstep in the bios. While in the bios , double check your shared video RAM and boost if you can. I also usually just disable LPT and serial ports to free up IRQs but this is a habit from the old days of MIDI trickery lol.

  2. remember to use -g only for the image you pass to gdb, not the firmware you load into the device (if it can grok elf).

    Also another very critical prerequisite for C programs is -O0 (which is usually default). But if you use -Os or something, you can get very unpredictable debugging results.

    This btw. makes debugging some code on avrs for example almost impossible, as they often rely on -Os to fit the image in there.

    But.. it is very possible and comfy to debug simple optimized C programs in assembly, if you know roughly what to expect.
    Use objdump -dS on the optimized .elf file with debugging info and you’ll roughly see what assembly code was produced for what C code.

    1. You don’t need to use ‘-g’ “only for gdb”. All that the -g option does it to add an additional debugging section, which will never get flashed to your device.

      Also, using ‘-O0’ for debugging makes it easier, true, but it might also make it less realistic, as it’s relatively easy to get corner case bugs that only occur at some debugging levels.

    1. I agree. Debugging from the command line is painful, especially for beginners. Eclipse can be a little hard to set up, though. has an eclipse based IDE that uses gcc/gdb and incorporates ST’s ST-Link for JTAG. Awful name, but seems like decent software.

    1. I’ve got a $10 altera usb-blaster clone from ebay that compatible with openocd, would love to give a try for software debugging!

      Does OpenOcd or UrJtag (not sure the difference) work with STM32F4DISCOVERY Kit?

      None of the common boards I’ve seen have a jtag connector (raspberry pi, pandaboard, cubie, ODROID-U2, udoo , CooperKit, EzSBC, NanoPC Radxa Rock, AM335x* etc).

      The beaglebone black has a usb jtag “EMULATOR” (??) as well as provisions for a standard jtag header… unfortunately, it seems most people would use that header with TI’s CCS (baremetal compiler instead of the gnu compiler), so getting it work with Eclipse and OpenOCD might be an uphill battle!


  3. Using OCD and gdb seems like fighting war with swords these days. IAR and Keil have wonderful graphical tools that can do all this and lot more at no expense and in 1/10th of time. Both are free for 32 kb code and I am yet to exhaust the resource to that extent.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.