STM32 Notes

Here are my ongoing notes for getting a few things working with 32-bit ARM Cortex-M4 microcontrollers.  It’s complicated because there seem to be 5 ways to do everything, and a complicated web of semi-outdated or too-specific tutorials online.  This is my contribution to that trend…

Background

I’m trying to get things working on an ST F3 discovery board.  Most of the steps should generalize, but I haven’t gone through and verified it.  In particular, the makefiles I’ll link below haven’t been simplified for easy switching across processor types (though in principle that’s no problem).

I’m working on an Ubuntu 12.04 system with a bunch of standard development packages already installed, so it’s possible I missed install instructions for some prerequisites.

Build toolchain

I starting working off these two tutorials, updating things a bit with information from other pages.

There are a lot of commercial development environments on Windows, and a few of them might have free trial editions.  On Linux, popular options are the CodeSourcery package, which is somewhat limited but might be easier to get working.  Another choice is the gcc-arm toolkit, and you can find old scripts to get and build the toolchain from scratch.  A better option is to use the prebuilt binaries at this Ubuntu PPA:

$ sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded
$ sudo apt-get update
$ sudo apt-get install gcc-arm-none-eabi

Now you have arm-none-eabi-gcc ready to go.

Compiling code

I downloaded the firmware example package from ST, specific to the F3 Discovery board.

$ wget http://www.st.com/st-web-ui/static/active/en/st_prod_software_internet/resource/technical/software/firmware/stm32f3discovery_fw.zip
$ unzip stm32f3discovery_fw.zip

They have nice project files for a bunch of Windows IDEs, but that’s not as useful to us here.

I hacked up a makefile I found from another source to use the newly-installed gcc-arm binaries and link in the required source files for the USB_Example project.  You can skim the XML in the MDK-ARM/USB_Example.uvproj file to see what the include directories and linked source files should be, but that’s kind of a pain.

Here’s the makefile that should go in the Project/Peripheral_Examples/USB_Example directory (paths are relative to it being there, alas).  It’s not really optimized since I don’t know enough about their libraries.  There’s a lot of extra stuff in this example because it’s bringing in their USB and accelerometer interface libraries as well.

TARGET:=USB_Example
TOOLCHAIN_PREFIX:=arm-none-eabi
OPTLVL:=3 # Optimization level, can be [0, 1, 2, 3, s].

PROJECT_NAME:=$(notdir $(lastword $(CURDIR)))
TOP:=$(shell readlink -f "../../..")
DISCOVERY:=$(TOP)/Utilities/STM32F3_Discovery
STMLIB:=$(TOP)/Libraries
STD_PERIPH:=$(STMLIB)/STM32F30x_StdPeriph_Driver
STARTUP:=$(STMLIB)/CMSIS/Device/ST/STM32F30x/Source/Templates/gcc_ride7
LINKER_SCRIPT=$(CURDIR)/TrueSTUDIO/USB/STM32_FLASH.ld

INCLUDE=-I$(CURDIR)
INCLUDE+=-I$(STMLIB)/CMSIS/Include
INCLUDE+=-I$(STMLIB)/CMSIS/Device/ST/STM32F30x/Include
INCLUDE+=-I$(STMLIB)/STM32_USB-FS-Device_Driver/inc
INCLUDE+=-I$(STD_PERIPH)/inc
INCLUDE+=-I$(DISCOVERY)

# vpath is used so object files are written to the current directory instead
# of the same directory as their source files
vpath %.c $(DISCOVERY) $(STD_PERIPH)/src
vpath %.s $(STARTUP)

ASRC=startup_stm32f30x.s

# Project Source Files
SRC=stm32f30x_it.c
SRC+=system_stm32f30x.c
SRC+=main.c

# Discovery Source Files
SRC+=stm32f3_discovery.c

# Standard Peripheral Source Files
SRC+=hw_config.c
SRC+=usb_desc.c
SRC+=usb_endp.c
SRC+=usb_istr.c
SRC+=usb_prop.c
SRC+=usb_pwr.c

