3. Software Guide

3.1. About this Chapter

This Software Guide provides instructions for building and deploying the BSP software: the U-Boot bootloader and the Linux operating system to the µQ7 board.

The section “Compiling Linux Applications” provides guidance for compiling applications for the Pangolin.

3.2. Compiling Kernel and Bootloader

3.2.1. Prerequisites

You need a recent x86_64 Linux installation to run the cross-compiler on. The cross-compiler requires libc version 2.19. Distributions shipping this version are, among others:

  • Ubuntu 14.04 “Trusty”
  • Debian 8 “Jessie”

We recommend Debian 8. Please install the following packages to set up the generic build infrastructure:

sudo apt-get install device-tree-compiler u-boot-tools build-essential git bc

3.2.2. Compiler Setup

For both the U-Boot bootloader and the Linux kernel, a bare-metal arm cross-compiler is required. Note that a bare-metal compiler is only suitable for compiling kernel and bootloader. It will not generate applications that run under Linux.

You can download precompiled binaries from Linaro: https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-eabi/gcc-linaro-4.9.4-2017.01-x86_64_arm-eabi.tar.xz

Extract the archive in /opt .

Then, set up environment variables to make use of the new compiler:

export ARCH=arm
export CROSS_COMPILE=/opt/gcc-linaro-4.9.4-2017.01-x86_64_arm-eabi/bin/arm-eabi-

3.2.3. Building U-Boot

U-Boot (Universal Bootloader) is an open source, primary boot loader used in embedded devices to package the instructions to boot the device’s operating system kernel.

The boot loader source code can be cloned from https://git.theobroma-systems.com/pangolin-u-boot.git/:

git clone https://git.theobroma-systems.com/pangolin-u-boot.git

Compile using:

cd pangolin-u-boot
make pangolin_defconfig
make

The resulting u-boot image will be saved as u-boot-sunxi-with-spl.bin in the pangolin-u-boot directory.

3.2.4. Building the Boot Script

The U-Boot boot sequence is controlled by a file called boot.scr. This file is generated from a plain-text file called boot.cmd.

You can clone this file from https://git.theobroma-systems.com/pangolin-tools.git:

git clone https://git.theobroma-systems.com/pangolin-tools.git

Generate boot.scr using:

cd pangolin-tools
make

3.2.5. Building the Linux Kernel

The kernel source code can be cloned from https://git.theobroma-systems.com/pangolin-linux.git/:

git clone https://git.theobroma-systems.com/pangolin-linux.git

Compile using:

cd pangolin-linux
make pangolin_defconfig
make ARCH=arm uImage sun6i-a31-pangolin.dtb LOADADDR=0x40008000

This will create the two files needed for booting with U-Boot (paths are relative to the pangolin-linux directory):

  • The device tree: arch/arm/boot/dts/sun6i-a31-pangolin.dtb
  • The u-boot image: arch/arm/boot/uImage

3.3. Building the root filesystem

A filesystem can be created using Debootstrap, specifying armhf as architecture in the command line.

Install support packages on the x86_64 Debian:

sudo apt-get install qemu-user-static debootstrap binfmt-support

Supposing the target dir is called a31-uq7-rootfs and the chosen distro is jessie (recommended):

export targetdir=$HOME/a31-uq7-rootfs
export distro=jessie
mkdir -p $targetdir
sudo debootstrap --arch=armhf --foreign $distro $targetdir

Next, copy the qemu-arm-static binary into the right place for the binfmt packages to find it and copy the resolv.conf file from the host system:

sudo cp /usr/bin/qemu-arm-static $targetdir/usr/bin/
sudo cp /etc/resolv.conf $targetdir/etc

This will provide a very basic armhf rootfs in the targetdir. For the next stages, we chroot to the target dir and set up the environment again:

cd $targetdir
sudo mount -o bind /dev ./dev
sudo mount -o bind /proc ./proc
sudo mount -o bind /sys ./sys
sudo mount -o bind /run ./run
sudo chroot .
export distro=jessie
export LANG=C

Second stage of debootstrap inside the new root dir:

/debootstrap/debootstrap --second-stage

Setting up apt sources:

