STM32 Bare Metal Programming 04 – Makefile Automation

Makefile: Build Automation

We can use the make command line tool instead of manually typing in “compile”, “link”, and “flash” commands, automating the entire process. The make tool uses a configuration file called Makefile to read the instructions for executing actions. This automation is great because it also documents the process of building firmware and which compilation flags were used.

There is a very good Makefile tutorial for beginners at https://makefiletutorial.com, which I highly recommend checking out. Below, I will list some very necessary concepts to understand the Makefile we are using. For those who are already familiar with make, you can skip this part.

Actually, the format of Makefile is not complicated:

action1:
	command ...     # Comments can go after hash symbol
	command ....    # IMPORTANT: command must be preceded with the TAB character

action2:
	command ...     # Don't forget about TAB. Spaces won't work!

Now we can call make with the action name (also known as the target) to execute the corresponding action:

$ make action1

Of course, you can also define and use variables in the command, and actions can also be the names of files to be created:

firmware.elf:
	COMPILATION COMMAND .....

Any action can have a list of dependencies. For example, firmware.elf depends on the source file main.c, and when main.c changes, make build will rebuild firmware.elf:

build: firmware.elf

firmware.elf: main.c
	 COMPILATION COMMAND

We are ready to write the Makefile for the firmware and define a build action/target:

CFLAGS  ?=  -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion \
            -Wformat-truncation -fno-common -Wconversion \
            -g3 -Os -ffunction-sections -fdata-sections -I. \
            -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 $(EXTRA_CFLAGS)
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,[email protected]
SOURCES = main.c

build: firmware.elf

firmware.elf: $(SOURCES)
	arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@

Here we define some compilation flags. ?= indicates that this is a default value, which we can override in the command line like this:

$ make build CFLAGS="-O2 ...."

The Makefile file above defines the variables CFLAGS, LDFLAGS, and SOURCES, and then we tell make to create the firmware.elf file when building, which depends on the main.c file, using the arm-none-eabi-gcc compiler and the given compilation flags to generate it. The special variable $@ will be expanded to the action/target name, which in this case is firmware.elf.

Now let’s try calling make:

$ make build
arm-none-eabi-gcc main.c  -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion -Wformat-truncation -fno-common -Wconversion -g3 -Os -ffunction-sections -fdata-sections -I. -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16  -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=firmware.elf.map -o firmware.elf

If we run it again:

$ make build
make: Nothing to be done for `build'.

make will check the modification times of firmware.elf and the dependency main.c, and if they are up to date, it will do nothing. If we modify main.c, it will rebuild:

$ touch main.c # Simulate changes in main.c
$ make build

Now, there is still the “flash” action/target:

firmware.bin: firmware.elf
	arm-none-eabi-objcopy -O binary $< $@

flash: firmware.bin
	st-flash --reset write $(TARGET).bin 0x8000000

OK, now executing the command make flash in the terminal will create the firmware.bin file and then flash it onto the board using st-link. When main.c changes, this command will also rebuild, because firmware.bin depends on firmware.elf, and firmware.elf depends on main.c. So our development cycle consists of these two steps:

# Develop code in main.c
$ make flash

Another good practice is to add a clean action in the Makefile to remove the generated build files:

clean:
	rm -rf firmware.*

The complete source code can be found in the step-0-minimal[1] folder.

References

[1]

step-0-minimal: https://github.com/cpq/bare-metal-programming-guide/tree/main/step-0-minimal

Leave a Comment