STM32F4 (07VG) Discovery Toolchain for OSX

For those of you who know what you're doing - there is a "Speed Version." Have at it. 

This has been tested on 10.6.8, 10.7.5 & 10.8.2

What is a Toolchain?

A collection of tools to build code. More to the point for us: it is a collection of tools to build code on one platform (your machine) to run on a different platform (your microcontroller). The CrossPack toolchain I have been using is made to build code on my machine that will run on the ATMega324P. Now, we need a toolchain for the Discovery board which is ARM-based. Arm is readily available but the proprietary tools can be  a pain to use - and they generally charge and arm-and-a-leg for those tools. Pun intended. So, we need a compiler, linker, and libraries that will let us develop for ARM - and we want it for free using Open Source tools. 

The 4 flavors of effort

We are going with a combo of Options A & B. We will gather the prebuilt tools - taking advantage of the wheels other people invented - and build a few others so we can start coding instead of fighting other people's tools. 

What You'll Need

Installs & Dependencies  

Homebrew and MacPorts. 

I ended up using both. Homebrew handles some packages better than MacPorts from what I experienced. For instance, you wont be able to run the Macports version of OpenOCD because stlink wont work - but Homebrew's version works great. But MacPorts is more verbose - thus pointing out problems that Homebrew does not. (Like when you have the wrong version of XCode.) 

XCode

If you were just using CrossPack - or developing code at all - you probably already have this. 

Make sure you included the Command Line tools. On 10.7+ you do this by opening XCode -> Preferences -> Downloads -> select "Install" on the Command Line tools

However, while installing this toolchain on a second Mac, I didn't realize until later (while executing  make cross-gcc ) that the machine I was on had XCode 3.2. Because of this I was able to start the build but it failed on the libgcc portion toward the end of the build. Which is annoying because those builds take so long as it is. I discovered the issue because I decided to try just installing arm-none-eabi-gcc with MacPorts. MacPorts pointed out I was using an older version - Note: Homebrew did not know this. It just didn't show me any options for the compiler I was looking for - I decided to keep both MacPorts and Homebrew on my machine for this reason. 

Eclipse (optional).

This is optional but if you like IDEs I will show you how to get it working - or at least set up. 

GCC Dependencies.

Just Use Homebrew:

brew install mpfr gmp libmpc libelf texinfo

arm-eabi-toolchain ZIP File.

Download this from https://github.com/jsnyder/arm-eabi-toolchain 

or, if you have git:

git clone https://github.com/jsnyder/arm-eabi-toolchain.git

Then unzip the file

cd into the directory

Open the README for instructions, which are essentially this:

make install-cross

CC=clang make cross-binutils cross-gcc cross-newlib

make cross-gdb

There are further tweaks available on the page link above if you need them, but I did not. 

This process takes a while....go get coffee, read a book, take a nap....

arm-none-eabi-gcc

This is where I used Macports.  This is because I am trying to keep my environment separated and I know Macports will install this at /opt/local/bin which I then put into my environment setup script as explained later. I am sure there are other ways to do this. Moving on...

sudo port install arm-none-eabi-gcc

OpenOCD.

You'll start OpenOCD when you want to connect to your board. 

brew install openocd

wget

brew install wget

STM32F4 Discovery Firmware and Peripheral files.

wget http://www.st.com/internet/com/SOFTWARE_RESOURCES/SW_COMPONENT/FIRMWARE/stm32f4discovery_fw.zip

wget http://www.st.com/internet/com/SOFTWARE_RESOURCES/SW_COMPONENT/FIRMWARE/stm32f2xx_stdperiph_lib.zip

Unzip the files into your home directory:

unzip stm32f4discovery_fw.zip

unzip stm32f2xx_stdperiph_lib.zip

Makefiles!

THIS is a great example of pre-invented wheels for you. Thank You jthomson.towhee.org

        

