Fork me on GitHub

Project Notes

#550 Black Magic Probe

Using the Black Magic Probe for debugging ARM/STM32 devices over JTAG and SWD, with a demonstration on MacOSX.

Build

Notes

The Black Magic Probe (BMP) is a JTAG and SWD Adapter used for programming and debugging ARM Cortex MCUs. I got a Black Magic Probe V2.1 from the associated kickstarter but this is my first full test drive. For the examples below, I’m running on MacOSX.

bmp_front

The pictures show the JTAG ribbon connected on the top, and a (slightly skewed!) serial adapter connected on the bottom.

bmp_rear

The Black Magic Probe:

  • plugs into the programming workstation (Windows, Mac, Linux) over USB
  • runs an embedded GDB debug host - no other software required to connect a debugger
  • supports three methods of connecting the target device:
    • JTAG
    • SWD
    • serial

This is all handled by the STM32F103CBUx chip on the BMP itself. Here’s the schematic v2.1:

Schematic

Learning How to Use the BMP

The Black Magic Probe wiki has most of the basics covered. The 1Bitsy & Black Magic Probe Linux Quickstart Tutorial is a good place to start:

clip

Connecting the BMP

After connecting the BMP to USB, two “usbmodem” interfaces are detected by the operating system and each given a tty and character device handle. Note that naming is different than Linux (used in many of the BMP examples).

$ ls -1 /dev/tty.usb*
/dev/tty.usbmodem7BB19AA1
/dev/tty.usbmodem7BB19AA3
$ ls -1 /dev/cu.usb*
/dev/cu.usbmodem7BB19AA1
/dev/cu.usbmodem7BB19AA3

The first interface provides the GDB server, and the second provides a USB to UART adapter. For GDB, I’ll be connecting on the GDB server’s character device /dev/cu.usbmodem7BB19AA1.

Demonstration #1: Programming and debugging the 1bitsy over JTAG

The 1bitsy is an open source STM32F415RGT6 development board (mine came in a bundle with the BMP). Unlike other small boards, it doesn’t skimp on exposing processor pins, including a JTAG header.

The JTAG ribbon cable provided connects directly to the JTAG header on the 1bitsy, but note the orientation.

jtag_programming

I’m going to use the fancyblink program from the 1bitsy-examples for the test. I already have the GNU Arm Embedded Toolchain installed.

Setting up and compiling the examples:

$ git clone https://github.com/1Bitsy/1bitsy-examples.git
$ cd 1bitsy-examples
$ git submodule init
$ git submodule update
$ make
...(etc)...
$ cd examples/1bitsy/fancyblink

Here’s a transcript of a GDB session to program and debug on the 1bitsy:

Start GDB with the ELF of the program I’ll load into the device.

$ cd examples/1bitsy/fancyblink
$ arm-none-eabi-gdb fancyblink.elf

Connect to the BMP debug server, detect the target device with the jtag_scan command and attach it:

(gdb) target extended-remote /dev/cu.usbmodem7BB19AA1
Remote debugging using /dev/cu.usbmodem7BB19AA1

(gdb) monitor version
Black Magic Probe (Firmware v1.6.1) (Hardware Version 3)
Copyright (C) 2015  Black Sphere Technologies Ltd.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

(gdb) monitor jtag_scan
Target voltage: 3.3V
Available Targets:
No. Att Driver
 1      STM32F4xx

(gdb) attach 1
Attaching to program: /Users/paulgallagher/MyGithub/LittleArduinoProjects/Equipment/BlackMagicProbe/1bitsy-examples/examples/1bitsy/fancyblink/fancyblink.elf, Remote target
0x0800032e in rcc_osc_on (osc=RCC_PLL) at rcc.c:493
493     RCC_CR |= RCC_CR_PLLI2SON;

Program the device; only required if I don’t want to monitor the code already installed on the target

(gdb) load
Loading section .text, size 0x688 lma 0x8000000
Loading section .data, size 0xc lma 0x8000688
Start address 0x8000564, load size 1684
Transfer rate: 3 KB/sec, 561 bytes/write.