SRC+=$(wildcard $(STMLIB)/STM32_USB-FS-Device_Driver/src/*.c)
SRC+=$(wildcard $(STD_PERIPH)/src/*.c)
SRC+=$(DISCOVERY)/stm32f3_discovery_lsm303dlhc.c

CDEFS=-DSTM32F30X
CDEFS+=-DUSE_STDPERIPH_DRIVER

MCUFLAGS=-mcpu=cortex-m4 -mthumb
CFLAGS=$(COMMONFLAGS) $(MCUFLAGS) $(INCLUDE) $(CDEFS)

LDLIBS=
LDFLAGS=$(COMMONFLAGS) -fno-exceptions -ffunction-sections -fdata-sections \
        -nostartfiles -Wl,--gc-sections,-T$(LINKER_SCRIPT)

#####

OBJ = $(SRC:%.c=%.o) $(ASRC:%.s=%.o)

CC=$(TOOLCHAIN_PREFIX)-gcc
LD=$(TOOLCHAIN_PREFIX)-gcc
OBJCOPY=$(TOOLCHAIN_PREFIX)-objcopy
AS=$(TOOLCHAIN_PREFIX)-as
AR=$(TOOLCHAIN_PREFIX)-ar
GDB=$(TOOLCHAIN_PREFIX)-gdb

all: $(OBJ)
	$(CC) -o $(TARGET).elf $(LDFLAGS) $(OBJ)	$(LDLIBS)
	$(OBJCOPY) -O ihex   $(TARGET).elf $(TARGET).hex
	$(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin

.PHONY: clean

clean:
	rm -f $(OBJ)
	rm -f $(TARGET).elf
	rm -f $(TARGET).hex
	rm -f $(TARGET).bin

You should be able to build everything now and get the binary, USB_Example.bin.

Flashing the board

Again, there are several options.  The easiest is probably the nice USB interface that comes from the preinstalled bootloader on the Discovery board.  This is the STLINKv2 protocol.  Apparently, you can even use it to connect to a board with gdb (arm-none-eabi-gdb) and have a pretty powerful debugging setup.

If you have a Discovery board, the top half has a USB programmer to do STLINK for you.  You can also buy a standalone dongle.

You can talk to it from Windows using ST’s free utility, along with their drivers.  You might need to “find drivers automatically” from the Device Manager regardless (I had to).

On Linux, you can use OpenOCD or st-flash.  I used st-flash, after installing a few extra things it wants:

sudo apt-get install automake libusb-1.0-0-dev
git clone https://github.com/texane/stlink.git
cd stlink
./autogen.sh
./configure
make

If you plug the ST-LINK usb port to your computer, you can talk to it with the stlink utilities:

$ lsusb
Bus 007 Device 007: ID 0483:3748 SGS Thomson Microelectronics ST-LINK/V2
$ sudo ./st-info --chipid
Error: could not open stlink device
Error: could not open stlink device
0x0422

You can flash the .bin file you made earlier:

$ sudo ./st-flash write USB_Example.bin 0x8000000
2013-10-01T16:02:16 INFO src/stlink-common.c: Loading device parameters....
2013-10-01T16:02:16 INFO src/stlink-common.c: Device connected is: F3 device, id 0x10036422
2013-10-01T16:02:16 INFO src/stlink-common.c: SRAM size: 0xa000 bytes (40 KiB), Flash: 0x40000 bytes (256 KiB) in pages of 2048 bytes
2013-10-01T16:02:16 INFO src/stlink-common.c: Attempting to write 19760 (0x4d30) bytes to stm32 address: 134217728 (0x8000000)
Flash page at addr: 0x08004800 erased
2013-10-01T16:02:17 INFO src/stlink-common.c: Finished erasing 10 pages of 2048 (0x800) bytes
2013-10-01T16:02:17 INFO src/stlink-common.c: Starting Flash write for VL/F0 core id
2013-10-01T16:02:17 INFO src/stlink-common.c: Successfully loaded flash loader in sram
  9/9 pages written
2013-10-01T16:02:18 INFO src/stlink-common.c: Starting verification of write complete
2013-10-01T16:02:18 INFO src/stlink-common.c: Flash written and verified! jolly good!

You can put the demo software it shipped with back on it, as well.  One caveat is that st-flash only takes binary (.bin) files, not hex (in plain text, typically .hex), and it won’t complain if you try with the wrong thing.  So you have to convert the supplied demo file (at Project/Demonstration/Binary/STM32F3_Discovery_Demo_V1.1.0.hex):

arm-none-eabi-objcopy -O binary -I ihex STM32F3_Discovery_Demo_V1.1.0.hex STM32F3_Discovery_Demo_V1.1.0.bin

And you can flash the resulting .bin file back on the board in the same way as before.

Programming standalone boards (not Discovery)

(This is planning from notes here and elsewhere, I haven’t done this yet).

You can use the Discovery board as a programmer and flash a target board as done above.  Just remove the two DISCOVERY jumpers at CN4 and connect the six wire SWD interface appropriately to the target board.  See the full Discovery docs for more details (section 4.2.2).

Another option is to flash the board without a programmer, using a simple USART interface.  See the “Microcontroller system memory boot mode” application note.  Apparently, these chips have a native bootloader that will take serial input on the correct pins directly into flash memory when they are powered on after the correct reset pin sequence (see e.g. the LeafLabs Maple bootloader replacement instructions).  Utilities like stm32flash are designed to work in this mode, e.g. using an FTDI cable to your computer.  The downside is that you lose the nice debugging support that you get with STLINK.

Open tasks

  • Making a minimal example that doesn’t depend on the firmware example package (and uses as little of their library as possible), with the specific MCU version factored out so it can be changed easily.
  • Designing, fabricating, and flashing a standalone 32-bit board (LeafLabs Mini as a starting point, looking at Discovery schematics as necessary).  See ST’s hardware application note for an overview.  Or the full 1705 page reference manual
  • Explore LeafLabs Maple IDE integration with Discovery boards (to make programming easier with this Arduino interface clone).  Ideally, there would be a simple boards.txt modification to be able to work with Discovery boards as targets.  We could use the IDE for programming and building, and one of the STLINK utilities for flashing (unless we put the Maple bootloader on the Discovery, or hacked up the IDE).  See here and here for a discussion.
  • Doing anything real with the powerful capabilities of the M4 chips…
Updates:
  • This STM32 ebook seems really good.  His examples may be promising for minimal examples to use in the class.
  • The class inventory part is STM32F103C8T6, an F1 (Cortex M3).  The discovery boards are F1, F3, or F4.  F3 and F4 are Cortex M4 parts.