Black magic probe (BMP) on Bluepill (STM32F103C8 Minimum System Development Board)

Why I decided to write this?

I was recommended to use black magic probe (BMP) to flash / debug STM32 chips by friends from base48 hackersapce, so I searched the internet and found that there are several articles describing this procedure, such as:

And here is the github of black magic probe

Looks simple: get sources, compile, flash, but it was not so easy and straightforward as it seemed, here are some of the problems I experienced:

  • as a BMP I was using a clone of STM32F103C8T6: a CS32F103C8T6; I was unable to flash it with ST-LINK
  • when I make ST-LINK able to flash it I found that BMP compiled is >64kB and these chips refuses to flash more than 64kB (real STM32F103C8T6 are reported to be 128kB even datasheet says 64kB) - tried with ST-LINK and also tried to flash DFU first and then use it to flash the rest - both failed as 64kB reached
  • I wanted to use swlink pins already soldered on the bluepill board, so you dont need to solder anything to be able to use BMP as a debugger, but all articles were talking about different pins (PA5, PB14 instead of PA13, PA14)
  • my STM becomes locked showing 0kB of flash, I was unable to erase it or flash it - unlock via openOCD fixed this
  • articles above reccomends you to flash dfu bootloader first (blackmagic_dfu.bin), then connect bluepill via USB and flash the rest (blackmagic.bin) using dfu-util - this was not possible as dfu-util detected that firmware is bigger than reported flash size and refused to start flashing - see Announced versus available Flash size on F103

This article assumes that you have build tools for STM32 already installed, also as git, st-link utility (st-flash), etc...

CS32F103C8T6 clone

The problem why ST-LINK refuses to flash is the fact that this clone is reporting different coreid (0x2ba01477 instead of 0x1ba01477), you can fix this by change of STM32VL_CORE_ID constant in ST-LINK sources (include/stm32.h) and recompile, but even if you supply --flash=0x20000 parametter to force 128kB flash it starts flashing but fail at about 60-70% - it seems that this chip have 64kB of flash only.

Also I had problems to run Arduino LiquidCrystal_PCF8574 library example on this chip - the LCD was never properly initialized, it flashed on reset of bluepill (so there was some communication happening), but never showed any text - I suspect timing problems.

Some reading about STM32 clones:

Fortunatelly I have only 2 such boards using this CS chip and about 10 others with STM chip (bought from different chinesse seller, not sure they are 100% genuie but at least works), so I decided to stop wasting time trying to use this CS clone as it is reported as unreliable and I took different bluepill with STM chip.

If you modified the ST-LINK sources to be able to flash CS chip don't forget to revert changes and recompile, otherwise it will refuse to flash "real" STM chips.

How to unlock chip showing 0 flash size

In case you bluepill wiil become locked and refuse to erase / flash, try these steps to unlock it:

  • install openocd (sudo apt install openocd)
  • move the BOOT0 jumper to position "1"
  • connect locked bluepill to ST-LINK (3V3 to 3V3, SWIO to SWIO, SWCLK to SWCLK, GND to GND)
  • connect ST-LINK to PC
  • run following commnd:
openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c "init" -c "halt" -c "stm32f1x unlock 0" -c "shutdown"

Expected result:

Open On-Chip Debugger 0.9.0 (2018-01-24-01:05)
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
none separate
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.279947
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0xa1000000 pc: 0x1ffff3b6 msp: 0x200000c4
Info : device id = 0x20036410
Info : flash size = 64kbytes
target state: halted
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000003a msp: 0x200000c4
stm32x unlocked.
INFO: a reset or power cycle is required for the new settings to take effect.
shutdown command invoked
  • disconnect power for a short time or press reset button on the bluepill
  • don't forget to move the BOOT0 jumper back to "0" position