wget http://jthomson.towhee.org/stm32f4discovery_files/STM32F4DISCOVERY_Makefiles.zip

Unzip this file in your home directory.  (I have attached a Makefile from this which is edited specifically for use here. You will use my version for now. )

My Attached Files.

Download the attached example Makefile and main.c file. 

Session-based Environments

When you need a couple different compilers and tools on your system, you don't want the key words and other idiosyncrasies that may be *called* the same but *implemented* differently between them to break your work. It can cause confusing problems as you switch between platforms. Instead, create a function in your .bashrc file you can call as you need it. NOTE: This means when you close out of your terminal or terminal session your environment will go back to the way it was before - so you'll need to re-execute the command when you want to develop on this board. 

You can do this by putting something like this in your .bashrc file:

    function stmenv () {

          export PATH="/opt/local/bin:$PATH"

          export STMSDKDIR="$HOME/STM32F4-Discovery_FW_V1.1.0"

     }

*Don't forget to source the file with .~/.bashrc after you save and exit the file!

When you know you are going to be developing for the STM32F4 Discovery board, just open a terminal and type stmenv. If you close this terminal session, keep in mind the need to type this again when you want to develop for this board. 

Just type stmenv in your terminal after you install the arm-none-eabi-gcc below. If you fail to do this (or have an error in the function), you'll probably end up using the compiler at /usr/bin/gcc instead of /opt/local/bin which will just fail when you use make flash. OR, as I ran into a couple times, you will get an error that the st32f4_discovery.h file can't be found. 

The Makefile

Generally if you use an IDE you write some code, press a button, it does something, and then spits out your .bin .hex .elf or whatever file you need. We aren't using an IDE so, like using CrossPack, we use a makefile. 

You need a makefile for each project, just like CrossPack. The difference being CrossPack would graciously create a template makefile for you whenever you started a new project. Here, you can just copy my example (and use it like a template) into your project directories and tweak it to your needs. 

I have already made some tweaks for you:

For starters, when I pulled off an example Makefile from the .zip file off jthomson's site, it was configured for *his* file system. My system is not laid out the same - yours may be different too. So, after learning a little more Make-fu, I abstracted those parts of the Makefile to use my current environment (See the Session-based Environments section.) These changes will likely work great for your system by using your $PATH variable instead of hardcoded paths. Specifically:

I commented out this line and deleted any other references to this TOOLCHAIN_PATH variable:

TOOLCHAIN_PATH:=~/sat/bin

because without it, the path listed in my $PATH variable is used instead. 

I commented out this line:

TOP:=$(shell readlink -f "../..")

and replaced "TOP" with "STMSDKDIR" which stands for the SDK file for the STM board. STMSDKDIR is defined in my .bashrc file by the line:

export STMSDKDIR="$HOME/STM32F4-Discovery_FW_V1.1.0" 

Added this line at the top to use the shell I prefer:

SHELL := /bin/bash

(See the attached copy of my Makefile)

Another thing a makefile is REALLY good for, is automating commands that mess with address handling. For instance, a tutorial I was reading as I worked on this project had you retype the hex-address *every time* you wanted to flash code to the device. That is a VERY easy way to accidentally flash to the wrong address - resulting in potentially catastrophic (or at least confusing) results.  So, after learning how to automate this process from a guru friend, I added these lines to my makefile:

flash: $(TARGET).bin

echo -ne "reset halt\nflash write_image erase $$(PWD)/$< 0x08000000 bin\nreset run\nexit\n" | nc localhost 4444 

I explain the rest of the text later - but see that 0x08000...and-some-more-zeros number? That number is really easy to mistype. And frankly, who wants to remember that command anyway?  So this will allow you to type make flash instead. make flash will first make sure you have the code compiled into a .bin, .hex, etc, push the file to your board with the correct address, then exit the session.  Neat trick, eh? I thought so. Makefiles are great.

Talking to the STM32F4 board

Can your machine see the board?

