Skip to content

🔎 On Chip Software Debugging ðŸŸĄ

JTAG and SWD debuggers are the standard ways to interact with microcontrollers in order to halt their actions, inspect memory, and step through code. It can be used to flash devices, which can sometimes be faster than doing so over serial. Can be used to perform on device line-by-line code debugging which is a powerful tool over print statements when it comes to debugging the state and behavior of a program.

This tutorial uses PyOCD because its easy to use, and easy to install. The other big OCD (on-chip debugging) software is OpenOCD which works as well but is a bit more complicated to use. One issue with PyOCD is that it only works for ARM processors, so it cannot be used for RISC-V, MIPS, XTensa based devices.

To install PyOCD run:

python3 -m pip install pyocd

Connecting to a Debugger

Connect the debugger (STLinkV2) to your MicroMod Carrier board using the STLink to SWD connector adapter. Before connecting and powering everything check that the the ribbon connector is connected to the port with the glowing LED. That is the correct connection. Using the incorrect connection could cause part damage.

If you are using another type of device with different connections follow this guide. A connection to ground (GND) must be made between the debugger and the development board in order for the devices to communicate.

Danger

DOUBLE AND TRIPLE CHECK YOUR CONNECTIONS! Incorrect connects can result in breaking a board, debugger or possible your computer.

Connect jumpers from GND, SWDIO and SWDCLK to the pins on the board. If the board supports both SWD and JTAG like many arm cortex boards do, then connect the pins in the following way:

  • SWDIO --> TMS
  • SWDCLK --> TCK

Connect jumpers from the GND, TDI, TMS, TCK, and TDO pins on the JTAG debugger to the headers on the development board of the same name.

Using GDB

If you do not know how to use GDB here is a GDB Cheat Sheet.

You should be able to add breakpoints to add breakpoints at this point. A typical first breakpoint for a program is to set a breakpoint on main.

>>> break main

Next you will want to reset the program back to the start and halt the CPU using the following command.

>>> monitor reset halt

To begin running through the program use the continue command.

>>> continue

At this point you should see the source code of your main.cpp show up. Now you can step through your code and set breakpoints using step, next, finish and continue, break, etc.

Typically you would use the run command to start the code. When performing firmware testing, the run command is not needed as the code is already "running" on the remote microcontroller.

Info

On boards with a factory bootloader, when you start debugging, you will notice that you cannot see the source code lines in the gdb shell. This is because the bootloader instructions are not associated with any addresses in your code, thus you will not see source code. This is fine. Continue with the guide. The LPC40xx family of microcontrollers has such a bootloader.

Tip

Highly recommend using tui enable or gdb-dashboard which is an awesome tool for making command line gdb debugging easier.

Using print and set variable commands

A very helpful command for GDB is the print command.

>>> print a + 123

The statement above takes any expression and will print its result. For example one could do something like this:

>>> print reg.TIM1.CCER

The above expression will print the TIMER1 CCER register value.

Tip

If you get an error like:

Cannot access memory at address ???

This happens because GDB is limiting access to memory that is known at link time and is apart of the binary's structure. But if a user wants to access peripheral memory not associated with RAM or Flash memory then they can execute this command:

set mem inaccessible-by-default off

You can also use the set variable command to actually change those values. For example, if you are within a loop you force the loop i iterator variable to 5. You can also change register values as well.

>>> set variable i = 5
>>> set variable reg.USART1.CR1 = 1