mirror of
https://github.com/rfivet/stm32bringup.git
synced 2025-02-21 05:37:09 -05:00
180 lines
5.9 KiB
HTML
180 lines
5.9 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>3.6 Toolchain Update</title>
|
||
<link type="text/css" rel="stylesheet" href="style.css">
|
||
</head>
|
||
<body>
|
||
<h1>3.6 Toolchain Update</h1>
|
||
|
||
When a new release of GNU ARM Embedded Toolchain comes out, I have to do some
|
||
adaptations when switching to it.
|
||
<p>
|
||
By example, to switch from release 9 update to release 10 major, I made three
|
||
changes to <b>Makefile</b>.
|
||
<p>
|
||
● Update the Linux base directory location:
|
||
|
||
<pre>
|
||
#GCCDIR = $(HOME)/Packages/gcc-arm-none-eabi-9-2020-q2-update
|
||
GCCDIR = $(HOME)/Packages/gcc-arm-none-eabi-10-2020-q4-major
|
||
</pre>
|
||
|
||
● Update the Windows base directory location:
|
||
|
||
<pre>
|
||
#GCCDIR = D:/Program Files (x86)/GNU Arm Embedded Toolchain/9 2020-q2-update
|
||
GCCDIR = D:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2020-q4-major
|
||
</pre>
|
||
|
||
● Update the library subdirectory location:
|
||
|
||
<pre>
|
||
#LIBDIR = $(GCCDIR)/lib/gcc/arm-none-eabi/9.3.1/thumb/v6-m/nofp
|
||
LIBDIR = $(GCCDIR)/lib/gcc/arm-none-eabi/10.2.1/thumb/v6-m/nofp
|
||
</pre>
|
||
|
||
In the case of release 10 major, unfortunately while doing some regression
|
||
testing by recompiling the projects so far, I found that the new release
|
||
optimizes further the C startup clearing of BSS data by calling
|
||
<code>memset()</code> from the distribution libraries.
|
||
<pre>
|
||
$ make
|
||
f030f4.elf from startup.txeie.o adc.o adcmain.o
|
||
D:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2020-q4-major\bin\arm-none-
|
||
eabi-ld.exe: startup.txeie.o: in function `Reset_Handler':
|
||
D:\Renau\Documents\Projects\stm32bringup\docs/startup.txeie.c:126: undefined ref
|
||
erence to `memset'
|
||
make: *** [mk8:61: f030f4.elf] Error 1
|
||
</pre>
|
||
So I had to add <b>libc.a</b> and its location on top of <b>libgcc.a</b>
|
||
to the list of libraries.
|
||
<pre>
|
||
LIBS = -l$(LIBSTEM) -lc -lgcc
|
||
LIB_PATHS = -L. -L$(GCCDIR)/arm-none-eabi/lib/thumb/v6-m/nofp -L$(LIBDIR)
|
||
</pre>
|
||
with <b>libc.a</b> the link phase complete successfully.
|
||
<pre>
|
||
f030f4.elf from startup.txeie.o adc.o adcmain.o
|
||
text data bss dec hex filename
|
||
2644 0 16 2660 a64 f030f4.elf
|
||
</pre>
|
||
<p>
|
||
As I don’t want to turn off size optimization and I am not willing to
|
||
always pay the full 180 bytes for a production ready <code>memset()</code>
|
||
when it is called only once at startup to clear a few bytes, I ended up adding
|
||
my own version of <code>memset()</code> to my local library.
|
||
|
||
<pre>
|
||
#include <string.h>
|
||
|
||
void *memset( void *s, int c, size_t n) {
|
||
char *p = s ;
|
||
while( n--)
|
||
*p++ = c ;
|
||
|
||
return s ;
|
||
}
|
||
</pre>
|
||
<pre>
|
||
LIBOBJS = printf.o putchar.o puts.o memset.o
|
||
</pre>
|
||
Link succeed with a reduction of 152 bytes of code.
|
||
<pre>
|
||
f030f4.elf from startup.txeie.o adc.o adcmain.o
|
||
text data bss dec hex filename
|
||
2492 0 16 2508 9cc f030f4.elf
|
||
</pre>
|
||
<h2>GCC front end handling the libraries selection</h2>
|
||
As I was investigating the compilation flags to find if there was a
|
||
better way to solve this issue, I figure out I could let <b>gcc</b> handle
|
||
the distribution libraries selection and their location based on the CPU
|
||
type. So I changed the linker invocation accordingly and got rid of LD,
|
||
LIBDIR and LIB_PATHS definitions.
|
||
|
||
<pre>
|
||
# $(LD) -T$(LD_SCRIPT) $(LIB_PATHS) -Map=$(PROJECT).map -cref -o $@ $(OBJS) $(LIBS)
|
||
$(CC) $(CPU) -T$(LD_SCRIPT) -L. -Wl,-Map=$(PROJECT).map,-cref \
|
||
-nostartfiles -o $@ $(OBJS) -l$(LIBSTEM)
|
||
</pre>
|
||
|
||
As the compiler front end is now controlling the libraries selection it is
|
||
possible to give it a hint how to select a better optimized memset(). The
|
||
libc library comes in two flavors: regular and nano.
|
||
|
||
<pre>
|
||
OBJS = $(SRCS:.c=.o)
|
||
LIBOBJS = printf.o putchar.o puts.o # memset.o
|
||
|
||
CPU = -mthumb -mcpu=cortex-m0 --specs=nano.specs
|
||
</pre>
|
||
|
||
<code>memset()</code> included in the nano version of libc occupies the same
|
||
space as my own implementation.
|
||
<pre>
|
||
f030f4.elf from startup.txeie.o adc.o adcmain.o
|
||
text data bss dec hex filename
|
||
2492 0 16 2508 9cc f030f4.elf
|
||
</pre>
|
||
<h2>PATH based command selection</h2>
|
||
Finally, I revised the way I specify the commands location by updating the
|
||
PATH environment variable in the Makefile instead of giving the full path of
|
||
each command.<br>
|
||
On Windows, I make sure that drive specification matches the development
|
||
environment in use (Cygwin, MSYS2 and other).
|
||
|
||
<pre>
|
||
### Build environment selection
|
||
|
||
ifeq (linux, $(findstring linux, $(MAKE_HOST)))
|
||
INSTALLDIR = $(HOME)/Packages
|
||
#REVDIR = gcc-arm-none-eabi-10-2020-q4-major
|
||
REVDIR = arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi
|
||
else
|
||
DRIVE = d
|
||
ifeq (cygwin, $(findstring cygwin, $(MAKE_HOST)))
|
||
OSDRIVE = /cygdrive/$(DRIVE)
|
||
else ifeq (msys, $(findstring msys, $(MAKE_HOST)))
|
||
OSDRIVE = /$(DRIVE)
|
||
else
|
||
OSDRIVE = $(DRIVE):
|
||
endif
|
||
INSTALLDIR = $(OSDRIVE)/Program Files (x86)
|
||
#REVDIR = GNU Arm Embedded Toolchain/10 2020-q4-major
|
||
REVDIR = GNU Arm Embedded Toolchain/arm-gnu-toolchain-14.2.rel1-mingw-w64-i686-arm-none-eabi
|
||
endif
|
||
|
||
GCCDIR = $(INSTALLDIR)/$(REVDIR)
|
||
export PATH := $(GCCDIR)/bin:$(PATH)
|
||
|
||
BINPFX = @arm-none-eabi-
|
||
AR = $(BINPFX)ar
|
||
CC = $(BINPFX)gcc
|
||
OBJCOPY = $(BINPFX)objcopy
|
||
OBJDUMP = $(BINPFX)objdump
|
||
SIZE = $(BINPFX)size
|
||
</pre>
|
||
Switching back to latest version of the toolchain at the time of writing this,
|
||
the link shows further improvement of the code size. The optimization via
|
||
<code>memset()</code> has been skipped by the compiler.
|
||
<pre>
|
||
f030f4.elf from startup.txeie.o adc.o adcmain.o
|
||
text data bss dec hex filename
|
||
2464 0 16 2480 9b0 f030f4.elf
|
||
</pre>
|
||
<h2>Checkpoint</h2>
|
||
|
||
Invoking the compiler instead of the linker gives more flexibility in
|
||
case the toolchain directory structure changes or if I target a
|
||
different core. The compiler is aware of the location of the toolchain
|
||
libraries while the linker need explicit parameters to handle those
|
||
changes.
|
||
<p>
|
||
<a href="37_inram.html">Next</a>, I will (re)build to execute code in RAM
|
||
instead of FLASH.
|
||
|
||
<hr>© 2020-2025 Renaud Fivet
|
||
</body>
|
||
</html>
|