Getting the ARM toolchain to work on Ubuntu 19.04 and later (including for Black Magic Probe (BMP))

The short version is: Download the tar ball from arm.com, extract, add the /bin folder in the extracted to the path, and make GDB work by adding symbolic links in /usr/lib/x86_64-linux-gnu for the expected version 5 of the libraries “libncurses” and “libtinfo” (to point to the existing/newest versions of those libraries).

Introduction

This post contains complete instructions to set up the GCC cross-compiler from scratch on a newly installed Ubuntu 19.04 (Disco Dingo) or later (no extra packages assumed to be installed), compiling a “Hello, World!” (LED blink) program for an ARM board (1bitsy), flashing it to the board using GDB and the Black Magic Probe, and interactively single-stepping the program in GDB.

The installation part is completely general and the LED blink part only requires specifying another processor (as the used library works on multiple ARM processors). The flash and debugging part in GDB is dependent on an adapter that implements the GDB debugging protocol (Black Magic Probe is used as an example here).

Only the last part is specific for Black Magic Probe.

The problem

A previous blog post covered using apt-get to install the GCC cross-compiler for ARM:

sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
sudo apt-get update
sudo apt-get install gcc-arm-embedded

While this still works on Ubuntu 18.04 (32 bit) and Ubuntu 16.04 (64 bit), it no longer works on Ubuntu 19.04 and later:

E: Unable to locate package gcc-arm-embedded

Even when using the new procedure to get the compiler to run, there are also problems getting GDB to run. For further details, see Appendix A.

Step-by-step procedure

The following can be blindly applied. It has been tested on a 64-bit Ubuntu MATE 20.04 (Focal Fossa) system and a 64-bit Ubuntu 19.10 (Eoan Ermine) system and is likely to also work on a 64-bit Ubuntu 19.04 (Disco Dingo) system.

Setting up the cross compiler

Before starting, uninstall any already-installed ARM GCC cross compiler (this command can be used unconditionally – if it is not installed, it will report “Package ‘gcc-arm-none-eabi’ is not installed, so not removed”):

sudo apt remove gcc-arm-none-eabi 

Instead of using apt-get, we get the toolchain directly from arm.com as a tar ball. This is actually much simpler than it sounds: Download it, extract it, and add the location of the /bin folder in the extracted folder to the path (environment variable “PATH”). That’s it. In detail:

In the following, the sample path “/temp2/2019-12-05” under the current user is used to download and extract into. You may want some other folder(s) – adjust as needed.

Go to arm.com and find “Linux x86_64 Tarball”. Download “gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2” to ~/temp2/2019-12-05 (direct download URL (valid as of 2019-12-07)), MD5 FE0029DE4F4EC43CF7008944E34FF8CC. It is about 110 MB.

Extract it. For example, in Nautilus (the default file manager in Ubuntu), right click on the .bz2 file, select “Open with Archive Manager”, select the single folder, right click on it, select “Extract”, press button “Extract”, wait for it to finish, “Close”, and close Archive Manager.

Alternatively, on the command line:

cd ~/temp2/2019-12-05
tar xvzf gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2

Install other required packages:

sudo apt-get update
sudo apt-get install ncurses-dev
sudo apt-get install git
sudo apt-get install make
sudo apt-get install python-minimal

For initial testing (in the same session), this suffices:

cd ~
export PATH=$PATH:~/temp2/2019-12-05/gcc-arm-none-eabi-9-2019-q4-major/bin
arm-none-eabi-c++  --version

The output should look something like this:

arm-none-eabi-c++ (GNU Tools for Arm Embedded Processors 9-2019-q4-major) 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599]
Copyright (C) 2019 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.

For more permanent use, put this into the .profile file, near the end, in the user top folder, using some text editor (Vim/vi in this example – but you need to be proficient in using Vim/vi. Otherwise, use another editor, like nano or Geany):

vi ~/.profile
PATH=$PATH:~/temp2/2019-12-05/gcc-arm-none-eabi-9-2019-q4-major/bin