cat << EOT > /etc/apt/sources.list
deb http://httpredir.debian.org/debian $distro main contrib non-free
deb-src http://httpredir.debian.org/debian $distro main contrib non-free
deb http://httpredir.debian.org/debian $distro-updates main contrib non-free
deb-src http://httpredir.debian.org/debian $distro-updates main contrib non-free
deb http://security.debian.org/debian-security $distro/updates main contrib non-free
deb-src http://security.debian.org/debian-security $distro/updates main contrib non-free
EOT

We can now pull the latest apt database from the Debian mirrors and install the locales package (in Jessie the dialog package is needed as well):

apt-get update
apt-get install locales dialog
dpkg-reconfigure locales

Now it is a good time to install a good editor of your choice:

apt-get install vim
update-alternatives --config editor #select vim.basic

Install any additional packages inside the chroot. An ssh server and sudo are recommended:

apt-get install openssh-server sudo

Set the root password for logging in via console or ssh:

passwd

root login over ssh is not permitted by default (set to no), or permitted only with public key (set to without-password). To verify that, run:

cat /etc/ssh/sshd_config | grep "PermitRootLogin"
PermitRootLogin without-password

To allow this open the file /etc/ssh/sshd_config in your editor of choice and set PermitRootLogin to yes.

A better option would be to create a user besides root:

adduser user

Optionally, you can add it to the sudo list:

adduser user sudo

Set up a basic network configuration file with DHCP via eth0:

cat << EOT >> /etc/systemd/network/eth.network
[Match]
Name=eth0
[Network]
DHCP=yes
EOT
systemctl enable systemd-networkd
systemctl enable systemd-resolved

Set the hostname:

echo a31-uq7 > /etc/hostname

For distros older than jessie (wheezy and earlier), the serial console has to be enabled manually. In jessie, this is handled automatically.:

echo T0:2345:respawn:/sbin/getty -L ttyS1 115200 vt100 >> /etc/inittab

You can optionally also install a Desktop Environment. Xfce is a lightweight desktop environment recommended for use on the A31 µQ7. To install Xfce, do the following:

apt-get install task-xfce-desktop

We can now exit and cleanup the support files:

exit
sudo umount ./run
sudo umount ./sys
sudo umount ./proc
sudo umount ./dev
sudo rm ./etc/resolv.conf
sudo rm ./usr/bin/qemu-arm-static
cd -

We now have a root filesystem which can be deployed to the SD card.

3.4. Deploying on SD Card

3.4.1. Partition Setup

Both U-Boot and Linux will be located on the same SD card. The layout of the card is as follows:

Offset Contents
0 Partition table
8kiB U-Boot bootloader
544kiB U-Boot environment variables
1MiB Partition 1 (ext4 - Linux root fs)

Partitions can be created using fdisk (assuming the SD card is mapped to /dev/sdX) and has no partitions (this can be checked using the p command):

sudo fdisk /dev/sdX
> p

This should show an empty partition table, for example:

Disk /dev/sdX: 3980 MB, 3980394496 bytes
123 heads, 62 sectors/track, 1019 cylinders, total 7774208 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xdbbd45c7

   Device Boot      Start         End      Blocks   Id  System

If there are partitions on the sdcard, they can be deleted with d.

The required partition can be created with the command n, then accepting the defaults:

> n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): <ENTER>
Partition number (1-4, default 1): <ENTER>
First sector (2048-7774207, default 2048): <ENTER>
Last sector, +sectors or +size{K,M,G} (...): <ENTER>
> w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

This will create a primary partition at offset 1MiB.

Now, to format the partition as ext4:

sudo /sbin/mkfs.ext4 -E lazy_itable_init=0 /dev/sdX1

The option lazy_itable_init=0 speeds up the first boot because it initializes the inode tables in advance.

The SD card is now ready to have the U-Boot bootloader and Linux deployed.

3.4.2. Deploying U-Boot

The U-Boot image u-boot-sunxi-with-spl.bin is written to the SD card. Assuming the SD card is mapped to /dev/sdX:

sudo dd if=pangolin-u-boot/u-boot-sunxi-with-spl.bin of=/dev/sdX bs=8K seek=1 conv=fsync

3.4.3. Deploying the Linux Kernel and the Root Filesystem

Mount the SD card partition and copy the rootfs (assuming that the rootfs is located at /opt/a31-uq7-rootfs and the sd card at /dev/sdX1):

