Tag Archives: embedded

Using Docker to cross-compile embedded software

Are you tired of managing the installation of different cross-development toolchains on the same machine, fixing issues when your compiler does not work after a host OS upgrade or having to deal with the same toolchain being installed in heterogeneous environments?

Docker fixes some of these issues by providing a light-weight virtualization layer that isolates the cross-development toolchains from the host OS, allows the easier coexistence of different tools in the same machine, and facilitates their management and deployability.

We have been facing these problems while developing software for an Infineon XMC4800 microcontroller on a Linux host, and have improved our process by using a Docker cross-compilation container with the following features:

  • Docker container based on Ubuntu 18.04 LTS
  • GNU ARM toolchain
  • Infineon XMC libraries for XMC4800
  • Segger JLink tool for target flashing and debugging
  • Container compiles code from the host invocation directory
  • Use of ccache to speed up subsequent compilations

This is our resulting Dockerfile:

# Root image built from LTS ubuntu in Docker Hub.
FROM ubuntu:18.04

MAINTAINER Juan Solano "jsm@jsolano.com"

# Update this variable to force a refresh of all base images and make
# sure subsequent commands do not use old cache versions.
ENV REFRESHED_AT 2018-11-26

ARG USERNAME="docker"
ARG USERGROUP="dckrgroup"
ARG DEBIAN_FRONTEND=noninteractive
# These can be overriden with a command line option when the image is
# built, e.g. --build-arg UID=$(id -u) --build-arg GID=$(id -g).
ARG UID=1000
ARG GID=1000
ARG GCC_ARM_TOOLCHAIN_VER="gcc-arm-none-eabi-7-2018-q2-update"
ARG GCC_ARM_TOOLCHAIN_URL="https://developer.arm.com/-/media/Files/downloads/gnu-rm/7-2018q2/"$GCC_ARM_TOOLCHAIN_VER-linux.tar.bz2
ARG XMC_LIB_VER="XMC_Peripheral_Library_v2.1.18"
ARG XMC_LIB_URL="http://dave.infineon.com/Libraries/XMCLib/"$XMC_LIB_VER.zip
ARG JLINK_VER="JLink_Linux_V634g_x86_64"

# Set up the compiler path and other container environment variables.
ENV PATH $PATH:/home/$USERNAME/opt/$GCC_ARM_TOOLCHAIN_VER/bin
ENV GCC_ARM_TOOLCHAIN_VER $GCC_ARM_TOOLCHAIN_VER
ENV GCC_COLORS="error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01"
ENV USB_SCRIPT="usbdev_allow.sh"
ENV TZ=Europe/Berlin

