Full disclosure: I work at ST Microelectronics, but what I write here is purely my opinion and my work, conceived and conducted in my spare time.
The ST Nucleo boards are development platforms mounting an STM32 microcontroller, made for the same enthusiasts that are attracted to Arduino and the like. They have between 64KiB and 512KiB of embedded Flash, up to 128KiB of RAM, up to around 100MHz of clock, ARM Cortex-M 32bit processor, an integrated programmer/debug adapter called ST-Link, Arduino-compatible connectors as well as a breakout pins that export all STM32 I/O, and their price is around 10$. Their intended development platform is ARM mbed, that allows to write code and build programs online, using a quite simple API that abstracts away many details of the platform, making it easy to start, and easy to share code and experience with the mbed community.
I have my hands on a Nucleo F103RB, that mounts an STM32F103RB microcontroller, and I wanted to try it on my Linux box. The first thing I did was plugging it in. The unusual thing about the Nucleo boards is that they appear, at the USB interface, as three different devices: a storage disk with its file system, a serial port and a debugging interface. This is how it appears:
$ dmesg ... [ 1209.124022] usb 3-2: new full-speed USB device number 3 using uhci_hcd [ 1209.296729] usb 3-2: New USB device found, idVendor=0483, idProduct=374b [ 1209.296734] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [ 1209.296738] usb 3-2: Product: STM32 STLink [ 1209.296741] usb 3-2: Manufacturer: STMicroelectronics [ 1209.296744] usb 3-2: SerialNumber: 066EFF534951775087044835 [ 1210.582585] usb-storage 3-2:1.1: USB Mass Storage device detected [ 1210.582770] scsi10 : usb-storage 3-2:1.1 [ 1210.582887] usbcore: registered new interface driver usb-storage [ 1210.604091] cdc_acm 3-2:1.2: This device cannot do calls on its own. It is not a modem. [ 1210.604113] cdc_acm 3-2:1.2: ttyACM0: USB ACM device [ 1210.605778] usbcore: registered new interface driver cdc_acm [ 1210.605781] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters [ 1211.584633] scsi 10:0:0:0: Direct-Access MBED microcontroller 1.0 PQ: 0 ANSI: 2 [ 1211.585468] sd 10:0:0:0: Attached scsi generic sg3 type 0 [ 1211.590616] sd 10:0:0:0: [sdc] 304 512-byte logical blocks: (155 kB/152 KiB) [ 1211.593610] sd 10:0:0:0: [sdc] Write Protect is off [ 1211.593615] sd 10:0:0:0: [sdc] Mode Sense: 03 00 00 00 [ 1211.596613] sd 10:0:0:0: [sdc] No Caching mode page found [ 1211.596618] sd 10:0:0:0: [sdc] Assuming drive cache: write through [ 1211.621623] sdc: [ 1211.638608] sd 10:0:0:0: [sdc] Attached SCSI removable disk $ lsusb ... Bus 003 Device 006: ID 0483:374b STMicroelectronics ...
The debugging interface doesn’t seem to appear, but the serial is created as “/dev/ttyACM0
” and the disk as a SCSI adapter in “/dev/sdc
“. In order to upload and flash code into the microcontroller it is sufficient to copy the binary file into the storage, and ST-Link will flash it and delete the file. It’s very simple and works out of the box in Linux, except for the fact that in my Debian testing computer it asked me for root permission before mounting it, but I solved this issue later…
The mbed website suggests to update the board with the latest firmware, but the downloads offer a Windows EXE updater and a Windows DLL as a driver. A quick Internet search didn’t provide solutions so I decided to skip the update hoping it will work anyway.
(Trying to) connect with OpenOCD 0.7.0
I wanted to see if I could connect to the STM32 with OpenOCD (like I did with Olimex STM32P), so I tried to see how the platform is supported.
At a first glance it seems that the OpenOCD that I have installed (0.7.0) already contains some configurations for ST-Link and STM32F1x, which looks like what I need. The scripts are usually installed in “/usr/share/openocd/scripts/
” directory, which is also the directory from where OpenOCD searches for its configuration files.
I tried the following command, that specifies ST-Link as the interface, and a generic stm32f1x as the target, showing some debug information (level 3):
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x_stlink.cfg -d3
But OpenOCD did not find the board. By looking at ST-Link configuration file it’s clear that it expected Product ID 0x3748 but this board appears as 0x374b. To correct the PID to the one we saw earlier I ran:
$ openocd -f interface/stlink-v2.cfg -c "hla_vid_pid 0x0483 0x374b" -f target/stm32f1x_stlink.cfg -d3
But the configuration failed at “stlink_usb_open()
“, and by a quick search it seems to fail because I did not have permission to open the device. Usually OpenOCD solves this issue by creating an udev rule file in “/lib/udev/rules.d/60-openocd-custom.rules
” that gives the plugdev
group the necessary permissions. I decided to create a new udev rule file called “/etc/udev/rules.d/60-openocd-custom.rules
” with just the following content for ST-Link product:
ACTION!="add|change", GOTO="openocd_rules_end" SUBSYSTEM!="usb|tty|hidraw", GOTO="openocd_rules_end" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="664", GROUP="plugdev" LABEL="openocd_rules_end"
But running the same command OpenOCD complained with the following message:
... Debug: 164 7 stlink_usb.c:1233 stlink_usb_open(): stlink_usb_open Debug: 165 7 stlink_usb.c:1251 stlink_usb_open(): transport: 1 vid: 0x0483 pid: 0x374b Error: 166 10 stlink_usb.c:1279 stlink_usb_open(): read version failed Debug: 167 10 hla_layout.c:49 hl_layout_open(): failed Debug: 168 10 command.c:631 run_command(): Command failed with error code -4 User : 169 10 command.c:669 command_run_line(): in procedure 'transport' Debug: 170 10 command.c:631 run_command(): Command failed with error code -4 User : 171 10 command.c:669 command_run_line(): in procedure 'init'
It turns out ST-Link/V2 and ST-Link/V2-1 are different in the USB device enumeration, and the OpenOCD 0.7.0 version I was using did not have support for ST-Link/V2-1.
Connecting with OpenOCD 0.8.0
So I upgraded to OpenOCD 0.8.0 that, in its changelog, explicitly mentions ST-Link/V2-1. In fact it works!
$ openocd -f interface/stlink-v2-1.cfg -f target/stm32f1x_stlink.cfg Open On-Chip Debugger 0.8.0 (2014-10-20-22:02) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : This adapter doesn't support configurable speed Info : STLINK v2 JTAG v23 API v2 SWIM v6 VID 0x0483 PID 0x374B Info : using stlink api v2 Info : Target voltage: 3.264064 Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
As cleanup, I removed my udev
rule file because OpenOCD already installs a new rule for this adapter. It seems to me that another effect of adding this rule is that Nucleo USB disk storage can be mounted without root permissions.
GDB debugging
I wanted to see if I could debug the device, so I prepared this OpenOCD configuration file that I called “gdb-pipe.cfg
“:
gdb_port pipe log_output openocd.log $_TARGETNAME configure -event gdb-detach { echo "Debugger detaching: resuming execution." resume }
The script uses a functionality that creates a communication pipe for GDB and writes the output to a file instead of standard output. The “detach” configuration is useful because when GDB disconnects from the target I want the program to continue, and not to stay halted.
Then I prepared a GDB script “attach.gdb
” that contains:
target remote | openocd -f interface/stlink-v2-1.cfg -f target/stm32f1x_stlink.cfg -f gdb-pipe.cfg monitor halt monitor gdb_sync stepi
The script runs OpenOCD and communicates with it through a pipe, then synchronizes with the running target and stays halted. I then connected to the STM32 with the GDB from the GCC ARM Embedded toolchain. Here is an example of a debugging session:
$ arm-none-eabi-gdb --command=attach.gdb GNU gdb (GNU Tools for ARM Embedded Processors) 7.6.0.20131129-cvs Copyright (C) 2013 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=i686-linux-gnu --target=arm-none-eabi". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Open On-Chip Debugger 0.8.0 (2014-10-20-22:02) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html 0x00000000 in ?? () target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x81000000 pc: 0x0800288c msp: 0x20004ff0 stepi ignored. GDB will now fetch the register state from the target. Program received signal SIGINT, Interrupt. 0x0800288c in ?? () (gdb) info registers r0 0x7a412 500754 r1 0x19b62cba 431369402 r2 0x40000824 1073743908 r3 0x2cbb 11451 r4 0xf4240 1000000 r5 0x19ae88a9 430868649 r6 0x20 32 r7 0x14 20 r8 0xdffd6fde -537038882 r9 0xbffbfeff -1074004225 r10 0x48c30094 1220739220 r11 0x88dd0a7c -1998779780 r12 0x40013400 1073820672 sp 0x20004ff0 0x20004ff0 lr 0x8002891 134228113 pc 0x800288c 0x800288c xPSR 0x81000000 -2130706432 (gdb) continue Continuing. ^C Program received signal SIGINT, Interrupt. 0x08002890 in ?? () (gdb)
Flashing a binary program
I wanted to see if I could also flash the binary with OpenOCD; it’s not a crucial functionality since the binary can also be flashed by copying it into the disk storage, but it’s a good indication that thing works well. I took a binary file created and compiled with mbed with the following procedure:
- Add platform ST Nucleo F103RB to mbed compiler
- Create new program from template Blinky LED Hello World
- Compile it and it will download the binary program.
The downloaded binary is called “Nucleo_blink_led_NUCLEO_F103RB.bin
“, so I prepared the following OpenOCD script called “flash_blink.cfg
“:
init reset init halt flash write_image erase Nucleo_blink_led_NUCLEO_F103RB.bin 0x08000000 shutdown
The script writes the binary at the beginning of the flash; the address is taken from the STM32F1X user manual. Then I flashed the device successfully with the following command:
$ openocd -f interface/stlink-v2-1.cfg -f target/stm32f1x_stlink.cfg -f flash_blink.cfg Open On-Chip Debugger 0.8.0 (2014-10-20-22:02) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : This adapter doesn't support configurable speed Info : STLINK v2 JTAG v23 API v2 SWIM v6 VID 0x0483 PID 0x374B Info : using stlink api v2 Info : Target voltage: 3.267240 Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x08000108 msp: 0x20005000 auto erase enabled Info : device id = 0x20036410 Info : flash size = 128kbytes target state: halted target halted due to breakpoint, current mode: Thread xPSR: 0x61000000 pc: 0x2000003a msp: 0x20005000 wrote 12288 bytes from file Nucleo_blink_led_NUCLEO_F103RB.bin in 0.957933s (12.527 KiB/s) shutdown command invoked
After manually pressing the Reset button the user LED on the Nucleo board starts to blink as expected.
Conclusions
In conclusion, I found out that is pretty easy to use the new Nucleo boards (I assume the other boards are the same as mine) on Linux, with the exception of firmware upgrade . Next time I will try to write and compile some C program outside of mbed development environment and flash it on board, but I don’t foresee any problems since I already did something similar on an STM32 in a previous blog post.
Caleb Reister
2016/01/25
I was able to get my Nucleo F446RE running using this post, your STM32-P152 with GDB post with a few minor tweaks (such as changing stm32f1x_stlink to stm32f4x_stlink). For whatever reason, you need to run an instruction before the source code can actually be viewed in gdb. I was then able to make a breakpoint and step through the code. I am running Arch Linux with OpenOCD 0.9.
Salvatore
2016/07/10
Hi, great article I really liked it!
I’m trying the same board on an Ubuntu 15.10 virtual machine (virtual box) but after few seconds that I connect the board it disconnects… I think the problem is with the cdc_acm driver because i get the following from dmesg:
[ 3893.189906] sd 15:0:0:0: Attached scsi generic sg2 type 0
[ 3893.208147] sd 15:0:0:0: [sdb] 1072 512-byte logical blocks: (548 kB/536 KiB)
[ 3893.221174] sd 15:0:0:0: [sdb] Write Protect is off
[ 3893.221182] sd 15:0:0:0: [sdb] Mode Sense: 03 00 00 00
[ 3893.233568] sd 15:0:0:0: [sdb] No Caching mode page found
[ 3893.233573] sd 15:0:0:0: [sdb] Assuming drive cache: write through
[ 3915.828904] cdc_acm 1-2:1.2: failed to set dtr/rts
[ 3920.992200] cdc_acm 1-2:1.2: failed to set dtr/rts
[ 3930.992450] cdc_acm 1-2:1.2: failed to set dtr/rts
[ 3932.827672] usb 1-2: USB disconnect, device number 35
Everything works until the last error message…
What kernel version did you used?
Thank you
Salvatore
Balau
2016/07/12
Currently my Debian is at kernel 4.6.0 but it worked on previous kernels too. This is my dmesg:
[ 9386.692017] usb 3-1: new full-speed USB device number 4 using uhci_hcd
[ 9386.865641] usb 3-1: New USB device found, idVendor=0483, idProduct=374b
[ 9386.865647] usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 9386.865651] usb 3-1: Product: STM32 STLink
[ 9386.865654] usb 3-1: Manufacturer: STMicroelectronics
[ 9386.865658] usb 3-1: SerialNumber: 066EFF515456707067173043
[ 9387.415035] cdc_acm 3-1:1.2: ttyACM0: USB ACM device
[ 9387.416755] usbcore: registered new interface driver cdc_acm
[ 9387.416760] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[ 9387.459651] usb-storage 3-1:1.1: USB Mass Storage device detected
[ 9387.459733] scsi host10: usb-storage 3-1:1.1
[ 9387.459849] usbcore: registered new interface driver usb-storage
[ 9387.468486] usbcore: registered new interface driver uas
[ 9388.459585] scsi 10:0:0:0: Direct-Access MBED microcontroller 1.0 PQ: 0 ANSI: 2
[ 9388.460308] sd 10:0:0:0: Attached scsi generic sg3 type 0
[ 9388.464591] sd 10:0:0:0: [sdc] 1056 512-byte logical blocks: (541 kB/528 KiB)
[ 9388.467592] sd 10:0:0:0: [sdc] Write Protect is off
[ 9388.467597] sd 10:0:0:0: [sdc] Mode Sense: 03 00 00 00
[ 9388.470585] sd 10:0:0:0: [sdc] No Caching mode page found
[ 9388.470591] sd 10:0:0:0: [sdc] Assuming drive cache: write through
[ 9388.497584] sdc:
[ 9388.512573] sd 10:0:0:0: [sdc] Attached SCSI removable disk
[ 9394.177359] FAT-fs (sdc): utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive!
It’s also possible that it is an issue with Virtualbox not redirecting the USB correctly from host to guest.
Salvatore
2016/07/13
After not so few struggles and tests I finally found the problem!
It’s not a problem with Virtual Box but the ST-Link Firmware Version…
After an update everything is correctly working.
Thank you,
Salvatore
Alex Kogan
2017/02/09
Hi, I’m using a similar STM32 board connected to a Raspberry Pi. To flash the MCU I drop a binary file to a mounted drive. The problem is that it takes a random, and sometimes long time, from the moment I drop the file to the actual moment the MCU is flashed. Did you experience the same phenomena?
Balau
2017/02/09
sorry, mine did not behave this way. in my case it was not important since I prefer to use openocd anyway.
sakthi
2018/04/06
I have NUCLEO-F429ZI board. Can you share opeocd command.
@ openocd -f interface/stlink-v2-1.cfg -f target/stm32f4x_stlink.cfg
i got error message like
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
WARNING: target/stm32f4x_stlink.cfg is deprecated, please switch to target/stm32f4x.cfg
Info : auto-selecting first available session transport “hla_swd”. To override use ‘transport select ‘.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 2000 kHz
adapter_nsrst_delay: 100
none separate
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : clock speed 1800 kHz
Info : STLINK v2 JTAG v28 API v2 SWIM v17 VID 0x0483 PID 0x374B
Info : using stlink api v2
Info : Target voltage: 3.245759
Error: init mode failed (unable to connect to the target)
in procedure ‘init’
in procedure ‘ocd_bouncer’
Kindly give suggestion to sort out this error
Thanks advance