sudo mkdir -p /mnt/sdcard
sudo mount /dev/sdX1 /mnt/sdcard
sudo cp -av /opt/a31-uq7-rootfs/* /mnt/sdcard

Copy kernel image, device tree and boot script into the boot directory:

sudo cp pangolin-linux/arch/arm/boot/dts/sun6i-a31-pangolin.dtb \
    pangolin-linux/arch/arm/boot/uImage pangolin-tools/boot.scr \
    /mnt/sdcard/boot

Finally, unmount the SD card:

sudo umount /mnt/sdcard

The SD card is ready for booting.

3.4.4. U-Boot Environment

The boot sequence is handled by the boot script /boot/boot.scr. Unless you want to customize the sequence, no further action is required.

If you want to step through the sequence manually or customize it, you can execute the following commands on the U-Boot prompt:

setenv bootargs console=tty0 console=ttyS2,115200 root=/dev/mmcblk1p1 rw rootwait
ext4load mmc 0:1 0x40008000 boot/uImage
ext4load mmc 0:1 0x40000000 boot/sun6i-a31-pangolin.dtb
bootm 0x40008000 - 0x40000000

Optionally, these commands can be compiled together in a single command and saved so it is performed on every subsequent boot:

setenv boot_sd "ext4load mmc 0:1 0x40008000 boot/uImage
ext4load mmc 0:1 0x40000000 boot/sun6i-a31-pangolin.dtb
bootm 0x40008000 - 0x40000000"
setenv bootcmd "run boot_sd"
saveenv

To reset the U-Boot settings to default, execute:

env default -f -a
saveenv

3.5. Deploying on On-Board eMMC storage

As the eMMC storage is only accessible from the module itself, you must first boot the A31 µQ7 from SD card.

Partion and format the eMMC storage as described in 3.4.1 Partition Setup, but using the device /dev/mmcblk0.

Mount the eMMC partition and copy the contents of the SD card to the eMMC storage. The copy process will take about 30 seconds:

sudo mkdir -p /mnt/emmc
sudo mount /dev/mmcblk0p1 /mnt/emmc
sudo cp -ax / /mnt/emmc
sudo umount /mnt/emmc

The final step is copying the bootloader from the SD card to the eMMC:

sudo dd if=/dev/mmcblk1 of=/dev/mmcblk0 bs=8K skip=1 seek=1 count=64 conv=fsync

Shut down the board (poweroff command) and remove the SD card. Make sure the boot selector switch Boot SW is set to “Normal Boot”. The next boot will run U-Boot off the internal eMMC storage.

3.6. Compiling Linux Applications

The easiest option is to compile your applications directly on a running A31 µQ7 module. Just install the gcc package and related utilities and you are good to go:

sudo apt-get install build-essential

The second option is to cross-compile your applications. That means running a cross-compiler on an x86_64 Linux installation.

You can download precompiled binaries of the cross-compile toolchain from Linaro: http://releases.linaro.org/14.11/components/toolchain/binaries/arm-linux-gnueabihf/gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf.tar.xz

Note that this toolchain is only suitable for compiling Linux user-space applications. It will not compile the Linux kernel itself or the bootloader.

3.7. Serial Number

Each A31 µQ7 module has a unique serial number that can be read by software.

In U-Boot, the serial number is contained in the environment variable serial#. You can print it using the command:

printenv serial#

Under Linux, it is represented by a simple text file in /sys:

cat /sys/firmware/devicetree/base/serial-number

The serial number is fixed in hardware (derived from the eMMC Product Serial Number) and can not be modified.

3.8. MAC Address

By default, the MAC address of each A31 µQ7 module is a random value derived from the serial number. The properties of this default MAC address are:

  • It is a Locally Administered Address: The U/L bit of the MAC address is set to 1
  • It is not guaranteed to be globally unique
  • The address is fixed for each A31 µQ7 module. It stays constant across reboots as it is deterministically derived from the serial number

To set your own Universally Administered Address, you overwrite the U-Boot environment variable ethaddr. On the U-Boot prompt, with XX:XX:XX:XX:XX:XX replaced by your MAC address:

setenv ethaddr XX:XX:XX:XX:XX:XX
saveenv

The MAC address can be queried from the U-Boot prompt using:

printenv ethaddr

To reset the MAC address to the default value, run:

env delete ethaddr
saveenv