Cocoacrumbs

Cocoacrumbs

All of the buildings, all of those cars
were once just a dream
in somebody's head
Mercy Street - Peter Gabriel

Cocoacrumbs

13 minutes read

Pic 1

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.

Recent posts

See more

Categories

About

Cocoacrumbs