TITLE: Bare Metal ARM Programming
AUTHOR: Chuck McManis
LAST UPDATE: 18-Mar-2019


Many people have noticed that microprocessor capabilities have really increased with the advent of the ARM Cortex-M series. These 32 bit processors can be bought in single quantities for a few dollars, the same as the 8 bit processors they are replacing, and come with significantly more FLASH and RAM as well as a host of peripherals from USB to Ethernet.

Many people want to “jump in” to embedded programming or to upgrade from their Arduino Sketches to something a bit more powerful. This can be very daunting at first. So to help you over that hump, and to give you some idea of what you are getting into, this article covers everything you need to know about writing programs on “bare metal” for the Cortex-M series.

The largest vendor in this space is ST Micro who has both inexpensive development boards with built in programmers called “Nucleo” boards. And boards with various peripherals that you can play with that they call “Discovery” boards. Both the Nucleo boards and the Discovery boards will usually include an “Arduino” connector which allows you to use some, but not all, Arduino shields with them.

One of my favorite Discovery boards is the STM32F469i Discovery board. This board has an 800 x 480 color LCD on it, an SD card slot, headphone/microphone port, USB connector, and 16 Megabytes of RAM on DDR ram. Not often do you get a microprocessor with that sort of resource, almost like the PC/AT from the early DOS days. It also has 2 Megabytes of FLASH and 324 Kilobytes of RAM (before you activate the DDR memory) so you can do a lot with this board. I have a Github Repo with code I’ve written for this board to explore its various peripherals.

These systems are also a good way to learn “command line” programming which can be a very powerful and flexible way to write code for these chips. We’ll talk about that here. What I’m not going to talk about are GUI type development environments. I understand that this means that if you only know how to program using the Arduino IDE, this article will be harder to put into practice. However, if you choose to try it out, I hope you will be richly rewarded in having a new capability in your toolbox.

Elements of Development

These days there are a bevy of open source tools that generally run on Linux systems of Mac systems (which have UNIX under the hood). Microsoft is making tremendous progress with the Windows System Linux but using it currently requires some special setups which I’ll discuss at the end.

There are four core elements to developing;

There are also “all-in-one” systems that are typically offered by the Manufacturer or by a third party at the manufacturer’s request, they are things like the STCubeMX package, the EAR systems compilers, and others. I strongly recommend that you do not start with these systems as they obscure what is really going on. This might seem helpful but the purpose is really to make it harder for you to switch chips or libraries later on. If you really want to program to the bare metal, you need to learn what the bare metal code does. That can be hard to do with an all-in-one package.

The Editors

Text editors are one of those things that people find one that they are comfortable with and stick with it. The two “big” ones in the Linux world are vim and emacs. Vim is known as a “moded” editor where you can be in “command” mode or “insert” mode, whereas emacs is known as a “modeless” editor where commands are usually associated with special key sequences that are not normally typed. Both can be customized with scripts, both can call out to compilers and build systems, and both can be augmented with additional capabilities.

That said, if you really have your heart set on an IDE, both Code Studio (now free from Microsoft) and NetBeans are good examples of free editors, Sublime and Visual Slickedit are examples of non-free development environment.

The Compilers

There is a choice of two compilers that are free, and a number of compilers that are not free. The free ones are gcc and clang. Of the two, only gcc has a manufacturer supported port for the ARM Cortex M architecture.

If you are using Ubuntu (or a debian based distribution of Linux) it is very simple to get the supported gcc compiler on to your system. It is also possible to get a broken compiler on your system. DO NOT use apt-get to load the Ubuntu package for “arm-none” on your system. The package maintainer does not include all the parts you need to compile for different Cortex-M families and it will not work with 99% of the web tutorials. Instead, you can use the manufacturer supported compiler with three simple steps:

That is it, now you can type arm-none-eabi-gcc --version and it will tell you which version of the compiler (it will be the latest stable one) is installed.

The Libraries

Now that you have a compiler, you need some C libraries to that can initialize your processor and talk to the peripherals. The one I am partial to is libopencm3. This is because it is simple, all of the source is included, and it is usually all you need for the ST Micro processors at least, other processors are not quite as well supported.

I find the simplest way to put this on your system is to use git to clone a copy of the respository into your home directory. If you type

git clone https://github.com/libopencm3/libopencm3

This will put the directory right into libopencm3. Follow that up with:

cd libopencm3; make

And the library will be built for you and ready to use.


One of the reasons I like the Discovery and Nucleo boards is that they have a built in debugger on the board. This is a separate STM32 processor that is running debugger firmware. This is very well supported by the open source package openocd. When creating a new environment from scratch I’ll often clone the openocd repository using:

git clone --recursive https://github.com/ntfreak/openocd

And then follow the instructions in the README file for building it. Note you will have to install some dependencies as well (like libusb, libhidapi, Etc.)

Once you have openocd installed you can start it (it will open a gdb network server for you to use) using this command:

openocf -f boards/st_nucleo_f4.cfg (this for an STM32F4 based Nucleo board)

Running your first program

At this point you have all the tools you need to do development. However, a good way to get some examples to look at is to clone the libopencm3 _examples repository. Note that this repository has its own copy of the libopencm3 library because the examples are not updated as quickly as the library is and you want a library repository that works.

To do this use:

git clone --recursive https://github.com/libopencm3/libopencm3-examples

Once that finishes, connect to the directory libopencm3-examples and type make. This will make both the libopencm3 library and the examples.

Now you can connect to ./examples/stm32/f4/nucleo-f411re for example (if you are using the Nucleo F411RE) cd to the blink directory and use gdb to flash the binary into the nucleo.

cd blink
arm-none-eabi-gdb blink.elf
GNU gdb (GNU Tools for Arm Embedded Processors 7-2018-q3-update)
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
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.
(gdb) target extended-remote :3333
(this will connect to the OpenOCD instance you started earlier)
(gdb) continue
(this avoids a bug in gdb where it won't break into the code, it may be fixed now)
(gdb) load
... loads (flashes) the blink file
(gdb) run
Start from the beginning (y/n)? y
(poof your program is running)


All of the tools for building programs that run directly on the processor (no OS) are now part of standard distributions. No more cross compiler compiling etc that used to plague building these environments on Linux. Have a look at the “Hello World” artcle for a more indepth walk through building and compiling a simple program.