Category Archives: STM32 MCU

Building the GNU ARM Toolchain

Note: This post serves mainly as a reminder to myself. I did not figure out everything myself and got the original instructions from here (many thanks to Adam Kunen). The steps here aren’t exactly the same, but they’re mostly similar. His posts also contain some explanations for the various configure options as well as a short explanation on the triplet (ie. “arm-none-eabi”).

The goal: To build the GCC toolchain for ARM suitable for bare-metal work, complete with gdb and libc (newlib). At the end of the day I used this to compile the LwIP sample projects (both “standalone” and FreeRTOS versions) for an STM32F4 evaluation board.

These are the versions of the various components I used:

There should be no issues using newer versions of these components.

In this tutorial I’m going to install the tool-chain at ~/arm-none-eabi/ with with the sources in ~/arm-none-eabi-src. Do change this path if you prefer a different location. (On my own machine, I placed it in /opt/arm-none-eabi)

Update (6/9/2013): Some of the configure commands include “–with-cpu=cortex-m4”. This is because I was building for a ARM Cortex-M4 MCU. You should replace this with your target architecture. I had problems with an earlier build when I didn’t add this option in. It turns out that Cortex-M processors are picky about word alignment, and if you don’t configure this in before you build newlib and gcc, the libraries may not respect the word alignments and you may end up with hard faults.

Ok, first we create the directory skeleton:

cd
mkdir arm-none-eabi arm-none-eabi-src
cd arm-none-eabi
mkdir src build

Now, download the the packages and extract them:

cd ~/arm-none-eabi-src/src

wget ftp://ftp.gnu.org/gnu/gcc/gcc-4.7.1/gcc-4.7.1.tar.bz2
wget ftp://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.bz2
wget ftp://ftp.gnu.org/gnu/gdb/gdb-7.4.tar.bz2
wget ftp://sources.redhat.com/pub/newlib/newlib-1.20.0.tar.gz

tar -xf gcc-4.7.1.tar.bz2
tar -xf binutils-2.22.tar.bz2
tar -xf gdb-7.4.tar.bz2
tar -xf newlib-1.20.0.tar.gz

Build binutils first:

cd ~/arm-none-eabi-src/build
mkdir binutils-2.22
cd binutils-2.22
../../binutils-2.22/configure --target=arm-none-eabi \
  --prefix=~/arm-none-eabi --with-cpu=cortex-m4 \
  --with-no-thumb-interwork --with-mode=thumb
make all install
export PATH="$PATH:~/arm-none-eabi/bin"

At this point you could also put the path “~/arm-none-eabi/bin” into your .bashrc file if you want.

After this, we will do the first part in building gcc.

Note: gcc relies on three bignum libraries: mpfr, mpc, and gmp. You should download the source code for those three libraries, rename them to mpft, mpc, and gmp respectively, and move them inside the gcc source tree. Do not compile these libraries separately.

The steps to build the first stage are:

cd ~/arm-none-eabi-src/build
mkdir gcc-4.7.1
cd gcc-4.7.1
../../src/gcc-4.7.1/configure --target=arm-none-eabi \
  --prefix=~/arm-none-eabi ---with-cpu=cortex-m4 \
  --with-mode=thumb --disable-multilib \
  --with-no-thumb-interwork \
  --enable-languages="c,c++" --with-newlib \
  --with-headers=../../src/newlib-1.20.0/newlib/libc/include \
  --with-system-zlib
make all-gcc install-gcc

Here I deviate from Kunen’s tutorial a little. I could not get gcc 4.7.1 to compile without the “–with-system-zlib” flag. (The make process fails somewhere when it tries to do link tests. If anyone can explain why or knows why using the system zlib is disadvantageous, do leave a comment and let me know.)

Okay, now let’s build our newlib libc with our freshly compiled gcc cross compiler:

cd ~/arm-none-eabi-src/build
mkdir newlib-1.20.0
cd newlib-1.20.0
../../src/newlib-1.20.0/configure --target=arm-none-eabi \
  --prefix=~/arm-none-eabi --disable-multilib \
  --disable-newlib-supplied-syscalls
make all install

Here there’s another configuration option which I added which Kunen doesn’t: –disable-newlib-supplied-syscalls. The reason is I want to supply the system call stubs myself so I can have a potentially fully functional stdin, stdout, etc. Also, if you’re using an RTOS, here is where you could make standard libc malloc work with your RTOS’ memory management. Even if you aren’t using an RTOS, supplying appropriate stubs will still give you a fully functional libc.

The catch is you’ll always need supply the system call stubs if you use printf, and friends, or malloc and friends. You can read more about it here and here.

Now, we can complete the gcc build:

cd ~/arm-none-eabi-src/build/gcc-4.7.1
make all install

And the final piece, gdb:

cd ~/arm-none-eabi-src/build
mkdir gdb-7.4
cd gdb-7.4
../../src/gdb-7.4/configure --target=arm-none-eabi \
  --prefix=~/arm-none-eabi
make all install

Alright! Now put

export PATH="$PATH:~/arm-none-eabi/bin"

in your .bashrc or /etc/environment (if you haven’t already) and you have a fully functional ARM tool-chain suitable for bare-metal work.