Run the program, do all of the usual GDB type things: interrupt execution, step, inspect registers etc.

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /Users/paulgallagher/MyGithub/LittleArduinoProjects/Equipment/BlackMagicProbe/1bitsy-examples/examples/1bitsy/fancyblink/fancyblink.elf
^C
Program received signal SIGINT, Interrupt.
0x0800026c in main () at fancyblink.c:60
60      for (i = 0; i < 6000000; i++) { /* Wait a bit. */
(gdb) list
55
56    /* Blink the LEDs (PA8) on the board. */
57    while (1) {
58      /* Toggle LEDs. */
59      gpio_toggle(GPIOA, GPIO8);
60      for (i = 0; i < 6000000; i++) { /* Wait a bit. */
61        __asm__("nop");
62      }
63    }
64
(gdb) cont

So far so good!

Demonstration #2: Programming and debugging the “Blue Pill” over SWD

The STM32F103C8T6 “Blue Pill” has an SWD header instead of JTAG. Debugging with the BMP is no different.

I used the little JTAG to 7-pin JTAG/SWD adapter board provided with the BMP. This makes it easier to wire up the SWD connections on the Blue Pill:

swd_programming

Here’s a transcript of a GDB session to program and debug the Blue Pill. I’m using the blinky.elf from LEAP#549 Bare Metal C on the Blue Pill as my example program.

Start GDB with the ELF of the program I’ll load into the device:

$ arm-none-eabi-gdb blinky.elf

Connect to the BMP debug server, detect the target device and attach it. This is really the only step that is different when using SWD: I’ll use the swdp_scan command to find the device instead of jtag_scan:

(gdb) target extended-remote /dev/cu.usbmodem7BB19AA1
Remote debugging using /dev/cu.usbmodem7BB19AA1
(gdb) monitor swdp_scan
Target voltage: 3.3V
Available Targets:
No. Att Driver
 1      STM32F1 medium density
(gdb) attach 1
Attaching to program: /Users/paulgallagher/MyGithub/LittleArduinoProjects/ARM/STM32F103C8T6/BareMetal/blinky/blinky.elf, Remote target
0x080001a8 in delay (ms=500) at delay.c:7
7   for(uint32_t i = 0 ; i < ms * DELAY_COUNT_1MS ; i++);

Program the device; only required if I don’t want to monitor the code already installed on the target

(gdb) load
Loading section .text, size 0x2ec lma 0x8000000
Start address 0x8000266, load size 748
Transfer rate: 10 KB/sec, 748 bytes/write.

Run the program, do all of the usual GDB type things: interrupt execution, step, inspect registers etc.

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /Users/paulgallagher/MyGithub/LittleArduinoProjects/ARM/STM32F103C8T6/BareMetal/blinky/blinky.elf
^C
Program received signal SIGINT, Interrupt.
0x080001a2 in delay (ms=500) at delay.c:7
7   for(uint32_t i = 0 ; i < ms * DELAY_COUNT_1MS ; i++);
(gdb) list
2
3 #define DELAY_COUNT_1MS      568U
4
5 // Command: a simple do-nothing delay for approximately `ms` milliseconds
6 void delay(uint32_t ms) {
7   for(uint32_t i = 0 ; i < ms * DELAY_COUNT_1MS ; i++);
8 }

Again, works great!

Credits and References

About LEAP#550 ARMJTAGSWD
Project Source on GitHub Project Gallery Return to the LEAP Catalog

This page is a web-friendly rendering of my project notes shared in the LEAP GitHub repository.

LEAP is my personal collection of electronics projects, usually involving an Arduino or other microprocessor in one way or another. Some are full-blown projects, while many are trivial breadboard experiments, intended to learn and explore something interesting (IMHO!).

The projects are usually inspired by things found wild on the net, or ideas from the sources such as:

Feel free to borrow liberally, and if you spot any issues do let me know. See the individual projects for credits where due. There are even now a few projects contributed by others - send your own over in a pull request if you would also like to add to this collection.