First Steps with the STM32F4 in Linux (Part 2)

June 9, 2012

In part one the toolchain was installed, the STM library was built and an example project was compiled and uploaded to the board.

This part will cover some of the ways firmware can be written for the STM32F4 with the C programming language. To keep things short each example will only show how to light up the blue LED on the development board.

C
One step up from assembly would be to code in C without the benefit of any libraries or header files. Figure out what register needs to be accessed, read or write to the necessary bits, and go from there. For trivial projects this is fairly easy. The reference manual (RM0090) has the memory map on p.50 (Section 2.3) which provides all of the base addresses. The RCC register map is on p.134 (Section 5.3.24) and the GPIO register map is on p.153 (Section 6.4.11). For example, to light up the blue LED on the development board (and do nothing else) you would use need to enable the GPIOD clock, set pin 15 of GPIOD as an output, and set the pin high:

void main() { // Enable GPIOD clock *(unsigned int*) 0x40023830 |= (1 << 3); // RCC base: 0x40023800 // AHB1ENR offset: 0x30 // GPIOD enable: set bit 3 // Enable output mode for D15 *(unsigned int*) 0x40020C00 |= (1 << 15*2); // GPIOD base: 0x40020C00 // MODER offset: 0x00 // Pin 15 output: set bit 30 // Set D15 high *(unsigned int*) 0x40020C18 = (1 << 15); // GPIOD base: 0x40020C00 // BSRR offset: 0x18 // Pin 15 high: set bit 15 }

C with the stm32f4xx.h Header
Looking up memory addresses by hand gets old real quick. The stm32f4xx.h header file provided by STM has hundreds of macros that provide convenient names for each register and setting. It's a huge header, at just over 500KB, but traversing it is quick once you get used to the layout. The header defines structures for each subsystem and bitmasks for each structure. Redoing the above example to utilize this header results in more readable code:

#include "stm32f4xx.h" int main() { // Enable GPIOD clock RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable output mode for D15 GPIOD->MODER |= GPIO_MODER_MODER15_0; // Set D15 high GPIOD->BSRRL = GPIO_BSRR_BS_15; }

C with the STM Standard Peripheral Drivers Library
The STM library provides functions that abstract away some of the details. Instead of playing with memory directly, function calls are used. This library was downloaded and built in part one. Redoing the above example yields:

#include "stm32f4xx_rcc.h" #include "stm32f4xx_gpio.h" GPIO_InitTypeDef outputSettings; int main() { // Enable GPIOD clock RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); // Enable output mode for D15 outputSettings.GPIO_Pin = GPIO_Pin_15; outputSettings.GPIO_Mode = GPIO_Mode_OUT; GPIO_Init(GPIOD, &outputSettings); // Set D15 high GPIO_SetBits(GPIOD, GPIO_Pin_15); }

Download the project, build it with make and upload it with make install. The Makefile for this project expects the archive to be extracted to ~/stm32f4/projects/.

C with the libopencm3 Library
There are several unofficial libraries for the STM32 microcontrollers and libopencm3 is one of the more popular ones. It's a work-in-progress so the library is still evolving. The function names are more logical and this library seems to have a promising future. Download and build the library:

$ cd ~/stm32f4 $ git clone git://libopencm3.git.sourceforge.net/gitroot/libopencm3/libopencm3 $ cd libopencm3 $ make

Here's the LED example code ported to this library:

#include "libopencm3/stm32/f4/rcc.h" #include "libopencm3/stm32/f4/gpio.h" void main() { // Enable GPIOD clock rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN); // Enable output mode for D15 gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO15); // Set D15 high gpio_set(GPIOD, GPIO15); }

Download the project, build it with make and upload it with make install. The Makefile for this project expects the archive to be extracted to ~/stm32f4/projects/.

Become familiar with whatever library you choose by skimming through their example projects and carefully reading any headers that are included in those examples. I'll be covering the basics of the STM library in a later post: general purpose inputs, ADC usage, PWM, timers and more.