This is an exercise project. The two main goals are:
- To get started with GDB on microcontrollers.
- To get started with writing a Makefile for driving GNU Arm Embedded Toolchain (GCC) based project.
The project is inspired by a Debugging Firmware with GDB blog post. And my natural need for learning and having fun, of course. ;-)
In addition, the following statements become true:
- The GCC command line required for compiling a Cortex-Mx based code isn't black magic. Some of the flags aren't obvious at first sight, but they do become after a very short while.
- The OpenOCD command line required for programming and debugging a microcontroller firmware isn't black magic either. It takes a moment to learn, but then typing it becomes your second nature.
The Debugging Firmware with GDB blog post uses nRF52840 development kit (PCA10056) board with Nordic's nRF52840 microcontroller (Cortex-M4).
I, on the other side, use NUCLEO-F091RC development board with ST's STM32F091RCTX microcontroller (Cortex-M0).
Though the boards differ it their nature, any Cortex-Mx board will serve the purpose equally well. The generated assembly will generally differ, because Cortex-M4 (nRF52840) has much richer instruction set than Cortex-M0 (STM32F091), but in this exercise I don't go deep enough for this fact to matter.
![]() |
---|
NUCLEO-F091RC board used in the exercise |
The following host-side cross development tools are in charge of making the experiment possible:
- GNU Arm Embedded Toolchain, which includes GCC (compiler) and GDB (debugger), version 10-2020-q4-major (official binaries).
- Open On-Chip Debugger (OpenOCD) for programming and bridging GDB for remote debugging, version 0.11.0-rc1+dev-00026-gaaa6110d9-dirty (compiled from git source code repository).
The target firmware is based on Debugging Firmware with GDB blog post example, but adapted for STM32 microcontroller. Take a look at the source code found in this repository if you're interested in details.
Basically, it's a simple UART example code to talk with a PC over a serial line. Using terminal emulator on the PC side, an experiment with a conditional breakpoint can be conducted. (It could be without the serial connection as well, but it's way cooler to work on the real hardware.)
$ export PATH+=:/path/to/toolchain/bin
$ make
CC main.c.o
AS startup_stm32f091rctx.s.o
CC system_stm32f0xx.c.o
LINK gdb-for-firmware.elf
$ export PATH+=/path/to/openocd/bin
$ openocd -d0 -f board/st_nucleo_f0.cfg \
-c "program gdb-for-firmware.elf verify reset exit"
Open On-Chip Debugger 0.11.0-rc1+dev-00026-gaaa6110d9-dirty (2021-01-13-19:14)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
debug_level: 0
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x08000108 msp: 0x20008000
** Programming Started **
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
shutdown command invoked
$ arm-none-eabi-gdb gdb-for-firmware.elf
GNU gdb (GNU Arm Embedded Toolchain 10-2020-q4-major) 10.1.90.20201028-git
Copyright (C) 2020 Free Software Foundation, Inc.
(..)
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from gdb-for-firmware.elf...
(gdb) target extended-remote | openocd -d0 -f board/st_nucleo_f0.cfg \
-c "gdb_port pipe; log_output /dev/null"
(gdb) monitor reset halt
(gdb) load
(gdb) monitor reset init