How to Build Your Own Tailor-made IoT Linux OS (Part 1)

Creating & Compiling Your Own Linux on a Raspberry Pi 3 Using Buildroot & U-Boot Bootloader

--

What follows is a comprehensive updated guide to building your own custom, embedded Linux for your next IoT device using the latest versions of Buildroot and U-Boot bootloader.

The learning process will go from installing Buildroot for customizing the most used aspects of any Linux system to how to create the different types of images and configure the networking. The settings shown are to run on a real target, specifically, the Raspberry Pi 3 model B board, due to its price and availability.

What You Are Going to Learn

  1. Serial connection using UART
  2. Linux build systems
  3. Toolchains
  4. Compiling and configuring Linux kernels & modules
  5. Pre-installing packages
  6. Configuring system parameters
  7. Flashing firmware image to an SD card
  8. Bootloaders (changing default RPI bootloader to U-Boot)
  9. Static compilation of packages

Prerequisites

you can read the article and learn, but if you want to try it yourself, this is what you’ll need:

  1. Target device: Raspberry Pi 3 Model B
  2. SD card + reader for your PC
  3. USB to TTL Adapter cable (FTDI adapter could also work)
  4. Build device: Ubuntu (18.04 LTS recommended, for Windows users, WSL works as well)

Setting Up The the Infrastructure

Serial Connection

To connect to control (read and write) the target device, you need some kind of a console. SSH will be the go-to solution when you have a fully running system with TCP/IP stack, network interfaces, IP configured and the right SSH server running. Unfortunately, this is not the case when you develop a system from scratch, you need a direct console connection to all stdin/out/err of the board, way before you even have an OS installed or an HDMI display driver loaded (dealing with bootloaders, for example), that’s where UART comes into the picture:

UART (Universal Asynchronous Receiver/Transmitter) is a serial communication protocol in which data transfers serially, i.e., bit by bit. Asynchronous serial communication is common for byte-oriented transmission. In Asynchronous serial communication, a byte of data transfers at a time.

Connecting UART To RPI 3

Configuring Raspberry Pi 3
All you need to do is add the following line to the config.txt file on the /boot partition:

There’s more on this after you create the Linux image.

Once you have set up everything, go to the next step. (Connecting will just give you a blank console at this point.)

Raspberry Pi 3 UART Pins

Raspberry Pi 3 UART pins layout (source)

Plug in the adapter/cable
If you’re using USB to TTL, then simply connect the pins in the following order:

  1. Connect the black wire to pin #6 (ground).
  2. Connect the green wire to pin #8 (RXD to TXD)
  3. Connect the white wire to pin #10 (TXD to RXD)

If for some reason that doesn’t work and you get a blank console, then switch the white and the green.
If you’re using an FTDI board, then connect this way:

FTDI board connection ro RPI 3 (source)

Once you plug in the cable, you may connect to the serial port.

The following parameters are necessary to connect to the Raspberry Pi console, and they apply on both Linux and Windows (complete how-to connect to serial port on windows/linux):

  • Speed (baud rate): 115200
  • Bits: 8
  • Parity: None
  • Stop Bits: 1
  • Flow Control: None

Windows setup:
To know the port name of its serial port, simply run mode on a cmd:

Using PuTTY:

Linux terminal setup:
To know the port name of its serial port:

  • Built-in (standard) Serial Port: the Linux standard is /dev/ttyS0, /dev/ttyS1, and so on
  • USB Serial Port Adapter: /dev/ttyUSB0, /dev/ttyUSB1, and so on.
  • Some types of USB serial adapter may appear as /dev/ttyACM0 …

You will need to be a member of the dialout group to access this port (for later releases, the required group is tty). You can check which is necessary with:

and you will see something like “crw-rw — — T 1 root dialout …”, means character device, and root can “read,write” and the group dialout can “read,write” to the port and everyone else cannot access it.
To find out if you, the current user, is in the group dialout, use the command:

If you do not see dialout listed, add yourself with the command

Connect to the terminal:

What’s a Linux Build System?

First, you should read this great intro by Free Electrons. (Slide 6 is enough to read for now.)

The development environment in embedded systems programming is usually quite different from the testing and production environments. They may use different chip architectures, software stacks, and even operating systems. Development workflows are different for embedded developers vs. desktop and web developers. Typically, the build output will consist of an entire software image for the target device, including the kernel, device drivers, libraries, and application software (and sometimes the bootloader).

  1. Build systems allow an embedded Linux developer to generate a working embedded Linux system from scratch.
  2. They automate the process of downloading, configuring, patching, compiling, and installing all the free software packages.
  3. You have a well-known procedure for rebuilding your system from scratch.
  4. You can easily integrate patches, bug fixes, or new upstream versions.
  5. Your colleagues can easily take over your work since there’s a documented procedure for system generation.
  6. The build system already knows about most free software packages.
  7. These packages manage dependencies and already solve cross-compiling issues.

Common build systems for IoT devices are Buildroot, Yocto, and OpenWRT (used mostly for routers and networking devices).
To run a Linux system in any target device, basically, three things are needed (source):

  1. Bootloader, to load the kernel/different OS (discussion later)
  2. The Linux kernel, which is the software the bootloader will copy to RAM memory and interact with the hardware, which gives the ability to execute programs and manage device drivers
  3. The root filesystem (RFS), which is the place where applications and system configuration are and where user files are stored

So, it’s clear you need to generate both the kernel and the RFS; this is not an easy task in an embedded system due to the very specific nature of the involved hardware and the peripheral combinations. Some tools exist to make this task easier for the engineers; they’re usually a collection of scripts that download, prepare, compile, and deploy the necessary tools and packages to finally get a binary image the target board will use.

Buildroot, under the GNU software license, is in this category. Created in 2001 by uClibc developers, it’s for testing small embedded systems built with uClibc. Today, Peter Korsgaard is the chief maintainer with a very active community of users and contributors, and he is up-to-date with many new hardware drivers and software packages.

Buildroot

The Buildroot project is defined as “a simple, efficient, and easy-to-use tool to generate embedded Linux systems through cross-compilation.” It shares many of the same objectives as the Yocto project, however, it focuses on simplicity and minimalism. In general, Buildroot will disable all optional compile-time settings for all packages (with a few notable exceptions), resulting in the smallest possible system. It’s up to the system designer to enable the settings that are appropriate for a given device.

Buildroot is useful mainly for people working with embedded systems. Embedded systems often use processors that are not the regular x86 processors everyone is used to having in their PCs. They can be PowerPC processors, MIPS processors, ARM processors, etc.

Buildroot builds all components from the source but does not support on-target package management. As such, users sometimes call it a firmware generator since the images are largely fixed at build time. Applications can update the target filesystem, but there’s no mechanism to install new packages into a running system.

The Buildroot output consists broadly of three components:

  1. The root filesystem image and any other auxiliary files needed to deploy Linux to the target platform
  2. The kernel, bootloader, and kernel modules appropriate for the target hardware
  3. The toolchain used to build all the target binaries

Those are the basics for now, in the next part we’ll be configuring and installing the operating system using Buildroot..!

--

--