Let's find out.

Plug in both the mini and the micro usb to your board and your machine. The board will power on and you'll see some Demo code making the LEDs between the buttons flash and rotate in their stock Demo sequence. 

In your terminal session, enter:

system_profiler SPUSBDataType

You should see something like this in the list it presents you:

STM32 STLink:

              Product ID: 0x3748

              Vendor ID: 0x0483  (STMicroelectronics)

              Version:  1.00

              Serial Number: SÿpI€UW‡

              Speed: Up to 12 Mb/sec

              Manufacturer: STMicroelectronics

              Location ID: 0xfa130000 / 6

              Current Available (mA): 500

              Current Required (mA): 100

Great!

Starting OpenOCD

openocd -f /usr/local/share/openocd/scripts/stm32f4discovery.cfg &

The ampersand at the end is telling this to start "in the background". 

If you want openocd to tell you what it's doing as it's doing it remove the ampersand and open another terminal/tab to execute this command as seen below. 

Starting OpenOCD with an absolute path and running it in the fore-ground:

/usr/local/bin/openocd -f /usr/local/share/openocd/scripts/board/stm32f4discovery.cfg

See the which command-use below if you know you have openocd installed and these commands aren't working. It may just mean openocd is in a different directory. 

If you are not running OpenOCD in the background, you should see a bunch of output like this:

... 

libusb: 1.581668 info [op_handle_events] checking fd 8 with revents = 1

libusb: 1.581676 info [darwin_handle_callback] handling bulk completion with kernel status 0

libusb: 1.581686 info [ep_to_pipeRef] converting ep address 0x02 to pipeRef and interface

libusb: 1.581691 info [ep_to_pipeRef] pipe 2 on interface 0 matches

libusb: 1.581951 info [darwin_async_io_callback] an async io operation has completed

libusb: 1.581972 info [op_handle_events] checking fd 6 with revents = 0

libusb: 1.581980 info [op_handle_events] checking fd 8 with revents = 1

libusb: 1.581989 info [darwin_handle_callback] handling bulk completion with kernel status 0

libusb: 1.581998 info [ep_to_pipeRef] converting ep address 0x81 to pipeRef and interface

libusb: 1.582003 info [ep_to_pipeRef] pipe 1 on interface 0 matches

libusb: 1.582142 info [darwin_async_io_callback] an async io operation has completed

libusb: 1.582159 info [op_handle_events] checking fd 6 with revents = 0

libusb: 1.582167 info [op_handle_events] checking fd 8 with revents = 1

libusb: 1.582175 info [darwin_handle_callback] handling bulk completion with kernel status 0

Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints

Boss it around vs interactive mode

Start OpenOCD as above. 

An interactive session with the board can be started with:

telnet localhost 4444

So far, the only time I have used the interactive session is to type "help" to get a list of the commands the board understands. Something VERY handy when I was referencing tutorials for older STM32 board revs that use slightly different commands.

But for just flashing the device using my makefile with make flash, I just want to boss the board around then get out - NOT use an interactive session. You do this with netcat like this: 

echo -ne "flash probe 0\nexit\n" | nc localhost 4444

Don't have netcat? Use Homebrew.

Say "Hello!" with flash probe 0

Enter:

echo -ne "flash probe 0\nexit\n" | nc localhost 4444

You should see a few helpful pieces of info come back from the board, like its ID, Size, and start of the flash area:

????????Open On-Chip Debugger

> flash probe 0

device id = 0x10016413

flash size = 1024kbytes

device id = 0x10016413

flash size = 1024kbytes

flash 'stm32f2x' found at 0x08000000

> exit

Flash Your Hello World (LEDs) 

Plug your board to your machine. Start a terminal session if you have not already. Don't forget to use the stmenv command I explain in "Session-based Environments." 

Rename my Makefile and move it into this directory:

mv Jens_Makefile_Example_STM32F4_Discovery_With_OSX Makefile