Black magic probe for bluepill

  • connect the bluepill to the ST-LINK (3V3 to 3V3, SWIO to SWIO, SWCLK to SWCLK, GND to GND)
  • connect ST-LINK to the PC
  • execute following sequence - please note the "PROBE_HOST=swlink" which is not a typo - as amost all articles recommend you to use "PROBE_HOST=stlink" (with "t"), but the "swlink" option cause that the SWIO / SWCLK pins are mapped to the default SWIO / SWCLK pins which are already soldered on the blupill board by default - so you don't need to solder pins to be able to use debugger, and this also makes life easier as these pins are already labeled as SWIO / SWCLK (also swlink is recommended option for bluepill in blackmagic wiki, dunno why all others ignore this)
$ git clone https://github.com/blacksphere/blackmagic.git
... progress of git ...

$ cd blackmagic

$ make PROBE_HOST=swlink
... progress of make ...

$ ll | grep blackmagic
-rwxrwxr-x  1 buger buger 1030380 dub  5 10:04 blackmagic*
-rwxrwxr-x  1 buger buger   73244 dub  5 10:04 blackmagic.bin*
-rwxrwxr-x  1 buger buger  345604 dub  5 10:04 blackmagic_dfu*
-rwxrwxr-x  1 buger buger    7348 dub  5 10:04 blackmagic_dfu.bin*
-rw-rw-r--  1 buger buger   20727 dub  5 10:04 blackmagic_dfu.hex

$ st-flash erase
st-flash 1.5.1-22-g4ff515e-dirty
2019-04-05T10:11:45 INFO usb.c: -- exit_dfu_mode
2019-04-05T10:11:45 INFO common.c: Loading device parameters....
2019-04-05T10:11:45 INFO common.c: Device connected is: F1 Medium-density device, id 0x20036410
2019-04-05T10:11:45 INFO common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
Mass erasing

$ st-flash write blackmagic_dfu.bin 0x8000000
st-flash 1.5.1-22-g4ff515e-dirty
2019-04-05T10:16:09 INFO common.c: Loading device parameters....
2019-04-05T10:16:09 INFO common.c: Device connected is: F1 Medium-density device, id 0x20036410
2019-04-05T10:16:09 INFO common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
2019-04-05T10:16:09 INFO common.c: Attempting to write 7348 (0x1cb4) bytes to stm32 address: 134217728 (0x8000000)
Flash page at addr: 0x08001c00 erased
2019-04-05T10:16:10 INFO common.c: Finished erasing 8 pages of 1024 (0x400) bytes
2019-04-05T10:16:10 INFO common.c: Starting Flash write for VL/F0/F3/F1_XL core id
2019-04-05T10:16:10 INFO flash_loader.c: Successfully loaded flash loader in sram
  8/8 pages written
2019-04-05T10:16:10 INFO common.c: Starting verification of write complete
2019-04-05T10:16:10 INFO common.c: Flash written and verified! jolly good!

$ st-flash --flash=0x20000 write blackmagic.bin 0x8002000
st-flash 1.5.1-22-g4ff515e-dirty
2019-04-05T10:33:21 INFO common.c: Loading device parameters....
2019-04-05T10:33:21 INFO common.c: Device connected is: F1 Medium-density device, id 0x20036410
2019-04-05T10:33:21 INFO common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
Forcing flash size: --flash=0x00020000
2019-04-05T10:33:21 INFO common.c: Attempting to write 73244 (0x11e1c) bytes to stm32 address: 134225920 (0x8002000)
Flash page at addr: 0x08013c00 erased
2019-04-05T10:33:23 INFO common.c: Finished erasing 72 pages of 1024 (0x400) bytes
2019-04-05T10:33:23 INFO common.c: Starting Flash write for VL/F0/F3/F1_XL core id
2019-04-05T10:33:23 INFO flash_loader.c: Successfully loaded flash loader in sram
 72/72 pages written
2019-04-05T10:33:27 INFO common.c: Starting verification of write complete
2019-04-05T10:33:29 INFO common.c: Flash written and verified! jolly good!

Try to switch BOOT0 jumper to "1" in case that ST-LINK refuse to communicate with the bluepill.

