Building a Bare-Metal ARM GCC Toolchain from Source

The GCC toolchain is a nice way to get started with bare-metal ARM platforms because it is free, well-supported, and something that many C programmers are already familiar with. It is also constantly improving, and while most Linux distributions include a version of the arm-none-eabi GCC toolchain in their default package managers, those versions are sometimes old enough that I run into bugs with things like multilib/multiarch support.

So after trying and failing a few times to build and install this toolchain, I thought I would share what eventually worked for me. If you are building this on a system without much free disk space, this did take about 16GB of disk space when I ran it – but you shouldn’t need to keep more than ~500MB of that. I ended up building it on an ext3-formatted 32GB USB drive, and that seemed to work fine. You will probably run into errors if you try to run this on a FAT-formatted drive like a new USB stick, though, because the build process will run chmod and that will fail on a filesystem that doesn’t support file permissions. You might be able to make it work with an NTFS drive, but I digress.

Anyways, the first step is downloading the code, so let’s get started!

Step 1: Download the Source Code

The first step is to download the arm-none-eabi-gcc source code from ARM’s website – you want the “Source Invariant” version. If you are using a common architecture such as x86_64, you can also download a pre-built version of the latest release, but you probably want to build the thing yourself if you are reading this guide. If you want to make sure that the file you downloaded was not corrupted or tampered with, you can check it against the MD5 checksum listed under the file’s name on the download page:

That looks like it matches as of the time of writing. The archive contains build scripts and code for the whole toolchain, so create a new directory to build the toolchain in – I’ll use ~/arm_gcc/ as an example. Once it finishes downloading, move the archive to that folder and extract it:

The file that I downloaded was called gcc-arm-none-eabi-8-2018-q4-major-src.tar.bz2, but yours will depend on where you are in time. The extracted archive will make a new directory with a similar name – take a look inside, and you’ll see a few scripts and a ‘how-to’ document alongside the source code:

Step 2: Build the Toolchain

The How-to-build-toolchain.pdf file contains instructions for setting up and running the build – it’s almost as simple as installing the prerequisites and running a few scripts in sequence, but there are a few things worth calling out. First, read the ‘how-to-build’ document. It’s short, and if you read it you won’t go looking for a Makefile in the src/ directory like I did.

The prerequisites are easy to install; if you are using a Debian-based Linux distribution like Ubuntu, this command should work with the version of GCC that I wrote this guide for (don’t forget to use sudo or be root):

If you are building a newer version of the toolchain than the “2018-Q4” release, double-check the ‘how to build’ document to make sure those are the only dependencies that you need. And some of these packages might be fairly large, but I think you can probably omit the texlive packages if you tell the build system to skip creating manuals and documentation in the final step (mentioned below).

Once the dependencies are installed, proceed to step 1.3 in the ‘how-to-build’ document (titled, “Build GNU Tools for Arm Embedded Processors”). Note that I haven’t built the toolchain on Mac OSX, and it looks like there are some extra steps for that environment.

The first step after un-zipping the source files is to run the install-sources.sh script, which extracts the source code for each part of the toolchain. It also downloads some supporting libraries, so you’ll need internet access for this step as well as the previous one:

./install-sources.sh --skip_steps=mingw32

The --skip_steps=mingw32 option tells the build system not to create a Windows-compatible toolchain. Since I only plan to run this on the Linux host it was built on, this option saves time and space. If you do need to build a Windows toolchain, I guess you can skip the ‘skip_steps’ step for all of these scripts.

Once the sources are extracted (the larger archives might take a little while to unpack), you can set up the build system and supporting libraries with:

./build-prerequisites.sh --skip_steps=mingw32

This step will also take a little while as it runs through a ‘configure/make’ cycle for each dependency that it needs to build. Once it is done, you can build the toolchain itself. And while I haven’t tried this, it looks like you can skip building the manuals and documentation if you didn’t want to install the large texlive packages by passing in --skip_steps=mingw32,manual instead:

./build-toolchain.sh --skip_steps=mingw32

This will take even longer than the previous step – it can easily run for several hours (or even longer on a slow machine,) and in my case the terminal output froze towards the end of the process; I had to guess when it finished by checking that there were no more compiler/linker/etc processes running and that the size of the build folder stopped changing.

