1
0
mirror of https://github.com/rfivet/stm32bringup.git synced 2025-02-21 05:37:09 -05:00
stm32bringup/docs/11_toolchain.html

289 lines
9.5 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1.1 GNU Arm Embedded Toolchain</title>
<link type="text/css" rel="stylesheet" href="style.css">
</head>
<body>
<h1>1.1 GNU Arm Embedded Toolchain</h1>
Arm maintains a GCC cross-compiler available as binaries that run on Linux and
Windows.<br>It is available on their
<a href="https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm">
arm developer site</a>.
<h2>Installation on Windows</h2>
So far there are only win32 versions available for download either as
<b>.exe</b> installers or <b>.zip</b> archives. File naming convention helps to
identify the type of release (preview, major or update).
<p>
By default each release installs to its own directory instead of upgrading the
previous one. This way several releases can coexist and you can select which
one you use for a specific project. One downside to this is that the directory
and filename convention is heavy. For practical use, you need to configure an
IDE or encapsulate those paths and names in <b>Makefile</b> variables.
<pre>
### Build environment selection
GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi"
BINPFX = $(GCCDIR)/bin/arm-none-eabi-
CC = $(BINPFX)gcc
### Build rules
.PHONY: version
version:
$(CC) --version
</pre>
<ul>
<li> <b>GCCDIR</b> holds the path to the folder where the toolchain is installed.
When I install a new release, I need to update this path.
<li> All the commands to build are located in one <b>bin</b> subfolder and they
share the same name prefix <b>arm-none-eabi-</b>. So I have created a
<b>BINPFX</b> to easily identify the commands.
</ul>
<pre>
$ make
"D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m
ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-gcc --version
arm-none-eabi-gcc.exe (Arm GNU Toolchain 13.3.Rel1 (Build arm-13.24)) 13.3.1 202
40614
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
</pre>
<h2>Installation on Linux</h2>
Installation on Linux means downloading the Linux x86_64 tarball and extracting
it. I use the <b>~/Packages</b> folder for this type of distribution. This
means that the <b>Makefile</b> on Linux will be the same as the Windows one
except for the value of the <b>GCCDIR</b> variable.
<pre>
GCCDIR = $(HOME)/Packages/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi
</pre>
By selecting the path based on the development environment, there is no need
to make changes while switching between OS. <b>Gmake</b> has the built-in
variable <b>MAKE_HOST</b> that can be tested for this.
<pre>
### Build environment selection
ifeq (linux, $(findstring linux, $(MAKE_HOST)))
GCCDIR = $(HOME)/Packages/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi
else
GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi"
endif
BINPFX = $(GCCDIR)/bin/arm-none-eabi-
CC = $(BINPFX)gcc
### Build rules
.PHONY: version
version:
$(CC) --version
</pre>
I use the path prefix <b>$(HOME)/Packages</b> instead of <b>~/Packages</b> when
defining <b>GCCDIR</b> as some sub-processes called by <i>gmake</i> may have
issues with <b>~</b> expansion (in this case <i>ld</i>). This way <i>gmake</i>
will handle the expansion before calling the sub-processes.
<h2>Toolchains chain of events</h2>
In order to generate a file that can be loaded in the micro-controller, I
need to sketch the chain of events that will take place.
<ol>
<li> <b>Compile</b> source codes (<b>.c</b>) to object modules (<b>.o</b>)
<li> <b>Link</b> all the object modules (<b>.o</b>) together into an
executable (<b>.elf</b>)
<li> <b>Convert</b> the executable (<b>.elf</b>) into a format suitable for
loading or flashing (<b>.bin</b> or <b>.hex</b>).
</ol>
<h3>1. Compile</h3>
<b>Gmake</b> has default rules to built <b>.o</b> files out of <b>.c</b> files.
As I have already defined with <b>CC</b> the command to compile, I can make a
simple test of this step by creating an empty <b>.c</b> file and checking what
happens when I try to compile it.
<pre>
$ touch empty.c
$ make empty.o
"D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m
ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-gcc -c -o empty.o empty.c
</pre>
Compilation is succesful and <b>empty.o</b> file is generated.
<h3>2. Link</h3>
To link the object module generated in the first step, I need to
<ul>
<li> specify the command to link (<b>ld</b>)
<li> provide the name of a link script
<li> create a rule that calls the linker to generate an executable <b>.elf</b>
file from the object module <b>.o</b> file.
</ul>
<p>
There are sample link scripts that come with the toolchain, they are located
in the subfolder <b>share/gcc-arm-none-eabi/samples/ldscripts</b>. For now I can
use the simplest script: <b>mem.ld</b>.
<pre>
### Build environment selection
ifeq (linux, $(findstring linux, $(MAKE_HOST)))
GCCDIR = $(HOME)/Packages/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi
else
GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi"
endif
BINPFX = $(GCCDIR)/bin/arm-none-eabi-
CC = $(BINPFX)gcc
LD = $(BINPFX)ld
LD_SCRIPT = $(GCCDIR)/share/gcc-arm-none-eabi/samples/ldscripts/mem.ld
### Build rules
%.elf: %.o
$(LD) -T$(LD_SCRIPT) -o $@ $<
</pre>
<pre>
$ make empty.elf
"D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m
ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-ld -T"D:/Program Files (x86)/GNU
Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi"
/share/gcc-arm-none-eabi/samples/ldscripts/mem.ld -o empty.elf empty.o
</pre>
Link terminates successfully and creates <b>empty.elf</b>.
<h3>3. Convert</h3>
Finally, I use the command <b>objcopy</b> to convert the executable <b>.elf</b>
file into binary or intel hex format suitable to load in the micro-controller.
<pre>
### Build environment selection
ifeq (linux, $(findstring linux, $(MAKE_HOST)))
GCCDIR = $(HOME)/Packages/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi
else
GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi"
endif
BINPFX = $(GCCDIR)/bin/arm-none-eabi-
CC = $(BINPFX)gcc
LD = $(BINPFX)ld
OBJCOPY = $(BINPFX)objcopy
LD_SCRIPT = $(GCCDIR)/share/gcc-arm-none-eabi/samples/ldscripts/mem.ld
### Build rules
%.elf: %.o
$(LD) -T$(LD_SCRIPT) -o $@ $<
%.bin: %.elf
$(OBJCOPY) -O binary $< $@
%.hex: %.elf
$(OBJCOPY) -O ihex $< $@
</pre>
Now, if I start in a directory that contains only this <b>Makefile</b> and an
empty <b>empty.c</b> file, I can successfully build.
<pre>
$ make empty.bin empty.hex
"D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m
ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-gcc -c -o empty.o empty.c
"D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m
ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-ld -T"D:/Program Files (x86)/GNU
Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi"
/share/gcc-arm-none-eabi/samples/ldscripts/mem.ld -o empty.elf empty.o
"D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m
ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-objcopy -O binary empty.elf empty
.bin
"D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m
ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-objcopy -O ihex empty.elf empty.h
ex
rm empty.o empty.elf
</pre>
Notice that <b>gmake</b> automatically removes the intermediary <b>.o</b> and
<b>.elf</b> files on completion.
<p>
The generated <b>empty.bin</b> is empty.
<h2>Cleaning up</h2>
I want to keep the output of the build easy to understand without the clutter
of the long command names. Also I need a way to clean the working directory
back to its initial state.
<ul>
<li>By prefixing <b>BINPFX</b> with <i>@</i>, commands will not be displayed by
<i>gmake</i> when they are executed. Adding an <b>echo</b> of the command
target in the rules helps to keep track of the build progression.
<li>A new <b>clean</b> rule will remove all generated files.
</ul>
<pre>
### Build environment selection
ifeq (linux, $(findstring linux, $(MAKE_HOST)))
GCCDIR = $(HOME)/Packages/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi
else
GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi"
endif
BINPFX = @$(GCCDIR)/bin/arm-none-eabi-
CC = $(BINPFX)gcc
LD = $(BINPFX)ld
OBJCOPY = $(BINPFX)objcopy
LD_SCRIPT = $(GCCDIR)/share/gcc-arm-none-eabi/samples/ldscripts/mem.ld
### Build rules
.PHONY: clean
clean:
@echo CLEAN
@rm -f *.o *.elf *.bin *.hex
%.elf: %.o
@echo $@
$(LD) -T$(LD_SCRIPT) -o $@ $<
%.bin: %.elf
@echo $@
$(OBJCOPY) -O binary $< $@
%.hex: %.elf
@echo $@
$(OBJCOPY) -O ihex $< $@
</pre>
<pre>
$ make clean
CLEAN
$ make empty.bin empty.hex
empty.elf
empty.bin
empty.hex
rm empty.o empty.elf
</pre>
<h2>Checkpoint</h2>
At this stage, I have a working toolchain and I am able to build from an empty
source file (<b>empty.c</b>) to an empty binary file (<b>empty.bin</b>).
<p>
<a href="12_bootstrap.html">Next</a>, I will select a micro-controller
from the STM32 family and generate a binary file that it can execute.
<hr>© 2020-2024 Renaud Fivet
</body>
</html>