Test it!

  • make sure both BOOT jumpers are in 0 position
  • disconnect ST-LINK
  • conenct bluepill to the PC using uUSB cable
  • use lsusb command to check that USB device "ID 1d50:6018 OpenMoko, Inc" is present
  • check that two serial ports are created /dev/ttyACM0 (for debugging) and /dev/ttyACM1 (for serial)
  • now you have your own BMP!

Try to flash blink from Arduino to another bluepill

  • connect second bluepill to your BMP (5V to 5V, SWIO to SWIO, SWCLK to SWCLK, GND to GND)
  • install / open Arduino and make sure that "Generic STM32F103C series" board is selected
  • open blink exmple ("File" -> "Examples" -> "Basics" -> "Blink")
  • menu "Tools" -> "Upload method" -> "BMP"
  • menu "Tools" -> "Port" -> "/dev/ttyACM0"
  • upload the sketch, output in arduino should look like
Sketch uses 17044 bytes (26%) of program storage space. Maximum is 65536 bytes.
Global variables use 2576 bytes (12%) of dynamic memory, leaving 17904 bytes for local variables. Maximum is 20480 bytes.
Target voltage: ABSENT!
Available Targets:
No. Att Driver
 1      STM32F1 medium density
  • blink should be running = LED blinking

Flash oved gdb and run the code

  • connect second bluepill to your BMP (5V to 5V, SWIO to SWIO, SWCLK to SWCLK, GND to GND)
  • compile miniblink example from libopencm3 and run gdb
$ git clone https://github.com/libopencm3/libopencm3-miniblink
Cloning into 'libopencm3-miniblink'...
remote: Enumerating objects: 154, done.
remote: Total 154 (delta 0), reused 0 (delta 0), pack-reused 154
Receiving objects: 100% (154/154), 26.15 KiB | 0 bytes/s, done.
Resolving deltas: 100% (89/89), done.
Checking connectivity... done.

$ cd libopencm3-miniblink/

$ make
... progress of make ...

$ cd bin/stm32

$ ll | grep bluepill
-rwxrwxr-x 1 buger buger   1040 dub  5 11:31 bluepill.bin*
-rwxrwxr-x 1 buger buger 213272 dub  5 11:31 bluepill.elf*
-rw-rw-r-- 1 buger buger   2976 dub  5 11:31 bluepill.hex

$ arm-none-eabi-gdb -ex "target extended-remote /dev/ttyACM0"
GNU gdb (7.10-1ubuntu3+9) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-none-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Remote debugging using /dev/ttyACM0
(gdb) 
  • in gdb try to scan for the connected target:
(gdb) monitor swdp_scan
Target voltage: ABSENT!
Available Targets:
No. Att Driver
 1      STM32F1 medium density
  • attach the target
(gdb) attach 1
Attaching to Remote target
0x08000176 in ?? ()
  • load the debug binary
(gdb) file bluepill.elf
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from bluepill.elf...done.
  • flash it into target and verify
(gdb) load
Loading section .text, size 0x410 lma 0x8000000
Start address 0x800037c, load size 1040
Transfer rate: 6 KB/sec, 520 bytes/write.
(gdb) compare-sections
Section .text, range 0x8000000 -- 0x8000410: matched.
  • run the blink!
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/jdrozd/temp/bmpa/libopencm3-miniblink/bin/stm32/bluepill.elf 
  • use CTRL+C to stop the program
^C
Program received signal SIGINT, Interrupt.
main () at template_stm32.c:19
19              __asm__("nop");
... led stops blinking now ...
  • continue the program
(gdb) continue
Continuing.
... led continues to blink again ...
  • use help command, "Useful GDB commands" from blackmagic wiki and google to find out more gdb commands
  • use quit command to quit gdb

Test the BMP serial

  • connect second bluepill to your BMP (5V to 5V, SWIO to SWIO, SWCLK to SWCLK, GND to GND)
  • connect also PB6 of BMP to PA10 of the second bluepill (TX-RX)
  • connact also PB7 of BMP to PA9 of the second bluepill (RX-TX)
  • we will use libopencm3-examples, lets prepare them
