Toolchain for Cortex-M4/M0/M7

Last edit : Dec 2016

EDIT : do not accidentally press ctrl-c. It exists menu-config immediately.
Important links:

These are brief instructions for creating your own GCC based tool-chain for a Cortex-M4 microcontroller, heavily based on this post. I tried a few precompiled ones which I found on the Internet, but always wondered how to make one which would be configured specifically for my micro, not for “ARM” in general. Tool-chains generated by following method was tested by me on ST STM32F407 and Texas Instruments TIVA-C TM4C123 (i.e. one tool-chain for these two µC since they both include the same CPU). My setup as I write this:

  • Host operating system : Ubuntu 14.04 – 16.10
  • Kernel : 3.13.0-24-generic – 4.8.0-30-generic
  • Few GB of free space on HD.

Making a tool-chain is hard, therefore wise people over the net developed tools to simplify the process. Few years ago, when I attempted to build a GCC tool-chain I struggled with lack of information, complexity of the process, and variety of recipes, which all seemed were extremely complex, and in some point in the process I was struck with problem I couldn’t solve. Then I found crosstool-NG – it may seem funny, but all this stuff was new to me, and I was looking for the best way possible to finish the task, some “canonical” way of building a cross-compiler, and for me, crosstool-NG is exactly this. Lets grab the newest version from its website and follow the installation instructions (this step will build only the crosstool-NG itself, read the EDIT note below before doing this):

mkdir my-toolchain
cd my-toolchain
 
# Pay attention which version is the newest. As of writing this, the newest was
# 1.19.0, but at http://crosstool-ng.org/download/crosstool-ng/ the "header-file" 
# incorrectly indicated the 1.18.0 version
wget http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.19.0.tar.bz2
 
tar jxvf crosstool-ng-1.19.0.tar.bz2 
cd crosstool-ng-1.19.0/
 
# Resolve some dependencies. EDIT Ubuntu 15.04 wants libtool-bin as well.
sudo apt-get install bison flex gperf texinfo gawk libtool libtool-bin automake libncurses5-dev libexpat-dev help2man
 
# Provide a prefix to some destination which PATH points to.
./configure --prefix=/home/iwasz/local/
make
make install

EDIT (2016-12) It seems, that the newest official release available today is 1.22, which is more than year old. The older ct-ng is, the older GCC, and libraries it provides, which may cause a problems on newer systems. For example making a cross-gcc version 5.3 using ct-ng version 1.22 on Ubuntu 16.10 (which uses GCC 6.2) resulted in compilation error during GCC stage. Thus I think, that the best option is to start with development ct-ng from github repo. Instructions are here but basically you only need to:

git clone git@github.com:crosstool-ng/crosstool-ng.git
cd crosstool-ng
./bootstrap
./configure --prefix=/home/iwasz/local/
make
make install

Now we perform some setup. All features of our future tool-chain will be set during this step:

# cd back, so we are in "my-toolchain" directory again.
cd ..
mkdir staging
cd staging
ct-ng  menuconfig

The last command brings the following menu-config tool:

01-start-screen

Paths and misc options

  • Try features marked as EXPERIMENTAL : Y
  • Prefix : ${HOME}/local/share/${CT_TARGET} . Provide a destination folder that suits your needs, give descriptive name if you plan to host more than one crosscompilers.
  • Number of parallel jobs : 8 (depends on host capabilities of course).
  • EDIT minor : Uncheck “Render the toolchain read-only” (I find it annoying to have read only directory in my stuff, it’s problematic to delete it later, you have to chmod etc).
  • Check “Debug Crosstool-NG”, “Save intermediate steps”, and “gzip saved states” as described here.

02-paths-and-misc

Target options

  • Target Architecture : arm
  • (cortexm4) Suffix to the arch-part (breaks the build!). EDIT : trying with this turned on in 1.21.0, and works.
  • Use the MMU : N
  • Architecture level : armv7-m (EDIT armv7e-m was probably added since gcc-4.9). As you can find here, the ARM architecture for Cortex-M4 is ARMv7E-M. In GCC manual (type /, and -march a few times) we can find that, among many others, available values for -march are armv7, armv7-a, armv7-r, armv7-m. Unfortunately the armv7e-m is invalid (if someone could elaborate on that, it would be perfect), so I choose the most similar armv7-m option. EDIT here : I’ve found that they added armv7e-m in recent version of GCC.
    EDIT : armv6-m for Cortex-M0. You can always check it in the “programming manual” of every STM32 part in chapter entitled like “About the STM32 Cortex-M0 processor and core peripherals”
  • Emit assembly for CPU : cortex-m4 (full list of available options can be found in GCC manual somewhere near -mcpu phrase). Or here.
  • Tune for CPU : empty (empty because -mcpu was provided. -mtune is similar to -mcpu, but -mcpu restricts us to one CPU only, while -mtune tries to do its best to optimize for particular CPU while still retaining the possibility to compile for other CPUs).
  • Use specific FPU : fpv4-sp-d16. Cortex-M4 can have FPU, but not necessarily (with FPU it is called Cortex-M4F, and Cortex-M4 without). But the fact is I found this option somewhere over the net, and I am a little bit confused on the topic of FPU.
  • Floating point : hardware (FPU). EDIT : M0 have no FPU.
  • Default instruction set mode (thumb).

03-target-options Toolchain options. Add some cool Toolchain ID string: 04-toolchain-options Operating System. Set Target OS to bare-metal: 05-operating-system