mv Makefile /Users/jkniss/STM32F4-Discovery_FW_V1.1.0/Project/Demonstration

Save the original copy of main .c and copy mine to replace it:

mv /Users/jkniss/STM32F4-Discovery_FW_V1.1.0/Project/Demonstration/main.c /Users/jkniss/STM32F4-Discovery_FW_V1.1.0/Project/Demonstration/main.bak

mv main.c  /Users/jkniss/STM32F4-Discovery_FW_V1.1.0/Project/Demonstration/ 

cd into the directory "STM32F4-Discovery_FW_V1.1.0/Project/Demonstration". For me:

    

    cd  /Users/jkniss/STM32F4-Discovery_FW_V1.1.0/Project/Demonstration 

My main.c file is an edited version of the stock demo from the ST.com firmware files you extracted - the same Demo your board runs the first time you plug it in. I simply changed the LED behavior so you can tell your flash was successful just by looking at the board.

From the ../../STM32F4-Discovery_FW_V1.1.0/Project/Demonstration directory, type:

make clean

make flash

NOTE: You should always use make clean before make flash.

Instead of the four rotating and blinking lights you should see two.

The rest I will leave to your research on what to do with this board, where the peripherals are, how to connect things etc. 

Commands You Should Know

which 

    Lets you see where the tool you are looking for has been put in your filesystem. It helps you when you're thinking "did that get put in /opt/local/share? Or /usr/local/share?"

        It will also tell you if you even have the tool you are looking for on your machine. 

        Example: 

                which gcc

             Gives me this: 

                /usr/bin/gcc

--version

        Let's you figure out which version of that tool you have. 

You'll care about this ALOT when you have tried 6 different tutorials that all recommended you instal different things and you can't keep them all straight while you are figuring out which one will actually work. 

        Example:

            gcc --version

        Gives me this: 

            i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)

     

Using Eclipse

If you prefer to use an IDE, go to the following website and start with Step 3 (once you download and open Eclipse). The link to the Eclipse version you want is include in the link below and in the Sites list at the end of this tutorial. JUST do the stuff for Eclipse. 

http://www.alexwhittemore.com/open-source-ide-and-toolchain-for-the-stm32f4-discovery-on-mac-osx-lion/

I don't use IDEs so beyond getting it configured properly as in Alex's tutorial - I can't help you much. 

REFERENCES

This tutorial is based on a smashed-together version of these and on my own experimentation of what worked on my own system:

Thank you Jeff Buttars,  Dangerous Prototypes and Hack A Day

http://www.alexwhittemore.com/open-source-ide-and-toolchain-for-the-stm32f4-discovery-on-mac-osx-lion/  

http://pulkomandy.tk/_/_Electronique/_Discovering%20the%20STM32F3%20Discovery

https://jethomson.wordpress.com/2011/11/17/getting-started-with-the-stm32f4discovery-in-linux/

Helpful Tutorials and pages: 

Homebrew: http://mxcl.github.com/homebrew/

Setting up Eclipse for your Mac (optional): http://www.alexwhittemore.com/open-source-ide-and-toolchain-for-the-stm32f4-discovery-on-mac-osx-lion/

Github arm-eabi-toolchain repository: https://github.com/jsnyder/arm-eabi-toolchain

Eclipse Indigo zip-file page: http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/indigo/R/eclipse-java-indigo-macosx-cocoa.tar.gz

Setting up your toolchain: http://pulkomandy.tk/_/_Electronique/_Discovering%20the%20STM32F3%20Discovery

STM32f4 Peripherals Library: http://www.microcodes.info/getting-st-perhipial-library-in-a-mikroc-arm-project-249245.html

Makefiles and STM32F4 firmware files: https://jethomson.wordpress.com/2011/11/17/getting-started-with-the-stm32f4discovery-in-linux/

More Examples and usage once you get it up and running: http://www.triplespark.net/elec/pdev/arm/stm32.html

