I recently picked up an STM32F0 Discovery board from Digikey, and set about making it work on the Mac. Some documentation I found was slightly outdated for Yosemite and didn’t cover everything needed.

This is what I had to do:

Install libusb

libusb is a library that wraps common USB interactions so that application developers don’t have to tear their hair out dealing with the vagaries of dealing directly with USB. The STLink programming software will use it.

If you don’t already have it, you’ll need to install Homebrew, a package manager for Mac OS X that makes it easy to install popular open-source libraries.

Once Homebrew is installed, open a Terminal and type this:

brew install libusb-compat

After a short period of time, you will be returned to the bash prompt.

Originally intended for Linux, this open-source programmer knows how to speak the ST-Link v2 protocol that the Discovery board uses.

git clone git@github.com:texane/stlink.git
cd stlink
./autogen.sh
./configure
make
sudo make install
# enter your password here..

Once the install has completed, you should be able to type which st-flash and have it return /usr/local/bin/st-flash (or, if you changed the --prefix setting in the configure script, wherever you ended up installing it to.)

The driver is included in the stlink git repository so we’ll unpack and install it while we’re here.

cd stlinkv1_macosx_driver
tar -zxvf osx.tar.gz

Convince Yosemite to load unsigned kernel extensions

Added in recent versions of Yosemite, Apple has attempted to crack down on third-party kernel extensions (such as the STLink driver we’re trying to install) by forcing code signing. If you attempt to install the driver right now, you will end up with some error messages and nothing will happen.

Do this:

sudo nvram boot-args="kext-dev-mode=1"

Now restart your Mac. Don’t forget to come back here!

Modify the osx/install.sh file

Edit the osx/install.sh file in your favorite text editor.

Change the case statement from 10.10) to 10.10*). Change the references to $KEXT to osx/$KEXT.

When you’re done the file should look something like this:

#!/bin/bash

ISOSXLION=$(sw_vers -productVersion)
case $ISOSXLION in
10.6*)
        KEXT="stlink_shield10_6.kext"
    ;;
10.7*)
    KEXT="stlink_shield10_7.kext"
    ;;
10.8*)
    KEXT="stlink_shield10_8.kext"
    ;;
10.9*)
    KEXT="stlink_shield10_9.kext"
    ;;
10.10*)
    KEXT="stlink_shield10_10.kext"
    ;;
*)
    echo "OS X version not supported."
    exit 1
    ;;
esac
chown -R root:wheel osx/$KEXT/
cp -R osx/$KEXT /System/Library/Extensions/stlink_shield.kext
kextload -v /System/Library/Extensions/stlink_shield.kext
touch /System/Library/Extensions

After all that we can finally install the STLink driver. Invoke the following from the stlinkv1_macosx_driver directory:

sudo make osx_stlink_shield

If all goes well, you should see a message about the stlink_shield.kext being successfully loaded.

Test it out

Run the following:

cd ../ # in the root of the git repository
./st-util

You should see something like the following:

2015-07-10T18:46:38 INFO src/stlink-usb.c: -- exit_dfu_mode
2015-07-10T18:46:38 INFO src/stlink-common.c: Loading device parameters....
2015-07-10T18:46:38 INFO src/stlink-common.c: Device connected is: F0 device, id 0x20006440
2015-07-10T18:46:38 INFO src/stlink-common.c: SRAM size: 0x2000 bytes (8 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
2015-07-10T18:46:38 INFO gdbserver/gdb-server.c: Chip ID is 00000440, Core ID is  0bb11477.
2015-07-10T18:46:38 INFO gdbserver/gdb-server.c: Target voltage is 2929 mV.
2015-07-10T18:46:38 INFO gdbserver/gdb-server.c: Listening at *:4242...

Install the GCC ARM tools

  1. Get the Mac installation tarball from here.
  2. Unpack the tarball with tar jxvf to a handy directory (I used $HOME/Code/cross-compilers)
  3. Add the bin directory from the unpacked tarball to your $PATH. Edit your .bash_profile or whatever other file launches for your shell.

Make sure the ARM tools are installed properly

Run the following from a new Terminal window:

arm-none-eabi-gdb

You should see this text, among other things:

GNU gdb (GNU Tools for ARM Embedded Processors) 7.8.0.20150304-cvs
Copyright (C) 2014 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-apple-darwin10 --target=arm-none-eabi".

Install OpenOCD

OpenOCD is a nice tool for pushing your code to the device.

If you clone the OpenOCD git repository and follow the directions in this readme you should be up and running with OpenOCD using stlink.

Now you can start building code and deploying it to the discovery board.

Download the basic template project

Mike Szczys has developed a template project that gets you started on the Discovery.

Clone it from Github and build it. It should succeed, if the ARM tools were installed properly. You should end up with a main.elf file.

If you installed OpenOCD, running make program will install and launch the program on the Discovery board. You can tweak the timing and reinstall it to make sure that it actually did something.

Stuff should be running, congratulations.

Note that I am unsure as to if the ST license allows redistributing the files from the StdPeriph lib. My template project references the ST files in the Makefile without directly including them in the repo. That said, Mike Szczys’ template project was a bona fide life saver on this one and provided missing chunks such as the startup code, OpenOCD configuration files and linker scripts that I copied.

New projects should use his template project if at all possible.

Download the ST standard peripherals library

These files will be important if you want to write code without checking in the StdPeriph lib files, or if you wish to target a different device.

You can go here to get them.

Some important directories:

  • Libraries/CMSIS/Include: Core include files
  • Projects/STM32F0xx_StdPeriph_Templates: Device conf headers
  • Libraries/CMSIS/Device/ST/STM32F0xx/Include: Device headers
  • Libraries/CMSIS/Device/ST/STM32F0xx/Source/Templates: Device library files (statically link against these)
  • Libraries/STM32F0xx_StdPeriph_Driver/inc: Peripheral headers
  • Libraries/STM32F0xx_StdPeriph_Driver/src: Peripheral library (statically link against these too)

Debugging

If you’re anything like me the first time you wrote some code the board didn’t seem to do anything. Don’t worry. The debugger is here.

Once you’ve started the gdb bridge from STLink (in a previous step), launch the ARM GDB and connect to the bridge.

(gdb) target extended-remote :4242
Remote debugging using :4242
Cannot access memory at address 0xffffffff
0x08000358 in ?? ()

You can restart the program from the beginning of execution using monitor reset, and then step, set breakpoints, etc like you would normally in GDB.

If you have never used GDB before, the RMS tutorial is a handy guide.

Symbols can be loaded like this, prior to connecting to the remote:

(gdb) symbol-file blink.elf
Reading symbols from blink.elf...done.
(gdb) target extended-remote :4242
Remote debugging using :4242
0x080003d8 in WWDG_IRQHandler ()

Problems I encountered

Crashing in ____libc_init_array_from_thumb

I failed to provide -mcpu=cortex-m0 and -mthumb to the linker even though I had provided it to the compiler. This apparently caused it to break trying to switch instruction sets.

OpenOCD push failed in ocd_bouncer

I had the gdb-server running at the same time. Killing it let me communicate with the device again and push code to it.

Complaining about missing _exit

There is no _exit in the libc for this device, because where would you exit to on an embedded device?

Stripping sections during linking by passing --gc-sections to the linker ended up taking care of this problem, as it removed the pieces of libc (such as exit) that called these missing implementations.

Special Thanks

The following sources were helpful in figuring this one out: