STM32 Minimal Development Environment

Tags: ARM, Embedded, Programming

In the past I have written on the advantages of minimal development environments (read: Makefiles and GCC, no IDE, minimal abstraction layers) for ARM processors. One of the advantages of working this way is easy integration with existing processes such as build systems, production line, testing, etc. Using this in a virtualized environment also allows one to make sure every developer uses the same tools, and that the tools are tested and qualified for the intended project with a ready made virtual image available for each developer. They can then add their favorite editor and user interface, but the underlying build environment is fixed for everyone and archived as such on a per-project basis. This means that if a customer comes back a year or two later and wants to make a change, all the tools are there as we left them ready to make the change. In this blog post I'll write down a possible scenario for a typical STM32 project, in this case using a NUCLEO-L152RE board as a target. It should be easy to adapt to other STM32 boards/chips, and in general other ARM microcontrollers as well.

Programmer on chair

To get started, we need a minimal Debian virtual machine running in VirtuaBox for example. Making this VM is a little out of scope of this blog post, but should be as simple as downloading the minimal network installation iso from, and run through the installation process. You don't need large amount of disk space or RAM since this will be a command line only system we SSH in. For this, specify one extra, host only, network interface in your VM set-up.

Once that's up and running, become root (or install sudo), or whatever your prefer and let's get started installing some needed components. First, to get a basic development environment with make etc:

apt-get install build-essential

Secondly, the ARM cross compiler:

apt-get install gcc-arm-none-eabi gdb-arm-none-eabi

While we won't need it for now, it's a good idea to install openocd as well. We'll come back to that in a later post and it also pulls in some needed requirements.

apt-get install openocd

git, cmake, unzip, since we're going to build one package from source:

apt-get install git cmake unzip

That package: STLink. It's the open source tool used for flashing the STM32 and it has some other tools we will use later on.

git clone
cd stlink
make release
cd build/Release
make install

For the STM32 we need the STM32CubeL1 software package from ST. This includes the HAL (which we won't use), the Low Level API (LL) which we will use, etc. You need to register an account to download this, so yeah...

Next, let's create our project. Make a new directory, i.e. 'mkdir project' but don't cd there just yet. If you want to make it easy and skip the next steps, you can just check out the GitHub project accompanying this post. This contains all the files we're going to be copying across except for the STM32CubeL1 stuff.

First extract


And copy the 'Drivers' directory to your 'project' directory, or in case you're using the GitHub project as a base, the contents of the 'Drivers' directory to the 'Drivers' directory in the project.

cd STM32Cube_FW_L1_V1.8.0

cp -R Drivers/ ../project/

cd ../project

We're now going to create a ll library. This library will contain the low level API library, skipping all the HAL stuff. For this, you can find a Makefile in the repo in the Drivers directory, together with some supporting config files. This Makefile will compile only the _ll_ files required for the Low Level API. Copy the Makefile, and the stm32l1xx_conf.h (containing all the includes for _ll_ header files) and stm32l1xx_hal_conf.h files to project/Drivers. You're now pretty much ready to build the library, but of course, some HAL stuff causes issues still. Edit the following files:

STM32L1xx_HAL_Driver/Src/stm32l1xx_ll_fsmc.c  --> comment out line 68

STM32L1xx_HAL_Driver/Src/stm32l1xx_ll_sdmmc.c --> comment out line 166

These cause the "unknown type name 'HAL_StatusTypeDef'" errors during compilation. They're easy enough to clean up when you come across them. Just comment out the lines that include HAL specific stuff. Hopefully this will be fixed upstream at some point.

EDIT: these errros can be fixed by including 'stm32l1xx_hal_def.h' in the 'stm32l1xx_hal_conf.h' file. This is updated in the git repo, so the above step isn't needed anymore. Thanks u/_pseudonym on Reddit for pointing this out.

Then, run make and you should get a libll.a file. Congrats, your toolchain works and we don't have any of the HAL parts anymore.

Next, copy the file startup_stm32l152xe.s to the main project directory. Let's create a src/ directory under the project/ directory. This will hold our actual source files. We can already add system_stm32l1xx.c. We also create a main.c file with the initial set-up for the controller. This program sets up the clocks and a pin on the controller - and will loop indefinitely blinking the LED on this pin on the Nucleo board. We can add the project Makefile under project/ as well.

We also have to add the linker directives, in this case we choose to create a directory hierarchy Device/ldscripts under project/ and add sections_flash.ld, stm32l1nucleo_def.ld  and stm32l1xx.ld there.

All these config files, linker files, etc. are essentially modified from the examples included with the CubeL1 software. 

That should be it. Running 'make' in project/ should give you a .elf, .hex, .bin, etc. The .bin can be programed to the STM32 directly using st-link as follows (with the board attached):

st-flash --reset write project.bin 0x08000000

Here, 0x08000000 is the address of the flash memory on the STM32L1.


In a next post I'll take this further and use OpenOCD to flash/debug and more. In the mean time, you can read this article I wrote some time ago on how to flash the EEPROM as a separate entity with some minor OpenOCD modifications. You can also follow this link to where someone made modifications to the st-link for STM23L0 based devices to accomplish the same thing. Other STM32 devices with EEPROM should be easy to add.


Edit: - For STM32F4 users, have a look at this repo. It containes a Makefile-ized version for all demos for the Discovery board. 
         - Another minimal environment for STM32F
         - Thread on Reddit with some good info in the comments.




I've followed your instructions to generate a minimal L4 project - (links to tag since I'll be building off this).