Creating STM32 project using STMCube and custom Makefile

In this article I want to show how to create project for STM32 microcontroller with STMCube generator and build it with custom Makefile.

We need it if we don't want to use IDE (most of IDEs for ARM Cortex-M work only under Windows). Cube is useful when setting clocks of MCU, but HAL libraries produces huge and slow code, so for other peripherals it is better to use plain CMSIS. However, this project could use HAL for every peripheral, it's only on programmer's decision.
I also offer complete working project for F0 Discovery board.

When reading next steps of work, please refer to my project template, mainly Makefiles and Readme. Also look at file tree. For understanding of this article you need to know the basic principles of Makefiles, rules, etc. This Makefiles are tested under Linux environment, so file names are case-sensitive.

Step 1 - Create project in STMCube

Create project, set clocks and peripherals according to our needs. There are different possibilities for different microcontrollers. There are many possibilities in STMCube. You can play as you want :-) but this is not in scope of this article.
Important setting is to select Atollic Truestudio as target toolchain for project (because it uses modified GCC).
Now we can generate files of project. And that's all with STMCube.

Step 2 – Tools required for build

We need to set paths to ARM-GCC tools into system path. For downloading code into MCU I will use OpenOCD. And for other operating systems than Linux, you probably have to install some package with Make system manually.

ARM-GCC you could obtain from here.
OpenOCD is maybe in your distro's repositories, so you could install it from there.
STMCube homepage.

Step 3 – Structure of libraries

My project structure contains 2 Makefiles – the first one for libraries and the second one (main) for the rest of project.
Basically, STMcube places header files for MCU deep into CMSIS file tree and also includes some example projects and so on. We only need two headers for our specific MCU. I have moved headers from CMSIS/Device/ST/STM32Fyxx/Include to CMSIS/ST/Include. Only to clarify structure. Directory CMSIS/Include also contains headers for many ARM cores, but we only need one for particular project. You can remove others, but it is not mandatory. You can use my template as an example.
Content of directory STM32Fyxx_HAL_Driver doesn't need to be changed.

Now we can proceed to Makefile for Libraries. Firstly, we need to set correct path, vpath %.c … . Secondly, set name of file, where libraries will be packed – variable LIBAR. Last, we need to add used HAL files into source list. It should be clearly understood from comments in Makefile.

Different Cortex-M cores need different settings for compilator, so we need to adapt CFLAGS adequately.
In file stm32f0xx.h uncomment the define for particular MCU, which we use in project. That is all for Libraries.

Step 4 – Content of directories src and inc

The directory src have to contain files (example):

main.c
startup_stm32fYXXxZ.s
stm32f0xx_hal_msp.c
stm32f0xx_it.c
system_stm32fYXX.c

Files startup_stm32fYXXxZ.s, system_stm32fYXX.c are originally located in dir Drivers/CMSIS/Device/.../Source/Templates.
In directory inc there should be files:

main.h
stm32fYxx_hal_conf.h
stm32fYxx_it.h

Step 5 – Adapt Makefile for project

Now we will set some parameters in main Makefile. Please follow the comments included in it.
At first, we should set some meaningful name of project. Next we need to fulfil list of source files in project. Basically, these are files in src directory. As the project will grow, the list of sources will become longer.
Compilation settings are basically the same as for Libraries, but there may be differences. For som examples look into ARM-GCC readme.txt or search the Net or GCC's manual for more delicate options and examples.

Next set the name of startup file, e.g.:

STARTUP = $(SRCDIR)/startup_stm32f051x8.s

My Makefile uses individual rule for each source file. This approach has advantage of using full power of Make system – it will build only what is necessary.

Next set linking – fill name of Libraries archive and linking script. E.g.:

-lstm32f0 -TSTM32F051R8_FLASH.ld

The rules Flash, Erase and Reset are used to write binary code into MCU, to erase MCU's Flash memory and to reset the target MCU respectively. Or if you don't want to use OpenOCD, you could write here commands for tool of your choice.

Step 6 – Build project

Now the project is prepared for the building. So we can run command make. First are built Libraries, than project sources itself. At the end of process we will get information about used memory space in MCU.
Generated files (elf, hex, bin, lst, map) are placed into directory bin.

Next steps

How to add new source file into project? When you create new file, put its name into SRCS list and create new rule for compiling it (with needed dependencies).

How to change the compilator settings? Change switches in variable CFLAGS. Typically you may want to set another optimization, so set e.g. -O3.

Conclusion

Template can be downloaded from here.
If you will test this project template (with different MCU family) and have some suggestions or anything, please, send me a message. I will appreciate some feedback (from testing on humans :-) ).

Very similar process can be used for creating project based on any other libraries, e.g. StdPeriph.