Microcontroller manufacturers’ development boards, and the example software projects that they provide with them, can provide great assistance to engineers at the start of a new design. Equally, the software that they provide can cause problems as a design project goes beyond its early phases.
Designs using a real-time operating system as the platform for application code also face the challenge of partitioning functionality into concurrent tasks, designing bullet-proof inter-process communications, and testing the whole package in hardware.
More and more OEMs are finding that the best way to avoid both of the problems described above is to base new designs on an opensource, proven Operating System (OS) which is scalable and runs on various hardware platforms: Linux. This OS has been ported to more computer hardware platforms than any other. Its derivatives run on a very wide range of embedded systems such as network routers, mobile phones, building automation controls, televisions and video-game consoles.
Just because Linux is used successfully, however, does not mean that it may always be used easily. The OS consists of more than one million lines of code, and operates with a distinctive Linux philosophy that the beginner may struggle to grasp quickly.
The main aim of this article, therefore, is to provide a five-step guide to starting a new design project using the μClinux version of embedded Linux. To illustrate the guidance, the article describes the implementation of a μClinux project on an STM32F429 microcontroller from STMicroelectronics with an ARM® Cortex®-M4 core running at 180MHz and using Emcraft’s STM32F429 Discovery Linux Board Support Package (BSP).
Step 1: Linux tools and project layout
Every embedded software design starts with the selection of the right tools.
A toolchain is a set of software development tools that are linked (or chained) together, and it consists of components such as GNU Compiler Collection (GCC), Binutils and GLIBC, as well as, in some cases, other tools such as compilers and debuggers. The toolchain used for embedded development is a cross-toolchain, more commonly known as a cross-compiler.
The GNU Binutils is the first component of an embedded Linux
toolchain. GNU Binutils contains two important tools:
- ‘as’, the assembler, which turns assembly code generated by gcc into binary
- ‘ld’, the linker, which links discrete object-code segments into a library, or executable
The compiler is the second important component of a tool-chain. In embedded Linux, it is known as GCC, and supports a wide range of MCU and processor architectures.
Next is the C library. This implements Linux’s traditional POSIX Application Programming Interface (API), which can be used to develop user-space applications. It interfaces with the kernel through system calls, and provides higher-level services.
The engineer has several choices of C library:
- GLIBC is the C library available from the open-source GNU project. This library is full-featured, portable, and conforms to the Linux standard.
- Embedded GLIBC (EGLIBC) is a variant optimised for embedded systems. It has a reduced footprint, supports cross-compiling and cross-testing, and maintains source and binary compatibility with GLIBC.
- uClibc is another C library which may be used if Flash space is limited and/or the memory footprint must be minimised.
The debugger is also usually part of the toolchain, as a cross-debugger
is needed to debug applications running on the target machine. In the
embedded Linux world, the usual debugger is GDB.
Essential as these tools are, when used on their own it would take too long to compile Linux source code and merge it into a final image. Fortunately, the Buildroot tool automates the process of building a complete embedded system, and eases cross-compilation by generating any or all of:
- a cross-compilation toolchain
- a root file system
- a bootloader image
For embedded systems designers, it can also be convenient to use a utility aggregator tool, such as BusyBox, which combines the most commonly required utilities in one place.
One last essential tool is a BSP that is made specifically for the motherboard carrying the project’s target MCU or processor. A BSP includes pre-configured tools, and a bootloader which loads the OS to the board. It also provides source code for the kernel and device drivers, as shown in Figure 1.
Step 2: boot sequence, clock system, memory and serial interface
A typical embedded Linux boot-up sequence runs as follows:
1) Bootloader firmware (U-Boot in the example project) runs on the target from integrated Flash with no external memory required and performs all required initialisations after power-on/reset, including setting-up serial ports and the memory controller for external memory (RAM) accesses.
2) U-Boot may relocate the Linux image from external Flash to external RAM, and passes control to the kernel entry point in RAM. The Linux image can be compressed to save Flash storage space, at the cost of decompression time during boot-up.
3) Linux proceeds to boot up and mount a RAM-based file system (initramfs) as a root file system. Initramfs is populated with the required files and directories at build time, and is then simply linked into the kernel.
4) Execution of /sbin/init under the Linux kernel. The /sbin/init program initialises the system following the description in the /etc/inittab configuration file.
5) Once the init process completes the run-level execution and the commands in /sbin/init, it will start a log-in process.
6) The boot-up process finishes with the execution of the shell initialisation file’s /etc/profile.
Boot time may be decreased markedly, and overall performance may be improved, by enabling Execute In Place (XIP), a method for executing code from Flash.
The example project featured in this article is based on an STM32F429 MCU for which STMicroelectronics has developed several tools. One of the latest is the STM32CubeMX initialisation code generator (part number UM1718). This tool covers every detail of peripheral initialisation, shows warnings and errors, and alerts the user to hardware conflicts while configuring peripherals.
The STM32F429 MCU has enough internal Flash memory for small embedded Linux projects. It is important to remember that embedded Linux projects use several binary images: boot loader, Linux kernel and the root file system. These need to be aligned on Flash sector boundaries. This avoids the risk that, by loading one image, a part of another will be erased or corrupted.
Step 3: installing Linux on a host computer
To build an embedded Linux project, a Linux host is required. For a Windows PC, it is advisable to install the Oracle® VirtualBox, creating a new virtual machine with 512Mbytes of RAM and a 16Gbyte disk.
Many Linux distributions are available; Debian is, in the author’s experience, compatible with the VirtualBox environment. This Linux host must have access to the internet, so that the GNU cross-build tools for the ARM Cortex-M target may be downloaded. The designer will then create a tree structure similar to that shown in Figure 1, and extract cross-build tools into the /tools folder.
At this point, it is necessary to create an ACTIVATE.sh script. Simply use this code to do so. ( is the path to the extracted GNU tools folder):
Installing GNU tools into a clean Linux system, however, is not on its own sufficient to enable their use. Their operation is in fact dependent on some other system components (such as the host C/C++ compiler, standard C library headers, and some system utilities). One way to provide these necessary components is to install the Eclipse Integrated development Environment (IDE) for C. As well as fixing this immediate problem, the Eclipse IDE can help in many other aspects of the development process, although it is outside the scope of this article to describe its features.
Now, it is time to launch the Linux terminal utility: click ‘Applications’, then ‘Accessories’ and ‘Terminal’, as shown in Figure 2. Terminal is the main tool used to configure the Linux host and to build embedded Linux applications. Type these commands to install Eclipse and other required tools:
su [enter root user password]
apt-get install eclipse-cdt
apt-get install genromfs
apt-get install libncurses5-dev
apt-get install git
apt-get install mc
The last step in preparing Linux is to download the STM32F429 Discovery Buildroot and extract it to the /uclinux folder, see Figure 1.
Step 4: building μClinux with Buildroot
Now it is necessary to close the previous terminal, which was using the root user profile, and launch a new terminal. In the command line, type ‘mc’ and use the navigator to go to ‘Documents’, then ‘uclinux’. Press Ctrl+O and activate a Linux ARM Cortex-M development session, and run ‘.ACTIVATE.sh’. Again press Ctrl+O and enter the ‘stm32f429-linuxbuilder-master’ folder.
The user now has two options. If using the example project in VirtualBox, follow the ‘make clean’ and ‘make all’ command sequence. If preparing a brand new environment, use the ‘make’ command. Around 30 minutes later, the new μClinux images will be available, as follows:
Write these new images to Flash memory. Then connect the serial console to the board and press the Reset button, and the μClinux project will be live. The boot-up output will be shown in the console and the display will show the Linux penguin.
Step 5: create a ‘Hello, world’ application
Now it is time to add a user application to the μClinux project. A code example may be found at a pre-configured VirtualBox machine: visit this author’s μClinux publications via the following link: https://www.linkedin.com/in/arnoldasbagdonas.
This article shows that any engineer can begin a simple μClinux project in just a few easy steps. The example project provides a good starting point for more complex Linux designs.
In this author’s experience, the existence of open-source code and projects offers a tremendous advantage to engineers who wish to extend their capabilities and learn quickly how to implement designs in a sophisticated hardware and software environment. The author began the project with no knowledge of embedded Linux. It took only a few weeks to get the ‘Hello, world’ application running on the Discovery board. In only a few hours more, SD card support was added, a frame buffer viewer project was embedded and a digital picture-frame prototype was ready.
This provides strong evidence of the value of starting from the huge base of software provided by the open-source community.