
As an intermezzo, something totally different this time and the complete opposite of the retro chips adventures of the last few months.
Discussing future projects with the author of the Z20X computer triggered my interest in the STM32MP1 chips from STM. This has 2 Cortex A7 cores (running at 800 MHz) and a Cortex M7 on board. STM also has 2 evaluation boards for them for not too much money:
- STM32MP157A-DK1
using
STM32MP157A
(the Cortex A7 cores run at a maximum of 650 MHz) and there is no LCD display in the package. - STM32MP157F-DK2
using the
STM32MP157F
(the Cortex A7 cores run at a maximum of 800 MHz) and a LCD display is part of the package.
Unfortunately, when trying to create my own, custom, Linux system directly on Manjaro Linux, I bumped into incompatibilities because of missing/different dependencies required for a successful compilation of a Linux system.
I could quickly setup a Ubuntu VM and use that but that doesn’t feel as the optimal way of working. So I explored using Docker to set up a container with all the required tools for building a Linux system with Yocto. This blog post is how I did it.
Setting up Docker on Manjaro Linux
Docker
On my Manjaro Linux installation, Docker wasn’t set up yet. If you already have Docker up and running you can skip this section.
1. Installing Docker
Installing Docker via the command line can be done in this way:
sudo pacman -Syu
sudo pacman -S docker
Once the installation is completed, you can start the Docker service and, optionally, enable it to run whenever the system is rebooted:
sudo systemctl start docker.service # Start the docker service
sudo systemctl enable docker.service # Start docker after a shutdown/reboot
2. Verification
A quick check if Docker is installed, issue the following command:
sudo docker version
In the output you should see no warnings about a docker daemon not running!
3. Running Docker without root
To avoid to always have to use the sudo
command when you want to use docker,
use the following command line:
sudo usermod -aG docker $USER
You need to reboot for the changes to take effect!
Create an Ubuntu docker image
We start by creating a Dockerfile
describing what we want in the container and
we start from a Ubuntu distribution because that is one of the preferred distro’s
by STM.
I found a lot of useful information here. This post is basically a much condensed version (with some enhancements along the way) that gave me the desired result.
1. Create the Dockerfile:
We will create a Dockerfile
that will create a suitable container for us and
adds dev
as the user (with dev
as password).
Save the content below in a file called Dockerfile
at your preferred
location (you might want to change the time zone for your location). This
Dockerfile
is also usable later on when I build the ST distribution in a
future blog post:
FROM ubuntu
# The following 2 lines are added to avoid hanging the container creation. See <https://grigorkh.medium.com/fix-tzdata-hangs-docker-image-build-cdb52cc3360d>
ENV TZ=Europe/Brussels
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update && apt-get install -y gawk wget git-core diffstat unzip texinfo \
gcc-multilib build-essential chrpath socat cpio \
python python3 python3-pip python3-pexpect \
xz-utils debianutils iputils-ping python3-git \
python3-jinja2 libegl1-mesa libsdl1.2-dev xterm \
locales python3-distutils libssl-dev gdisk sudo \
libgmp-dev libmpc-dev pylint
RUN groupadd -g 1000 dev \
&& useradd -u 1000 -g dev -d /home/dev dev \
&& mkdir /home/dev \
&& chown -R dev:dev /home/dev
# The following 3 lines allow the 'dev' user to run sudo (password is "dev").
# Useful when later on packages need to be installed that are missing.
RUN usermod -aG sudo dev
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN echo 'dev:dev' | chpasswd
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
USER dev
WORKDIR /home/dev
2. Create the Docker container
Now we can create a container from the above Dockerfile
file which I gave the
name ubuntu-yocto
. Run this command line from the same directory as you saved
the Dockerfile in:
docker build -t ubuntu-yocto .
We should now have an Ubuntu container with all the required tools and a user
named dev
. The image is called ubuntu-yocto
. We can check this with a
docker images
command line:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-yocto latest f8798565edb4 8 minutes ago 868MB
ubuntu latest 597ce1600cf4 9 days ago 72.8MB
ubuntu-yocto
is the container with all the tools installed and which we need
to use in the future.
3. Using a shared directory
To quickly exchange data between host and docker container, I use a shared folder. Personally, I preferred to use this shared folder to store all Yocto data and scripts.
I created a folder to be shared between host and the docker container at this path:
~/Documents/Projects/STM32/stm32mp157F-DK2/yocto/shared-container-data`
We can run the docker image with the above shared directory which will be mounted
at /data
in the container itself with the following command:
docker run -dit -P --name yocto -v ~/Documents/Projects/STM32/stm32mp157F-DK2/yocto/shared-container-data:/data ubuntu-yocto
We get a hash as output (will be different each time):
cedcfed28edf76718b2d7eb431aa2e406253a61298fd416c0ac08828b0d135c9
And we can attach to the running docker image like so (we only need to enter the first 4 digits of the hash tag to identify which container to attach to):
docker attach cedc
And our terminal shows this: root@cedcfed28edf
prompt, indicating that we’re indeed
running in the docker image with the same hash tag:
root@cedcfed28edf:/#
PS. You can see a list of running Docker containers with the docker ps -a
command.
Installing Yocto and building a minimal Linux system
To make it easier to see what goes on, I’ll install everything in the shared /data
folder of the docker container. Execute the following commands in the terminal running
in the docker container:
1. Download Yocto
cd /data
mkdir yocto-labs
cd yocto-labs
git clone git://git.yoctoproject.org/poky.git
cd poky
git checkout -b dunfell-23.0.10 dunfell-23.0.10
cd ..
2. Add the stm32mp layers
cd /data/yocto-labs
git clone -b dunfell git://git.openembedded.org/meta-openembedded
git clone -b dunfell https://github.com/STMicroelectronics/meta-st-stm32mp.git
3. Set up the build environment
cd /data/yocto-labs/
source poky/oe-init-build-env
The output of the last command is:
$ source poky/oe-init-build-env
You had no conf/local.conf file. This configuration file has therefore been
created for you with some default values. You may wish to edit it to, for
example, select a different MACHINE (target hardware). See conf/local.conf
for more information as common configuration options are commented.
You had no conf/bblayers.conf file. This configuration file has therefore been
created for you with some default values. To add additional metadata layers
into your configuration please add entries to conf/bblayers.conf.
The Yocto Project has extensive documentation about OE including a reference
manual which can be found at:
http://yoctoproject.org/documentation
For more information about OpenEmbedded see their website:
http://www.openembedded.org/
### Shell environment set up for builds. ###
You can now run 'bitbake <target>'
Common targets are:
core-image-minimal
core-image-sato
meta-toolchain
meta-ide-support
You can also run generated qemu images with a command like 'runqemu qemux86'
Other commonly useful commands are:
- 'devtool' and 'recipetool' handle common recipe tasks
- 'bitbake-layers' handles common layer tasks
- 'oe-pkgdata-util' handles common target package tasks
4. Update conf/bblayers.conf
:
In /build/conf/
edit the bblayers.conf
file which currently contains:
BBLAYERS ?= " \
/data/yocto-labs/poky/meta \
/data/yocto-labs/poky/meta-poky \
/data/yocto-labs/poky/meta-yocto-bsp \
"
Add these 3 lines to bblayers.conf
/data/yocto-labs/meta-openembedded/meta-oe \
/data/yocto-labs/meta-openembedded/meta-python \
/data/yocto-labs/meta-st-stm32mp \
so that bblayers.conf
now contains:
BBLAYERS ?= " \
/data/yocto-labs/poky/meta \
/data/yocto-labs/poky/meta-poky \
/data/yocto-labs/poky/meta-yocto-bsp \
/data/yocto-labs/meta-openembedded/meta-oe \
/data/yocto-labs/meta-openembedded/meta-python \
/data/yocto-labs/meta-st-stm32mp \
"
5. Building the Linux system
Now we have everything set up to build a minimal-core-image
. This can be done
with the following command line (while we stand in the yocto-labs/build
directory):
MACHINE=stm32mp1 bitbake core-image-minimal
Now wait until all tasks (over 3000 …) are finished (if you need a reason to buy a fast PC …). The build automatically uses all cores/threads your PC has. When finished my shared directory took up 58 GBytes…
Creating the final image for the SD Card
The images created by Yocto can be found at this path:
.../yocto-labs/build/tmp/deploy/images/stm32mp1
but we still need to build the final image to be flashed to an SD Card.
A create_sdcard_from_flashlayout.sh
script can be found in the
.../yocto-labs/build/tmp/deploy/images/stm32mp1/scripts
directory that can do
that for us. It takes one argument which is the filename of the preferred flash
layout. Those layout files can be found here: .../yocto-labs/build/tmp/deploy/images/stm32mp1/flashlayout_core-image-minimal
.
I choose the FlashLayout_sdcard_stm32mp157f-dk2-extensible.tsv
to create the
wanted image.
Assuming I stand in the .../yocto-labs/build/tmp/deploy/images/stm32mp1/scripts
directory, execute this command line:
./create_sdcard_from_flashlayout.sh ../flashlayout_core-image-minimal/extensible/FlashLayout_sdcard_stm32mp157f-dk2-extensible.tsv
After a few seconds we see this output:
Create Raw empty image: ../flashlayout_core-image-minimal/extensible/../../FlashLayout_sdcard_stm32mp157f-dk2-extensible.raw of 1536MB
Create partition table:
[CREATED] part 1: fsbl1 [partition size 256.0 KiB]
[CREATED] part 2: fsbl2 [partition size 256.0 KiB]
[CREATED] part 3: fip [partition size 4.0 MiB]
[CREATED] part 4: boot [partition size 64.0 MiB]
[CREATED] part 5: vendorfs [partition size 16.0 MiB]
[CREATED] part 6: rootfs [partition size 1.4 GiB]
Partition table from ../flashlayout_core-image-minimal/extensible/../../FlashLayout_sdcard_stm32mp157f-dk2-extensible.raw
Populate raw image with image content:
[ FILLED ] part 1: fsbl1, image: arm-trusted-firmware/tf-a-stm32mp157f-dk2-sdcard.stm32
[ FILLED ] part 2: fsbl2, image: arm-trusted-firmware/tf-a-stm32mp157f-dk2-sdcard.stm32
[ FILLED ] part 3: fip, image: fip/fip-stm32mp157f-dk2-trusted.bin
[ FILLED ] part 4: boot, image: st-image-bootfs-poky-stm32mp1.ext4
[ FILLED ] part 5: vendorfs, image: st-image-vendorfs-poky-stm32mp1.ext4
[ FILLED ] part 6: rootfs, image: core-image-minimal-stm32mp1.ext4
###########################################################################
###########################################################################
RAW IMAGE generated: ../flashlayout_core-image-minimal/extensible/../../FlashLayout_sdcard_stm32mp157f-dk2-extensible.raw
WARNING: before to use the command dd, please umount all the partitions
associated to SDCARD.
sudo umount `lsblk --list | grep mmcblk0 | grep part | gawk '{ print $7 }' | tr '\n' ' '`
To put this raw image on sdcard:
sudo dd if=../flashlayout_core-image-minimal/extensible/../../FlashLayout_sdcard_stm32mp157f-dk2-extensible.raw of=/dev/mmcblk0 bs=8M conv=fdatasync status=progress
(mmcblk0 can be replaced by:
sdX if it's a device dedicated to receive the raw image
(where X can be a, b, c, d, e)
###########################################################################
###########################################################################
And 2 files have been created in ~/Documents/Projects/STM32/stm32mp157F-DK2/yocto/shared-container-data/yocto-labs/build/tmp/deploy/images/stm32mp1
:
FlashLayout_sdcard_stm32mp157f-dk2-extensible.how_to_update.txt
FlashLayout_sdcard_stm32mp157f-dk2-extensible.raw
The last file (1.6 GByte in size) is the one we need to put on the SD Card.
Note that the above output conveniently also shows the needed command lines to flash the image to an SD Card. But it needs slight modification since the host PC isn’t running Ubuntu Linux.
Flashing the image to the SD Card
We first need to figure out where our SD Card is mounted. We can use the lsblk
command for that:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 1 931.5G 0 disk
└─sda1 8:1 1 931.5G 0 part
sdb 8:16 0 931.5G 0 disk
├─sdb1 8:17 0 200M 0 part
├─sdb2 8:18 0 930.7G 0 part
└─sdb3 8:19 0 619.9M 0 part
sdc 8:32 1 29.7G 0 disk
├─sdc1 8:33 1 256K 0 part
├─sdc2 8:34 1 256K 0 part
├─sdc3 8:35 1 4M 0 part
├─sdc4 8:36 1 64M 0 part
├─sdc5 8:37 1 16M 0 part
└─sdc6 8:38 1 1.4G 0 part
nvme0n1 259:0 0 894.3G 0 disk
├─nvme0n1p1 259:1 0 300M 0 part
├─nvme0n1p2 259:2 0 8M 0 part
├─nvme0n1p3 259:3 0 34.6G 0 part [SWAP]
├─nvme0n1p4 259:4 0 128G 0 part /etc/hosts
└─nvme0n1p5 259:5 0 731.4G 0 part /data
In this case, my SD Card is mounted at /dev/sdc/
.
Before writing to the SDCard we need to first unmount all partitions on the
SD Card as the output of the create_sdcard_from_flashlayout.sh
script
nicely reminded us for. We will need to do that in a terminal of the host
PC. Not in the terminal running inside the docker container. Since it’s
the host PC which has the SD Card mounted.
Since my SD Card is mounted as sdc
and not as mmcblk
(as it would be
under Ubuntu) I need to slightly alter the proposed command line in the
output of the create_sdcard_from_flashlayout.sh
script to unmount all
partitions:
sudo umount `lsblk --list | grep sdc | grep part | gawk '{ print $7 }' | tr '\n' ' '`
Now we can flash the SD Card with. The command uses relative paths. So to
have this work to work correctly, make sure that your terminal of the host PC
stands in the scripts
directory:
/yocto-labs/openstlinux-5.10-dunfell-mp1-21-03-31/build-openstlinuxweston-stm32mp1/tmp-glibc/deploy/images/stm32mp1/scripts
I added the oflag=direct
flag to the dd
command to make sure I could see
the progress in writing to the SD Card otherwise it appeared as if nothing
happened:
sudo dd if=../flashlayout_core-image-minimal/extensible/../../FlashLayout_sdcard_stm32mp157f-dk2-extensible.raw of=/dev/sdc bs=8M conv=fdatasync status=progress oflag=direct
And be patient till this is finished since 1.6 GByte of data is written to the SD Card.
Testing the image
Now insert the SD Card into its slot of the STM32MP157F-DK2 and make sure you
have a micro USB cable connected to the CN11/ST-LINK connector of the board and
use you favourite terminal program to listen at 115.200 baud on device
/dev/ttyACM0
. E.g.:
$ picocom -b 115200 /dev/ttyACM0
picocom v3.1
port is : /dev/ttyACM0
...
NOTICE: CPU: STM32MP157FAC Rev.Z
NOTICE: Model: STMicroelectronics STM32MP157F-DK2 Discovery Board
NOTICE: Board: MB1272 Var4.0 Rev.C-02
INFO: Reset reason (0x15):
INFO: Power-on Reset (rst_por)
INFO: PMIC version = 0x20
INFO: FCONF: Reading TB_FW firmware configuration file from: 0x2ffe3000
INFO: FCONF: Reading firmware configuration information for: stm32mp_io
INFO: Using SDMMC
INFO: Instance 1
INFO: Boot used partition fsbl1
...
U-Boot 2020.10-stm32mp-r1 (Oct 05 2020 - 15:15:32 +0000)
CPU: STM32MP157FAC Rev.Z
Model: STMicroelectronics STM32MP157F-DK2 Discovery Board
Board: stm32mp1 in trusted mode (st,stm32mp157f-dk2)
Board: MB1272 Var4.0 Rev.C-02
DRAM: 512 MiB
Clocks:
- MPU : 800 MHz
- MCU : 208.878 MHz
- AXI : 266.500 MHz
- PER : 24 MHz
- DDR : 533 MHz
WDT: Started with servicing (32s timeout)
NAND: 0 MiB
MMC: STM32 SD/MMC: 0, STM32 SD/MMC: 1
...
Hit any key to stop autoboot: 0
Boot over mmc0!
...
Select the boot mode
1: OpenSTLinux
2: stm32mp157f-dk2-a7-examples
3: stm32mp157f-dk2-m4-examples
Enter choice: 1: OpenSTLinux
Retrieving file: /uImage
...
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
...
Poky (Yocto Project Reference Distro) 3.1.10 stm32mp1 /dev/ttySTM0
stm32mp1 login: root
root@stm32mp1:~#
Success!
What’s installed with a minimal core image of OpenSTLinux:
This is a short overview what’s installed in a minimal system (see the next section on how to add native build tools):
addgroup adduser ash awk
basename bootlogd busybox busybox.suid bzip2
blkid bunzip2 busybox.nosuid bzcat
cat chgrp chown chvt cmp
cpio cut chattr chmod chroot
clear cp cttyhack
date deallocvt depmod dirname du
dc delgroup df dmesg dumpkmap
dd deluser diff dnsdomainname dumpleases
echo egrep env expr
false fdisk find free fstab-decode
fuser fbset fgrep flock fsck
fstrim
getopt getty grep groups gunzip
gzip
halt halt.sysvinit head hexdump hostname
hwclock
last lastb.sysvinit ln logger logread
lsmod last.sysvinit ldconfig loadfont login
losetup lzcat lastb less loadkmap
logname ls
md5sum microcom mkswap mount
mdev mkdir mktemp mountpoint
mesg mkfifo modprobe mountpoint.sysvinit
mesg.sysvinit mknod more mv
nc netstat nohup nproc nslookup
od openvt
passwd pidof.sysvinit pivot_root printf patch
ping poweroff ps pidof ping6
poweroff.sysvinit pwd
rdate reboot resize rmmod runlevel
readbootlog reboot.sysvinit rfkill route runlevel.sysvinit
readlink renice rm run-parts
realpath reset rmdir run-postinsts
sed sha1sum sleep strings swapon
seq sha256sum sort stty switch_root
setconsole shuf start-stop-daemon su
sync setsid shutdown start_getty sulogin
sysctl sh shutdown.sysvinit stat
swapoff syslogd
tail tee telnet tftp time
touch traceroute ts tar telinit
test tftpd top tr true
tty
udevadm udpsvd unlink uptime utmpdump.sysvinit
udevd umount unzip users
udhcpc uname update-alternatives usleep
udhcpd uniq update-rc.d utmpdump
vi vlock
wall watch wc which whoami
wall.sysvinit watchdog wget who
xargs xzcat
yes
zcat
Adding build tools (including GCC and Nano) to the Linux system
Find the local.conf
file (in .../yocto-labs/build/conf
) and add these
lines (doesn’t seem to matter where but the space before the package name
seems to be important!):
IMAGE_INSTALL_append = " packagegroup-core-buildessential"
IMAGE_INSTALL_append += " nano"
The first line will append the typical GCC
build tools. The second line will
add the Nano
editor (in case you prefer not to work with the VI editor that is
part of the minimal Linux system).
Now rebuild the Linux system and flash it to an SD Card. If all went well, you
can now use GCC
and the Nano
editor natively on the STM32MP157F-DK2
board.