RUN apt-get update -q \
    && apt-get install --no-install-recommends -y apt-utils \
    && apt-get install --no-install-recommends -y vim make sudo \
       tzdata libncurses5 ca-certificates unzip bzip2 libtool ccache \
       usbutils libusb-1.0-0-dev libusb-dev \
    && rm -rf /var/lib/apt/lists/*

# Set timezone and standard user.
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
    && echo $TZ > /etc/timezone \
    && groupadd --gid $GID $USERGROUP \
    && useradd -m -u $UID -g $GID -o -s /bin/bash $USERNAME \
    && echo "root:root" | chpasswd \
    && echo "$USERNAME:$USERNAME" | chpasswd \
    && usermod -a -G 20 $USERNAME \
    && adduser $USERNAME sudo \
    && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

# Set up a build tools directory.
RUN mkdir -p /home/$USERNAME/opt
WORKDIR /home/$USERNAME/opt
RUN chown $USERNAME /home/$USERNAME/opt \
    && cd /home/$USERNAME/opt

# Install JLink as root, before changing to standard user.
COPY $JLINK_VER.deb /home/$USERNAME/opt
RUN dpkg -i $JLINK_VER.deb \
    && rm $JLINK_VER.deb
COPY $USB_SCRIPT /home/$USERNAME/opt
RUN chmod +x /home/$USERNAME/opt/$USER_SCRIPT

# Further operations as standard user.
USER $USERNAME

# Install the XMC library.
COPY $XMC_LIB_VER.zip /home/$USERNAME/opt
RUN unzip $XMC_LIB_VER.zip \
    && rm $XMC_LIB_VER.zip

# Install the ARM cross-compilation toolchain.
COPY $GCC_ARM_TOOLCHAIN_VER-linux.tar.bz2 /home/$USERNAME/opt
RUN bunzip2 $GCC_ARM_TOOLCHAIN_VER-linux.tar.bz2 \
    && tar xvf $GCC_ARM_TOOLCHAIN_VER-linux.tar \
    && rm $GCC_ARM_TOOLCHAIN_VER-linux.tar

# Required so that ccache files are kept in shared work directory.
RUN cd /usr/lib/ccache \
    && sudo ln -s ../../bin/ccache arm-none-eabi-gcc
ENV PATH /usr/lib/ccache:$PATH

# Create a directory for our project and setup a shared work directory.
RUN mkdir -p /home/$USERNAME/project
WORKDIR /home/$USERNAME/project
VOLUME /home/$USERNAME/project
RUN cd /home/$USERNAME/project \
    && mkdir -p $HOME/.ccache \
    && echo "cache_dir = $HOME/project/.ccache" >> \
       $HOME/.ccache/ccache.conf

Initially we added wget commands to the Dockerfile, so that the tools were directly downloaded before usage, but we have later decided to keep a local copy of our tools to speed up the Docker image creation. After creating the Docker image, compiling is just a matter of going to the directory where our source code lives and executing our make alias, which can be defined like e.g.:

alias xmcmake='docker run --rm -it --device=/dev/bus/usb --volume=$(pwd):/home/docker/project docker-arm-xmc make'

This starts a container based on the previously created docker-arm-xmc image, allowing access to the JLink usb port from inside the container, and executes the make command. After the make command is executed, the container exits and we can see our compiled binaries as well as a directory with the .ccache artifacts which will be used the next time the make command is invoked.

In subsequent posts, I will delve into additional development steps that can be realized with the help of this container. I hope you find this useful.

Industrial Beaglebone Black anyone?

Is it really possible to use the Beaglebone Black in industrial embedded projects? or it is just a maker/hobbyist platform?

I have been searching for an industrial version of the Beaglebone Black in order to leverage the great know-how and resources available on this great open source hardware platform to make it work reliably on industrial environments. A professional version would allow e.g. better platform longevity planning, reliability, customization or industrial temperature ranges. Last year there were some efforts that did not get anywhere.

The Beaglecore project in kickstarter seems like a great attempt at remedying this situation. It is a system on module (SOM) fully compatible with the existing Beaglebone Black, with features aimed at industrial computing and long-term availability. Help them achieve their goals!

Embedded Linux and ARM

Linux usage is growing enormously in embedded systems, thanks to its stability, being open source, the availability of drivers for a huge amount of hardware peripherals and its support for many networking protocols and filesystems. However, Linux exhibits some drawbacks in safety systems, where the code needs to be certified, or hard real-time systems where deadlines are critical.

Nowadays, some Linux installs in embedded systems have been deployed following a top-down approach, where no much care has been taken to remove unused software. This may have security implications, resulting also on code bloating and maintenance problems down the line of a software product lifecycle. I recommend following a bottom-up approach, where we control precisely the software installed in our systems. This helps in the long run with easier maintainability, and better security.

Why is ARM the dominant architecture on embedded systems? ARM follows a fabless model, with licensees competing with each other on SoCs that include an ARM core and a number of extensions. This model, together with the efficiency and elegancy of their design has made them number one, especially in power-conscious designs like mobile phones.

It is becoming very easy to port Linux to new hardware devices on X86, MIPS and ARM platforms. This is a list of popular ARM development platforms with ARM cores containing an MMU and therefore can be leveraged with standard Linux:

Embedded Linux support from board vendors

I have recently completed a project where I used a PC104 SBC (single-board computer) from a hardware vendor that sold our client a Linux development kit in addition to the hardware; the development kit included a busybox-based distribution with quite an old kernel (2.6.21) and a driver supporting some board-specific features. So far, so good. Very often the time required to build a distribution from scratch is more valuable than the price to pay for a commercial Linux distribution, so this approach is often the sensible one.

However, when we started developing the system, we realized that the provided driver included most of its functionality in a binary blob for which the vendor would not provide any source code or much support in the form of updates. We wanted to use a more recent kernel as 2.6.21 was lacking support for a GPS module we had attached to the board. According to the vendor, getting a binary driver compiled for a different kernel version was out of the question, as they did not have the expertise in-house. They even hinted at lacking some of the driver source, as their latest Linux expert (i.e. their only Linux developer) left the company years ago and they did not bother to set up everything in place to be able to build their driver before the Linux guy left. It is amazing that companies that build excellent hardware may exhibit such a slack attitude towards supporting their product with the most popular embedded OS today; it is even more amazing that they charge for such a development kit!

When starting to work on new hardware, we are confronted with the different options available for getting Linux on our boards; these are the main ones:

  • Roll your own distribution. There are a number of open source projects that can be leveraged to build your own distribution, like crosstool-ng, OpenEmbedded or Buildroot. These projects build a distribution based on your hardware requirements. However, this is not an easy task and you may find issues that require a lot of work from your part, depending on how the board and peripheral you use departs from a standard working configuration used by the distribution.
  • Use an open source distribution like Angström. These distributions are aimed at a specific set of boards. They are a good choice if your hardware is similar to some of the hardware supported by the distribution, otherwise they might require significant porting work.
  • Buy a Linux distribution from an independent vendor or consultant. There are different degrees of customization you can expect from vendors; some examples are Montavista, Wind River, or consultancies like DENX or Free Electrons.
  • Get Linux from the SBC vendor. This may be the shortest route to having a properly configured Linux distribution on your system; although you should pay attention at how committed the vendor is at supporting the issues you may find.

Whatever the route you chose, planning ahead and taking into account the different options is essential to the success of your project.

C++ for embedded?

Recently I was asked by a client about the advantages of C++ over C for a specific embedded project, and these are the ideas I came with:

C exhibits a narrower relationship between source and machine code, which sometimes makes debugging and code optimization easier. Some architectures also have better compiler support for C, although this applies chiefly to some not very common DSPs. In some cases, C may also provide more efficient usage of memory and a reduced runtime when compared to C++.

On the other hand, C++ provides many facilities through the STL that are not part of the standard C library. C++ facilitates information hiding and object orientation in cases where it might be useful. In addition to this, C++ exceptions simplify error handling without the error checking code frequently spread throughout a C program.

I don´t think other C++ features like templates and RTTI are so useful on embedded systems. If your compiler lets you turn these off completely, I would advise you to do it in order to get significant code size savings. It is always advisable to write a test program to check how well your compiler does with C++ features enabled.

The usage of C++ should be mandated by whether their features make sense in your product and a careful evaluation of the benefits they provide against their performance/size costs.

802.15.4 wireless sensor network prototyping

I have been looking into wireless sensor networks for some time, and I definitely need to jump into the wagon and order some development kits to play/experiment and build some prototypes. 802.15.4 is the radio layer used by Zigbee. I am not constrained to using specifically Zigbee and I prefer open-source stacks, but I would like to stay with 802.15.4 as it is more widespread than other technologies like DASH7. My current hardware options are:

  • Libelium. The Squidbee motes provide a prototyping solution based on Arduino, which is designed for teaching and educational purposes, while Waspmote is their commercial platform. They look very efficient and well built , with good documentation and support.
  • Openpicus. These guys provide an interesting platform for prototyping based on open-source software running FreeRTOS.
  • Some of the platforms based on TI’s CC2420 chip.

Wireless sensor networks need to be programmed in an efficient way due to the limited processing, storage and power resources of a typical sensor node, which is difficult to accomplish using high-level languages. Normally C or a specific dialect like e.g. nesC (used on TinyOS) is needed. The operating systems used on the different wireless sensor platforms can be split between free academic implementations, like TinyOs or Contiki, and proprietary OS layers used on Zigbee stacks, like TI´s Z-Stack, Freescale or Ember´s stack. These proprietary implementations don´t provide an unified C API, the only Zigbee compliance requirement being a correct over-the-air behavior. There have been some attempts at building an open-source Zigbee stack, but I am not aware of a successful one.

An interesting project is zigbee-linux, although it has a misleading name as it only covers 802.15.4. Zigbee itself is not compatible with the GPL, but there are efforts underway to bring to the table alternative protocols which are built on top of 802.15.4 and are GPL compatible, like 6lowpan/ROLL. One good option I have found for running an open wireless sensor network stack is SICSLoWPAN, an open-source IPv6 over 802.15.4 stack.

What do you think? Any platform you can recommend?

Agile methods on embedded software

Lately I keep hearing a lot about software companies moving into agile development processes. Irrespectively of the hype surrounding these news, I think some agile practices are really worth implementing in an embedded software environment: I have had great success e.g. with fast development cycles and continuous integration.

However, we need to be cautious with specific issues surrounding embedded systems, which I think make some of the agile practices less suitable for embedded software development:

  • Pair programming is quite difficult to implement as embedded software is complex, with issues involving hardware interfaces, real-time behavior and multitasking; this complexity means it is not easy to achieve a uniform level of knowledge across different areas for different engineers to contribute effectively through this practice.
  • Continuous customer communication may not be effective as most of the embedded systems software remains hidden from the customer, who usually is not able to grasp the inner workings of complex software.

This is what embedded guru Jack Ganssle thinks about the topic. What do you think? Are agile practices definitely worth using in embedded systems development?