Binary utilities

  • Binary format: (Flat) use ELF
  • binutils version (2.22) – latest which is not marked as EXPERIMENTAL. EDIT just recently I went with 2.24 (EXPERIMENTAL), and everything seems to be OK.

06-binary-utilities

C compiler

  • Show Linaro versions : Y
  • gcc version (linaro-4.8-2013.06-1)
  • C++ : Y

07-c-compiler   C-library

  • C library (newlib)
  • newlib version (2.0.0 (EXPERIMENTAL)) – the newest, and works OK.
  • Disable the syscalls supplied with newlib : Y – I provide my own syscalls in every program.

08-c-library Debug facilities

  • gdb : Y

09-debug

Then dig into “GDB” and check show lianro versions, and choose the newest from linaro, and set Enable python scripting to N (caused build problems for me) EDIT: qtcreator requires python support in GDB:

10-gdb-cfg

Exit menu-config (few times ESC, and save when prompted) and finally build the toolchain:

unset LD_LIBRARY_PATH 
ct-ng build
tail -f build.log # in another console (not necessary if debug options were set)

The build process takes some time (30-60 minutes), and if in some point for some reason the build fail, first place you check is the build.log file in staging directory (therefore I pasted this tail -f command earlier, but of course it does not matter how you display the file). For example, in my case, the crosstool-NG decided to fail with this:

... kilobytes, megabytes of logs ....
[ALL  ]    checking whether to use python... yes
[ALL  ]    checking for python... /usr/bin/python
[ALL  ]    checking for python2.7... no
[ERROR]    configure: error: python is missing or unusable
[ERROR]    make[2]: *** [configure-gdb] Error 1
[ALL  ]    make[2]: Leaving directory `/home/iwasz/Documents/my-toolchain/staging/.build/arm-unknown-eabi/build/build-gdb-cross'
[ERROR]    make[1]: *** [all] Error 2
[ALL  ]    make[1]: Leaving directory `/home/iwasz/Documents/my-toolchain/staging/.build/arm-unknown-eabi/build/build-gdb-cross'
[ERROR]  
[ERROR]  >>
[ERROR]  >>  Build failed in step 'Installing cross-gdb'
[ERROR]  >>        called in step '(top-level)'
[ERROR]  >>
[ERROR]  >>  Error happened in: CT_DoExecLog[scripts/functions@257]
[ERROR]  >>        called from: do_debug_gdb_build[scripts/build/debug/300-gdb.sh@170]
[ERROR]  >>        called from: do_debug[scripts/build/debug.sh@35]
[ERROR]  >>        called from: main[scripts/crosstool-NG.sh@632]
[ERROR]  >>
[ERROR]  >>  For more info on this error, look at the file: 'build.log'
[ERROR]  >>  There is a list of known issues, some with workarounds, in:
[ERROR]  >>      '/home/iwasz/local/share/doc/crosstool-ng/ct-ng.1.19.0/B - Known issues.txt'
[ERROR]  
[ERROR]  (elapsed: 58:52.70)

I didn’t thought long on this one (apt-get install libpython2.7-dev maybe???), but disabled the python support for GDB (I modified the instructions accordingly, so hopefully you haven’t had the same error). But in case you had, you should resolve the error (maybe change the configuration using menuconfig, or resolve the problem in other ways, depending on the cause) and rerun ct-ng, or refer to this stack-overflow thread for more info on speeding up the process after build has failed.


Edit Feb 2015 : I recently made cross-compiler x86_64 -> i686 to be able to make 32bit binaries on by 64bit box. Statically linked binaries made with it crashed with message:

FATAL: kernel too old

Following suggestions found here, I found that indeed, my binaries were (output of file command):

ELF 32-bit LSB  executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.15.4, not stripped

But my uname -a is:

Linux xxx 3.13.0-44-generic #73-Ubuntu SMP Tue Dec 16 00:22:43 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

The solution is to instruct crosstool-ng so it compile glibc/eglibc with older kernel support. Invoke ct-ng menuconfig and:

  1. Go into “C-library”
  2. Go into “Minimum supported kernel version (Specific kernel version) —>”
  3. Check “(X) Specific kernel version”
  4. “ESC ESC” and make sure that : “(2.6.9) Minimum kernel version to support”

EDIT (mar 2016). For the second time I encountered an error like this:

[ALL  ]    /usr/bin/install: cannot stat ‘…/.build/src/newlib-linaro-2.2.0-2015.01/libgloss/arm/linux.specs’: No such file or directory

According to this, and especially this , the error is caused by some bug in newlib itself. User ‘bhundvensugested that suffix ‘hf’ to ‘eabi’ (making it ‘eabihf’) is causing problems, so I turned off ‘Target options —> append ‘hf’ to the tuple (EXPERIMENTAL)’, and it helped.

4 comments for “Toolchain for Cortex-M4/M0/M7

  1. Mike
    March 13, 2015 at 8:49 pm

    Hey, this is a pretty good tutorial. I made a few tool chains, one for the M3 and two for the M4: one with the hardware FPU and one without FPU. All of the above work excellent!

    Thanks for a great article, I will probably put one together specifically for the M0 next!

    • admin
      March 18, 2015 at 7:25 pm

      Thanks!

  2. Alex
    July 2, 2016 at 9:49 pm

    Hello there, thank you for this great bit of information.
    So many things to set up properly ! I’ve already made several toolchains for M4 devices, but lost my configurations a while ago and this really helped to put another one together.
    Cheers, Alex

Leave a Reply

Your email address will not be published. Required fields are marked *