When the build does finish, you should find a directory called install-native/ in the same directory that you ran the build scripts in. That folder will contain the finished toolchain which we will install in the next step.

And if you want to backup the toolchain so you don’t need to re-build it later, there should also be a directory called pkg/ which contains two tarballs. One contains the same final build as the install-native/ directory, and the other contains the toolchain’s source code as it was generated for your platform.

Step 3: Install the Toolchain

It looks like the toolchain’s build contains four directories: bin/, lib/, share/, and arm-none-eabi/. I’m not sure why it creates the extra arm-none-eabi/ directory, and you might be able to adjust this by using common command-line options like --prefix during the build stage, but I didn’t look into that too much. It might bother you if you really like having a clean filesystem though, because the process I used to install the toolchain is embarrassingly simple – just copy everything into the /usr directory:

cp -R install-native/* /usr/
sudo ldconfig

You can check that the program was installed and view some basic information about its path settings with basic diagnostic commands like which arm-none-eabi-gcc and arm-none-eabi-gcc -print-search-dirs.

To uninstall the toolchain, you should be able to just remove the directories which you copied – in my case those were:

I also ended up with a few libcc1.so files under the lib/ directory, but that looks like an already-reported bug. It may cause conflicts with avr-gcc, but I’m one of those people who can’t see any point to using an AVR core these days; it seems like you pay more for less when there are options like MSP430s or PICs on the cheap/low-power/simple end and Cortex-M0s on the cheap/high-power end.

Conclusions

That should be all there is to it – after running ldconfig, you should be able to use the arm-none-eabi toolchain normally. In my case, building and installing an up-to-date version of the toolchain fixed an issue where GCC tried to link a soft-float math library for a hard-float build. I got the project to build by using the -mfloat-abi=softfp option, but actually running a floating-point operation still caused the chip to crash. With this fresh toolchain, I can build with -mfloat-abi=hard and my Cortex-M4F chip can calculate an arctangent 🙂

So maybe I was mis-configuring things, maybe I was using new configuration flags that the older toolchain didn’t recognize, maybe I forgot to install some library from the package manager, or maybe (against all probability) it was actually a compiler bug. But sometimes it makes more sense to just re-install the latest stable version of something instead of trying to muddle through a tricky issue which you can’t find much information about. Sure you can write a bug report, but if updating to a newer version fixes the bug, there’s probably not much point.

Anyways, happy compiling! And corrections are always welcome; like I said, I wrote this guide mostly because I messed the process up so many times before getting it to work, so…what does that tell you?

Comments (1):

John Sok

February 22, 2019 at 4:31 am

Perfect!! This is just barely above my current level of knowledge (for now), very helpful, thanks ! What direction are you thinking following this? Bottom => Up or Top => Down ? More project applications ? Good application topics indeed. Thanks..

Related posts:

Several years ago, a company called Future Technology Devices International (FTDI) sold what may have been the most popular USB / Serial converter on the market at the time, called the FT232R. But this post is not about the FT232R, because that chip is now known for its sordid history. Year after year, FTDI enjoyed their successful chip’s market position – some would say that they rested too long on their laurels without innovating or reducing prices. Eventually, small microcontrollers advanced to the point where it was possible to program a cheap MCU to identify itself as an FT232R chip and do the same work, so a number of manufacturers with questionable ethics did just that. FTDI took issue with the blatant counterfeiting, but they were unable to resolve their dispute through the legal system to their satisfaction, possibly because most of the counterfeiters were overseas and difficult to definitively trace down. Eventually, they had the bright idea of publishing a driver update which caused the counterfeit chips to stop working when they were plugged into a machine with the newest drivers.

FTDI may have technically been within their rights to do that, but it turned out to be a mistake as far as the market was concerned – as a business case study, this shows why you should not target your customers in retaliation for the actions of a 3rd party. Not many of FTDI’s customers were aware that they had counterfeit chips in their supply lines – many companies don’t even do their own purchasing of individual components – so companies around the world started to get unexpected angry calls from customers whose toy/media device/etc mysteriously stopped working after being plugged into a Windows machine. You might say that this (and the ensuing returns) left a bad taste in their mouths, so while FTDI has since recanted, a large vacuum opened up in the USB / Serial converter market almost overnight.

Okay, that might be a bit of a dramatized and biased take, but I don’t like it when companies abuse their market positions. Chips like the CH340 and CH330 were already entering the low end of the market with ultra-affordable and easy-to-assemble solutions, but I haven’t seen them much outside of Chinese boards, possibly due to a lack of multilingual documentation or availability from Western distributors. So at least in the US, the most popular successor to the FT232R seems to have been Silicon Labs’ CP2102N.

It’s nice to have a cheap-and-cheerful way to put a USB plug which speaks UART onto your microcontroller boards, so in this post, I’ll review how to make a simple USB / UART converter using the CP2102N. The chip comes in 20-, 24-, and 28-pin variants – I’ll use the 24-pin one because it’s smaller than the 28-pin one and the 20-pin one looks like it has some weird corner pads that might be hard to solder. We’ll end up with a simple, small board that you can plug into a USB port to talk UART:

Drivers for the CP2102N are included in most popular OSes these days, including Linux distributions, so it’s mostly plug-and-play.

It’s worth noting that you can buy minimal CP2102N boards from AliExpress or TaoBao for about $1, but where’s the fun in that?

It has been about nine months since ST released their new STM32G0 line of microcontrollers to ordinary people like us, and recently they released some new chips in the same linup. It sounds like ST wants this new line of chips to compete with smaller 8-bit micros such as Microchip’s venerable AVR cores, and for that market, their first round of STM32G071xB chips might be too expensive and/or too difficult to assemble on circuit boards with low dimensional tolerances.

Previously, your best bet for an STM32 to run a low-cost / low-complexity application was probably one of the cheaper STM32F0 or STM32L0 chips, which are offered in 16- and 20-pin TSSOP packages with pins spaced 0.65mm apart. They work great, but they can be difficult to use for rapid prototyping. It’s hard to mill or etch your own circuit board with tight enough tolerances, and it’s not very easy to solder the chips by hand. Plus, the aging STM32F031F6 still costs $0.80 each at quantities of more than 10,000 or so, and that’s pretty expensive for the ultra-cheap microcontroller market.

Pinout and minimal circuit for an STM32G031J6 – you only really need one capacitor if you have a stable 3.3V source.

Enter the STM32G031J6: an STM32 chip which comes in a standard SOIC-8 package with 32KB Flash, 8KB RAM, a 64MHz speed limit, and a $0.60 bulk price tag (closer to $1.20-1.40 each if you’re only buying a few). That all compares favorably to small 8-pin AVR chips, and it looks like they might also use a bit less power at the same clock speeds. Power consumption is a tricky topic because it can vary a lot depending on things like how your application uses the chip’s peripherals or what voltage the chip runs off of. But the STM32G0 series claims to use less than 100uA/MHz, and that is significantly less than the 300uA/MHz indicated in the ATTiny datasheets. Also, these are 32-bit chips, so they have a larger address space and they can process more data per instruction than an 8-bit chip can.

Considering how easy STM32 chips are to work with, it seems like a no-brainer, right? So let’s see how easy it is to get set up with one of these chips and blink an LED.

As someone who likes both electronics and the outdoors, sometimes I get anxiety about a lack of electricity. It would be nice to go camping somewhere away from it all, and still be able to charge things and run some lights, a display, maybe a small cooler. I’m sure some of you are rolling your eyes at that, but I’ve also been wanting to play with adding aftermarket indicators to old cars, like backup sensors or blind spot warnings, and it’d be nice to run them off a separate battery to avoid the possibility of accidentally draining the car’s battery overnight.

Since low-power solar panels are fairly cheap these days, I figured that it might be worth buying a few to mount to my car’s roof. And since my car is technically a pickup, it was very easy to put the battery in the bed and run the wiring through the canopy’s front window:

I’ve secured the battery a bit more since taking these pictures, but this is the basic idea – it’s pretty simple.

If you have a different kind of car, I’d imagine that you could just as easily put the battery in your trunk, but you might need to drill a hole for the wires if you don’t want to leave one of your windows cracked open.

I guess that a lot of this guide won’t apply exactly to your situation, because you’ll have different dimensions to work with, different limitations, and probably different solar panels. But I hope that laying out each step that I took and what worked for me might be helpful – your basic approach could probably look very similar.

And before we go any further, please keep your expectations in check. These panels can only produce up to 100W in direct sunlight, which is nowhere near enough power for something like an electric vehicle. So read on if this sounds interesting, but the car still runs on gas. We’re not saving the world here.