STM32F4 – mbed Your Code: Zero Switching Costs When Changing ARM Platforms

What would general Ackbar say if he saw you using a firmware code directly in an user application?

It’s a trap, indeed! Just compare the device specific details of this and this main functions. The former depends on the firmware code that is device specific. To reduce code adaptation costs when switching between devices with the same functionalities (UART, CAN, Ethernet,…), heavy-weight operating systems like Linux and Windows implement hardware abstraction layer (HAL). This layer enables user applications to access different devices through standardized interface without code adaptation. Unfortunately, HAL is not available on small OS such as FreeRTOS.

Luckily, provides an open-source HAL solution for ARM-based embedded platforms. They have done all the heavy work of implementing drivers for different platforms. All you have to do is to access them device-independently through HAL interface to make your code portable between different platforms. In this tutorial I show how to setup mbed SDK enabled project using my project wizard in less than a minute.

1. Prerequisites

  • Ubuntu 14.04 LTS (x86 architecture).
  • STM32F4 Discovery Board (ARM architecture, costs less than 20 EUR).
  • Complete the Object-oriented Programming with Embedded Systems (C++ /w STL).
    • Or at least go through chapter 2. Below is a quick-and-dirty instruction summary if you decide to stay on this page.
      cd ~
      # Remove the official package
      sudo apt-get purge binutils-arm-none-eabi \
                         gcc-arm-none-eabi \
                         gdb-arm-none-eabi \
      # Add 3rd party repository
      sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded
      sudo apt-get update
      # Check the GCC package version in the PPA repository
      sudo apt-cache policy gcc-arm-none-eabi
      # Install software requirements
      sudo apt-get install build-essential git openocd \
       gcc-arm-none-eabi qemu-system-arm \
       symlinks expect
      # Clone my git repository & init submodules
      git clone
      cd ~/stm32
      git submodule update --init

2. Install Software Dependencies

Install symlink manipulation program.

sudo apt-get install symlinks

3. Use a Project Wizard to Create a Bare-metal Template Project

I provide a generic project generation utility called mbed-project-wizard to ease project initialization and some other software development task. In the git repo you may find Template.mbed project that was created using the wizard as follows.

export PATH=$PATH:~/stm32/mbed-project-wizard
mkdir -p ~/stm32/examples/Template.mbed
cd ~/stm32/examples/Template.mbed mbed-none

# The generated directory structure
# tree
# .
# ├── bin # Built binary files
# ├── inc # Add your header files here
# ├── lib # Add 3rd party code here
# │    └── mbed # Added by project-wizard
# ├── src # Add you source files here
# │    └── main.cpp
# ├── Makefile # DON'T TOUCH
# └── STM32F407.ld # DON'T TOUCH

The template project is extensible and build automatically as long as you keep the directory structure intact (i.e. bin, inc, lib, src).

  • You may add or remove header files (*.h) from the inc folder, add subdirectories or even use symbolic links. The Makefile script automagically finds appropriate files.
  • You may add or remove C (*.c) or Assembly (*.s) source files from the src folder, add subdirectories or use symbolic links.
  • You may add additional 3rd party code in the lib folder. Hopefully, it will build without Makefile modifications.
  • Don’t touch the Makefile, unless necessary. I modified the original Makefile from the Template with Generic Makefile project due to the following build issues.
    • The mbed code fails to compile using the GCC default Gnu89 dialect, because some more advanced C features are used. It compiles with C99 dialect.
    • The mbed code fails to compile using C++11 dialect directly. I applied a nasty hack (allow all non-ANSI extensions) to enable C++11 and the latest standard template library (STL) features.

5. Build & Deploy the Project

To build this mbed enabled application follow the steps below.

make clean
make -j4 # Size Optimized Build
# Other build options
# make -j4 release-memopt # Size Optimized Build
# make -j4 release-memopt-blame # Analyse Mem. Footpr.
# make -j4 release # Non-optimized Build
# make -j4 debug # Debug Build

sudo make deploy

Q: Deployment fails repeatedly due to some OpenOCD issue. 😦 Is there a workaround?
A: Yes, the current official Ubuntu package (Aug 2014) contains a prehistoric OpenOCD version. You should build a newer version from scratch. I provide step-by-step instructions here (2nd section, it takes less than 3 minutes to build it). When you are done, just return here and continue as nothing happened. It will work out of the box. 🙂

4. Hardware Abstraction Layer Benefits: A Comparative Analysis

The mbed enabled application and the “Hello World!” application are very similar. They both use the general purpose input output (GPIO) devices to toggle LEDs.

There are, however, also differences. While the “Hello World!” application manipulates GPIO directly, the mbed enabled application achieves this through DigitalOut HAL interface. The former is hardware specific, the latter is hardware agnostic, and thus, easily portable to other mbed supported platforms.

Both code snippets are provided below.

// main.cpp: mbed enabled application (with HAL)

#include "mbed.h"

DigitalOut myled(LED1);

int main() {
    while(1) {
        myled = 1;
        myled = 0;


// main.c: "Hello World!" Application (without HAL)

#include "stm32f4_discovery.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"

int main(void)
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13|
                                GPIO_Pin_14| GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
  while (1)
    GPIO_SetBits(GPIOD, GPIO_Pin_12);
    GPIO_SetBits(GPIOD, GPIO_Pin_13);

About istarc

Embedded Systems Developer.
This entry was posted in Embedded Systems, STM32F4 and tagged , , , , , . Bookmark the permalink.

3 Responses to STM32F4 – mbed Your Code: Zero Switching Costs When Changing ARM Platforms

  1. Rohit says:

    Does this work with the STM32F429i Discovery boards?

    • istarc says:

      Not directly, I believe … because my target is STM32F407VGT6 and your is STM32F429ZIT6. Despite the differences, both belong to Cortex-M4F family, so it should not be hard to port the code. I would start with the linker script — check STM32CubeF4, search for STM32F429ZIT6 project and copy the script. 🙂 Good luck! BR, Iztok

  2. sumit says:

    I followed all the steps. The compilation process works successfully, the hex file is loaded in the device successfully (using dfu-util), yet the bilinky program doesnt work. Any pointers ?

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s