After the change, it may be necessary to login/logout or restart the computer to make the change take effect (it may not be enough to open a new terminal window).

Compiling the blink program

Get source code for a Hello, World! (blink) example program:

cd ~
git clone https://github.com/1bitsy/1bitsy-examples.git
cd 1bitsy-examples
git submodule init
git submodule update

On Ubuntu 20.04 and later, change “python” in the very first line of file “irq2nvic_h” to “python3” (see the appendix for details):

vi ~/1bitsy-examples/libopencm3/scripts/irq2nvic_h

Compile:

make

Check that it produced the executable:

ls -ls ~/1bitsy-examples/examples/1bitsy/fancyblink/*.elf

The result should be something like (broken up in two lines here):

112 -rwxrwxr-x 1 embo embo 234364 Jan 19 19:19 
/home/embo/1bitsy-examples/examples/1bitsy/fancyblink/fancyblink.elf

Getting GDB to work

This presumes the current version of “libncurses” and “libtinfo” is 6.2 (“libncurses.so.6.2” (160 KB) and “libtinfo.so.6.2” (190 KB) exist in folder “/usr/lib/x86_64-linux-gnu”). If not, adjust the version numbers accordingly (in Ubuntu 19.10, the version is 6.1 instead of 6.2.)

cd /usr/lib/x86_64-linux-gnu
sudo ln -s libncurses.so.6.2 libncurses.so.5
sudo ln -s libtinfo.so.6.2   libtinfo.so.5

This puts in symbolic links for the libraries GDB is expecting (version 5).

Verify:

ls -ls /usr/lib/x86_64-linux-gnu | grep libncurses.so.5
ls -ls /usr/lib/x86_64-linux-gnu | grep libtinfo.so.5

The output should look like:

0 lrwxrwxrwx  1 root root 17 Jan 19 15:38 libncurses.so.5 -> libncurses.so.6.2
0 lrwxrwxrwx  1 root root 15 Jan 19 15:38 libtinfo.so.5 -> libtinfo.so.6.2

Check that GDB works:

arm-none-eabi-gdb --version

The output should be something like:

GNU gdb (GNU Tools for Arm Embedded Processors 9-2019-q4-major) 8.3.0.20190709-git
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Setting up for hardware

id
sudo adduser $USER dialout
id

(Related Ask Ubuntu question. The reason why it is “dialout”.)

The output should include “(dialout)” in the “groups=” part. In that case, log out and log in. If it is not in the output, a restart of the computer is required (if a restart is not done the result is “Permission denied” in the “target extended-remote /dev/ttyACM0” line below).

Connect the Black Magic Probe with a microUSB cable.

dmesg | tail

Output includes: “ttyACM0” and “ttyACM1”. “ttyACM0” is the COM port that GDB uses to communicate with the Black Magic Probe and “ttyACM1” is the auxiliary COM port that can be used to connect to the target board’s serial port (so it is not necessary to use a separate USB-to-serial adapter).

Note that if some device with a serial port, for example, an Arduino, was already connected, the numbers are shifted, “ttyACM1” and “ttyACM2”

Connect the 1bitsy with a microUSB cable.

dmesg | tail

Output includes: “ttyACM2” – but only if there is already firmware on it that makes it appear as a serial device. This is not the case for the Kickstarter one…

Connect 1bitsy and Black Magic Probe using the JTAG cable. Note: the ribbon cable is to come from the same direction as the USB cable. That is, the ribbon cable should not cover the main chip/IC of the 1bitsy.

Flashing the blink program

cd ~/1bitsy-examples/examples/1bitsy/fancyblink
arm-none-eabi-gdb fancyblink.elf
target extended-remote /dev/ttyACM0
monitor version
monitor help
monitor jtag_scan
attach 1
load

Debugging with GDB

run
y
<Ctrl + C>
list

Note: ‘run’ (or ‘start’ or repowering) is required if updating/changing the source code. The changes do not take effect before restarting, that is, flashing (‘load’ in the previous step) will not actually make it start execute the newly flashed program (the old one is still RAM and is still executing).

Debugging in full-screen mode

Using a line debugger is like being trapped in the 1970s. However, GDB can also do full-screen debugging.

It can also be put into a mode when Enter does not have to pressed for each command. Thus it can come close to an experience of what is expected of a debugger.

Enable full-screen mode:

tui enable

It immediately shows a screen with about 10 lines on each side of the current line:

Screen of cross GDB in TUI mode connected to ARM board 1-bitsy through Black Magic Prove

Enable single key mode: Ctrl + X, C

Exit single key mode: Q

Continue, break into the running program (on the 1bitsy), and do some step over and step in operations:

cont
<Ctrl + C>
step
start
y
next
step
next
next
next
cont

In GDB, ‘next’ (short ‘n’) is step over (like F10 in Visual Studio), ‘step’ (short ‘s’) is step in (like F11 in Visual Studio), and ‘finish’ (short ‘fin’) is step out (like Shift + F11 in Visual Studio).

Quit debugging:

<Ctrl + C>
quit
y

Testing

This procedure was tested on Ubuntu 19.04 and Ubuntu 20.04 MATE with standard AMD PC hardware (64-bit, 8 GB RAM, etc.). For previous blog posts, it was tested on Ubuntu 16.04, Ubuntu 17.10, and Ubuntu 18.04 (some in 32-bit editions).

This blog post will continue to be updated as new versions of Ubuntu (and some other Linux distributions), the ARM cross compiler, Python, libopencm3, etc. becomes available (though possibly with some delay – express interest in comments to speed it up).

Appendix A Error messages and troubleshooting

While the main part of this post is focused on getting the toolchain installed as quickly as possible and up and running when debugging on ARM, this appendix documents the error messages that you may run into, the troubleshooting, and the background information on why the instructions are as they are.

‘apt-get’ blues

On Ubuntu 19.04 and later, this does not work:

We get this error:

E: Unable to locate package gcc-arm-embedded

tar blues

Using ‘tar’ on the command line to extract the GCC cross-compiler tar ball may lead to this output:

gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now

The current resolution is to use the file manager instead (as described in the main part of this blog post).

PATH setup blues – using Vim

When using Vim/vi to edit file ‘.profile’ this may be the result when pasting in the path line (the error message includes the quote at the end):

E353: Nothing in register "

The reason is that Vim/vi is not in insert mode. The first character in the clipboard, “P” in “PATH=$PATH:~/temp2/2019-12-05/gcc-arm-none-eabi-9-2019-q4-major/bin”, is seen a command, not something to paste. A direct paste actually sometimes works if using a command-line window on Ubuntu, but it may not always work, e.g., if using SSH to connect to another computer, etc.

The resolution is to enter insert mode explicitly by pressing “i” first.

Python blues

Using ‘make’ (when the PATH environment variable has been correctly set up), may result in this error:

  GENHDR  include/libopencm3/lpc17xx/irq.json
/usr/bin/env: ‘python’: No such file or directory
make[1]: *** [Makefile:55: include/libopencm3/lpc17xx/irq.json.genhdr] Error 127
make: *** [Makefile:54: lib] Error 2

The reason is that with Ubuntu 20.04 and later, the executable for the Python interpreter is no longer ‘python’, but ‘python3’ – the executable ‘python’ (for Python 2) was removed. And the library “libopencm3” used by the example code has not yet been updated to reflect this fact (even though there was some discussion in November 2020).

The resolution is to change “python” in the very first line of irq2nvic_h to “python3” (in our example, the file is at “~/1bitsy-examples/libopencm3/scripts/irq2nvic_h”). The result should be “#!/usr/bin/env python3”.

GDB blues

If GDB is launched after the tar ball has been installed (so the compiler can be invoked from anywhere),

arm-none-eabi-gdb --version

this is the likely result:

arm-none-eabi-gdb: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory

We will add some symbolic links, but first, to be confident we are making the changes in the right folder (for 32 bit or 64 bit libraries), find out the bitness of GDB (32 bit or 64 bit):

file ~/temp2/2019-12-05/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gdb

For 64 bit, the result includes “arm-none-eabi-gdb: ELF 64-bit LSB executable, x86-64”.

For 64 bit, the “libncurses” library lives in “/usr/lib/x86_64-linux-gnu”:

cd /usr/lib/x86_64-linux-gnu
ls -ls | grep libncurses

The output includes:

    4 -rw-r--r-- 1 root root     31 Aug  9 12:18 libncurses.so
    0 lrwxrwxrwx 1 root root     17 Aug  9 12:18 libncurses.so.6 -> libncurses.so.6.1
  160 -rw-r--r-- 1 root root 162024 Aug  9 12:18 libncurses.so.6.1

There is the symbolic link “libncurses.so.6”, but not “libncurses.so.5” that GDB expects.

Add it by:

cd /usr/lib/x86_64-linux-gnu
sudo ln -s libncurses.so.6.1 libncurses.so.5

If we try starting GDB again we get (a different error message):

arm-none-eabi-gdb: error while loading shared libraries:
libtinfo.so.5: cannot open shared object file: No such file or directory

As for libncurses, so for “libtinfo” from the error message:

cd /usr/lib/x86_64-linux-gnu
ls -ls | grep libtinfo

The output includes:

  0 lrwxrwxrwx 1 root root     35 Aug 9 12:18 libtinfo.so -> /lib/x86_64-linux-gnu/libtinfo.so.6
  0 lrwxrwxrwx 1 root root     15 Aug 9 12:18 libtinfo.so.6 -> libtinfo.so.6.1
188 -rw-r--r-- 1 root root 192032 Aug 9 12:18 libtinfo.so.6.1

Like for libncurses, there is the symbolic link “libtinfo.so.6”, but not “libtinfo.so.5” that GDB expects.

Add it by:

cd /usr/lib/x86_64-linux-gnu
sudo ln -s libtinfo.so.6.1   libtinfo.so.5

After this GDB finally works:

arm-none-eabi-gdb --version

The output includes:

GNU gdb (GNU Tools for Arm Embedded Processors 9-2019-q4-major) 8.3.0.20190709-git

 

4 comments

  1. I have gone to this step: “make”, but it was prompting: “arm-none-eabi-gcc: Command not found”.

    I tried to fix it by “vi ~/.profile
    PATH=$PATH:~/temp2/2019-12-05/gcc-arm-none-eabi-9-2019-q4-major/bin”, but it couldn’t be edited. It prompted: “E353: Nothing in register”. How can I fix it?

    1. What did you do in vi/Vim to paste?

      The most likely reason is that vi/Vim was not in insert mode when you pasted. Before pasting, press “i” first to explicitly enter insert mode. After pasting, exit insert mode by pressing the “Esc” key. Save and exit by ‘:wq’.

      Alternatively, use another editor, like nano or Geany.

      What system are you using? Linux distribution and version?

      1. I used Ubuntu 20.04 LTS, and I altered it to nano. It was fixed, but there was a new problem: “Compiling the blink example” was not working.

        1. The compile problem can be fixed by editing file “irq2nvic_h” (despite the name looking like a C header file, it is actually a Python scritpt).

          In ~/1bitsy-examples/libopencm3/scripts/irq2nvic_h, change “python” in the very first line to “python3” (the result should be “#!/usr/bin/env python3”).

          The reason is that in Ubuntu 20.04, the executable ‘python’ (for Python 2) was removed. And the library “libopencm3” used by the example code has not yet been updated to reflect this fact (even though there was some discussion in November 2020).

          I have now checked the whole process, incl. using the GDB debugger with the actual hardware (Black Magic Probe and 1bitsy) on Ubuntu MATE 20.04 (Focal Fossa), and I am updating the blog post.

Leave a comment

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