$ git clone https://github.com/libopencm3/libopencm3-examples.git
... progress of git ...

$ cd libopencm3-examples/

$ git submodule init
Submodule 'libopencm3' (https://github.com/libopencm3/libopencm3.git) registered for path 'libopencm3'

$ git submodule update
Cloning into 'libopencm3'...
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 25049 (delta 0), reused 0 (delta 0), pack-reused 25048
Receiving objects: 100% (25049/25049), 5.49 MiB | 2.11 MiB/s, done.
Resolving deltas: 100% (16441/16441), done.
Checking connectivity... done.
Submodule path 'libopencm3': checked out 'ff9664389bfb560145aa3b36ad8368900c57c3d8'

$ make
... progress of make, very long ...

$ cd examples/stm32/f1/stm32-h103/usart_printf/
  • open file usart_printf.c in text editor
  • search for "usart_set_baudrate(USART1, 230400);" and replace 230400 with 9600
  • replace all "GPIO12" with "GPIO13"
  • save the file and close text editor
$ make clean
$ make
... progress of make, very quick ...

$ arm-none-eabi-gdb -ex "target extended-remote /dev/ttyACM0"
GNU gdb (7.10-1ubuntu3+9) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-none-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Remote debugging using /dev/ttyACM0
0x08000588 in ?? ()

(gdb) file usart_printf.elf 
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from usart_printf.elf...done.

(gdb) attach 1
A program is being debugged already.  Kill it? (y or n) y
Attaching to program: /home/jdrozd/projects/stm32f103/libopencm3-examples/examples/stm32/f1/stm32-h103/usart_printf/usart_printf.elf, Remote target
0x080005c6 in reset_handler () at ../../cm3/vector.c:67
67      for (src = &_data_loadaddr, dest = &_data;

(gdb) load
Loading section .text, size 0x5de8 lma 0x8000000
Loading section .ARM.exidx, size 0x8 lma 0x8005de8
Loading section .data, size 0x8ac lma 0x8005df0
Start address 0x80005c0, load size 26268
Transfer rate: 17 KB/sec, 905 bytes/write.

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/jdrozd/projects/stm32f103/libopencm3-examples/examples/stm32/f1/stm32-h103/usart_printf/usart_printf.elf
  • now the LED on the target should blink quicky
  • open new terminal (keep the terminal with gdb opened in background)
  • execute command "screen /dev/ttyACM1 9600" in the new terminal, you should see incomming "Hello world!" messages with some increasing numbers, like thoose:
Hello World! 4121 41.209091 41.210000
Hello World! 4122 41.219090 41.220000
Hello World! 4123 41.229088 41.230000
  • switch back to gdb terminal and press CTRL-C
  • the LED should stop blinking and "Hello world" messagess should stop also
  • type "continue" and press enter in gdb terminal - LED blinks and messages should start again, notice that numbers in the messages are NOT counting from 0 again but continues from where the program was interrupted

Used SW / HW / Links:

Like my blog? Want to buy me coffee or beer?

LTC (litecoin): LeWzkcV2ArRv7Bi7TmrTpwkp6j2CZSLwfY

BTC (bitcoin): 1LzmUcwHK5Ys4zGPRoxYodjzpJsWiG61JY

DOGE (dogecoin): DQmS6EdDXssriDgSBpQMxYicHTiji6kMhx

ETH (ethereum): 0x387ff39c66e71c454ce5844c188c1a87835d2263

USDT (tether@ETH): 0xa69cae5a1da5ff5fb226e4bc87fe5d0f8c45908a

MANA (decentraland): 0xa69cae5a1da5ff5fb226e4bc87fe5d0f8c45908a

XMR (monero): 4JUdGzvrMFDWrUUwY3toJATSeNwjn54LkCnKBPRzDuhzi5vSepHfUckJNxRL2gjkNrSqtCoRUrEDAgRwsQvVCjZbRxBb8sEWJB1SCCuUEa