Bus-Blaster, JTAG, and flashing with GDB use: http://www.nabiltewolde.com/programming-the-stm32f4-discovery-with/

 

The Speed Version

Get Xcode 4 w/ the Command Line Tools

Get Home Brew

Get MacPorts

Download my Makefile and main.c file to your home directory

mv Jens_Makefile_Example_STM32F4_Discovery_With_OSX Makefile 

mv STM32F4-Discovery_FW_V1.1.0/Project/Demonstration/main.c STM32F4-Discovery_FW_V1.1.0/Project/Demonstration/main.bak

mv Makefile STM32F4-Discovery_FW_V1.1.0/Project/Demonstration

mv main.c STM32F4-Discovery_FW_V1.1.0/Project/Demonstration

From your HOME directory:

brew install mpfr gmp libmpc libelf texinfo wget openocd

sudo port install arm-none-eabi-gcc

wget http://www.st.com/internet/com/SOFTWARE_RESOURCES/SW_COMPONENT/FIRMWARE/stm32f4discovery_fw.zip

unzip stm32f4discovery_fw.zip

wget http://www.st.com/internet/com/SOFTWARE_RESOURCES/SW_COMPONENT/FIRMWARE/stm32f2xx_stdperiph_lib.zip

unzip stm32f2xx_stdperiph_lib.zip

wget http://jthomson.towhee.org/stm32f4discovery_files/STM32F4DISCOVERY_Makefiles.zip

unzip STM32F4DISCOVERY_Makefiles.zip

git clone https://github.com/jsnyder/arm-eabi-toolchain.git  (you might have to unzip this, I can't remember...)

cd arm-eabi-toolchain

make install-cross

export PATH=/Users/<your user>/arm-cs-tools/bin:$PATH  (or add this to your .bashrc or .profile)

CC=clang make cross-binutils cross-gcc cross-newlib    (should work, if not try: CC=/usr/bin/gcc-4.2 make cross-binutils cross-gcc cross-newlib)

make cross-gdb

make clean

cd

vi .bashrc

Add this to the file:

    function stmenv () {

          export PATH="/opt/local/bin:$PATH"

          export STMSDKDIR="$HOME/STM32F4-Discovery_FW_V1.1.0"

     }

Save and Exit the file

source .bashrc

stmenv

cd STM32F4-Discovery_FW_V1.1.0/Project/Demonstration/

Plug in your board

system_profiler SPUSBDataType

Make sure you see the Board

openocd -f /usr/local/share/openocd/scripts/stm32f4discovery.cfg &

echo -ne "flash probe 0\nexit\n" | nc localhost 4444

Make sure you see the Device Info

make clean

make flash

You should see two instead of four LEDs flashing in the center of the board.

ERRATA and Troubleshooting

brew install openocd FAILS

While working on the 10.8.2 version of this, I was building the toolchain on a visiting French professor's machine. Aside from the novel - and speed-bump like - experience of using a French keyboard, I was having some strange issues with things not compiling. Specifically, openocd just wouldn't compile from homebrew. This worked finally:

brew install --use-llvm --fresh openocd 

CC=clang make FAILS

This one was not fun. While working to ge the toolchain up on the 10.8.2 version I couldn't get the CC=clang make cross-binutils cross-gcc cross-newlib builds to work. The problem seems to be that I needed to restart the machine after getting the Command Line tools installed from XCode. When the machine rebooted I also needed to remove the cached versions of the previous build configs...these hang around and the build system will continue trying to use "bad" configurations in what I am guessing is an attempt to save processing time. I would get compiler errors of all kinds. This worked finally:

close the terminal

restart the machine

rm arm-eabi-toolchain/build/binutils/intl/config.cache

rm arm-eabi-toolchain/build/binutils/intl/config.h

make distclean

make clean

CC=clang make cross-binutils cross-gcc cross-newlib