How to manage your Qt based embedded Linux device with Mender (Colibri iMX7)

Introduction

This is a step-by-step guide on how to reproduce the demonstration that was done during the “Managing Your Qt Based Embedded Linux Device With Mender” webinar that was hosted by The Qt Company.

Abstract from the webinar:

So you have made a world-class application with Qt, but how do you deploy it to many devices in a robust, reproducible and secure way?

In this webinar Harald Kjølberg from Qt and Mirza Krak from Mender.io will show you how to use Mender.io to quickly and easily deploy applications made in Qt on to your field-deployed devices.

Mender is an end-to-end OTA (over-the-air) solution for users who seek a secure and robust way to deploy firmware and software to connected devices.

In this webinar we will start off by:

  • Giving an overview of Mender and how it works

Followed by an impressive demo showing you how to:

  • Use a QtCreator build as input artifact for Mender.io to do an application update
  • Do a phased roll-out of the newly created / updated application
  • Explain how you can automate the roll out using APIs
  • Explain how this can be integrated to deploy images based updates

Prerequisites

  • A supported Linux distribution and dependencies installed on your workstation/laptop as described in the Yocto Mega Manual

    • NOTE. Instructions depend on which Yocto version you intend to use.
  • Google repo tool installed and in your PATH.

  • A deployment environment using a desktop PC with Ubuntu 18.04 and Google Chrome as a web browser and at least 10 GB free disk space and 2 GB RAM available for Mender.

  • You should have a running Mender demo server. Instructions on how to setup this up can be found here

  • Colibri Aster carrier board

  • Colibri iMX7D 1GB V1.1A SOM

  • USB flash drive connected to the Colibri iMX7D with the following content:

    • b2qt-embedded-qt5-image-colibri-imx7-emmc.sdimg.gz (this file will be built during the tutorial)
    • u-boot.imx (this file will be built during the tutorial)
  • Working U-boot on the Colibri iMX7D

    • If you do not have a working U-boot, please consult the iMX Recovery Mode section of the Toradex developer resources.
  • Qt Creator IDE installed on your development PC with the Qt examples. On a Debian based operating system you can run:
apt-get install qtcreator qtbase5-examples

Step 1 - Initial setup of the Boot 2 Qt environment

Create workspace and change directory:

mkdir boot2qt && cd boot2qt

Clone meta-boot2qt:

git clone git://code.qt.io/yocto/meta-boot2qt.git -b v5.12.4

Change directory to meta-boot2qt:

cd meta-boot2qt

Clone meta-mender:

git clone https://github.com/mendersoftware/meta-mender.git -b sumo

Clone meta-mender-community:

git clone https://github.com/mendersoftware/meta-mender-community -b sumo

Initialize the environment:

./b2qt-init-build-env init --device colibri-imx7

Setup the environment:

MACHINE=colibri-imx7 . setup-environment.sh

Add Mender layers to environment:

cat <<- 'EOF' >> conf/bblayers.conf
BBLAYERS += "${BSPDIR}/sources/meta-mender/meta-mender-core"
BBLAYERS += "${BSPDIR}/sources/meta-mender/meta-mender-demo"
BBLAYERS += "${BSPDIR}/sources/meta-mender-community/meta-mender-toradex-nxp"
EOF

Add generic customizations to local.conf:

cat ../sources/meta-mender-community/templates/local.conf.append >> conf/local.conf

Add Colibri iMX7 customizations to local.conf:

cat ../sources/meta-mender-community/meta-mender-toradex-nxp/templates/local.conf.append >> conf/local.conf

Update MACHINE in local.conf to:

MACHINE="colibri-imx7-emmc"

Update the Mender server configuration in local.conf to connect to your running demo environment:

# Update IP address to match the machine running the Mender demo server
MENDER_DEMO_HOST_IP_ADDRESS = "< IP address >"

Add the following to local.conf (experienced build error with this enabled, we will not use this and can be disabled without impacting device functionality):

echo 'IMAGE_POSTPROCESS_COMMAND_remove = "do_qbsp_image;"' >> conf/local.conf

Build the embedded image:

bitbake b2qt-embedded-qt5-image

Build the toolchain (which is later used in Qt Creator IDE):

bitbake meta-toolchain-b2qt-embedded-qt5-sdk

Using the build output

After a successful build, the images and build artifacts are:

  • tmp/deploy/images/colibri-imx7-emmc/b2qt-embedded-qt5-image-colibri-imx7-emmc.sdimg.gz
  • tmp/deploy/images/colibri-imx7-emmc/b2qt-embedded-qt5-image-colibri-imx7-emmc.mender
  • tmp/deploy/images/colibri-imx7-emmc/u-boot-nand.imx
  • tmp/deploy/sdk/b2qt-x86_64-meta-toolchain-b2qt-embedded-qt5-sdk-colibri-imx7-emmc.sh

The disk image (with .sdimg.gz suffix) is used to provision the device storage for devices without Mender running already.

The u-boot-nand.imx file is used to provision the device with a Mender compatible U-Boot.

b2qt-x86_64-meta-toolchain-b2qt-embedded-qt5-sdk-colibri-imx7-emmc.sh you should install on your development machine which contains the cross-toolchain with all Qt components.

If you already have Mender running on your device and want to deploy a rootfs update using this build, you should use the Mender Artifact (b2qt-embedded-qt5-image-colibri-imx7-emmc.mender) files, which have .mender suffix. You can either deploy this Artifact in managed mode with the Mender server (upload it under Releases in the server UI) or by using the Mender client only in Standalone deployments.

Step 2 - Provisioning the device with the built images

Halt the boot process at the U-boot prompt on your serial console:

Colibri iMX7 #

The following commands are all executed from the U-boot prompt.

Setup convenience script to calculate number of blocks based on file size:

setenv set_blkcnt 'setexpr blkcnt ${filesize} + 0x1ff && setexpr blkcnt ${blkcnt} / 0x200'

Enable USB in U-boot:

usb start

Load u-boot.imx from USB flash drive to RAM:

fatload usb 0:1 ${loadaddr} u-boot.imx

Write u-boot.imx to eMMC:

run set_blkcnt && mmc dev 0 1 && mmc write ${loadaddr} 2 ${blkcnt}

Reset U-boot and halt it again at the U-boot prompt. This is because we want to be running the binary that we flashed in above command:

reset

Enable USB in U-boot again since we restarted U-boot:

usb start

Load b2qt-embedded-qt5-image-colibri-imx7-emmc.sdimg.gz from the USB flash drive to RAM:

fatload usb 0:1 ${loadaddr} b2qt-embedded-qt5-image-colibri-imx7-emmc.sdimg.gz

Write b2qt-embedded-qt5-image-colibri-imx7-emmc.sdimg.gz to eMMC:

gzwrite mmc 0 $loadaddr 0x$filesize

Above operation can take 5-10 minutes.

That is it, you can now power-cycle or reset the device and you should have a Boot2Qt image with Mender running on your device.

Step 3 - Mender integration with Qt Creator

This step requires you to setup a device kit in Qt Creator for the desired device. You can find more information in the Qt Documentation on how to accomplish this with the built tool chain in previous steps.

Next we need to setup an example project to utilize for our demo:

  1. Create a new project in Qt Creator IDE based on the example application “Wearable”
  2. Select “copy and open” option, which will copy the project the custom qt5 workspace, e.g ${HOME}/qt5-projects
  3. Select the custom device kit in the next step
  4. Disable shadow builds under “Projects → Build”
  5. Test that you are able to compile and deploy the Wearable application to the connect device using the Qt Creator IDE built in tools, e.g ssh or rsync.

We have a prepared a simple example script which can be found here that builds Mender Artifacts from the built Qt application.

Enter the Qt workspace of the project using a terminal:

cd ${HOME}/qt-projects/wearable

Download the script:

wget https://gist.githubusercontent.com/mirzak/d77ca35cc39d844e1715e77df998ecb7/raw/30000f8eaea62ba62beb93aa51f87604c4f335ce/create-mender-artifact.sh

Allow the script to be executed:

chmod +x create-mender-artifact.sh

Edit the following fields in the create-mender-artifact.sh script:

MENDER_SERVER_USER=""
MENDER_SERVER_PASS=""

NOTE! This is the credentials you created when starting the Mender demo environment

Create a Mender Artifact (single-file) containing the wearable binary and upload it to the server:

./create-mender-artifact.sh -f wearable -u

NOTE! Above command can be added to the Qt Creator IDE configuration to run this step as a post-build step.

This script additional supports packaging the application binary in to a root filesystem image by running:

./create-mender-artifact.sh -f wearable -u -r b2qt-embedded-qt5-image-colibri-imx7-emmc.ext4

NOTE! Above command can be added to the Qt Creator IDE configuration to run this step as a post-build step.

Conclusion

The outlined steps are primarily a demonstration to highlight possibilities and should not be considered suitable for production.


If this tutorial was useful to you, please press like, or leave a thank you note to the contributor who put valuable time into this and made it available to you. It will be much appreciated!

4 Likes

Hi Mirzak,

First of all thanks for the interesting webinar held a while ago and the follow up with this blogpost on how to reproduce the demonstration.

First I’ve been pulling some efforts in converting our Qt application to boot2qt based on a raspberrypi3 which runs successfully. Next, I’ve been using your guide in order to add meta-mender to the build. After some small changes to local.conf I’ve been able to run bitbake successfully.

I’ve flashed an SD card with the .sdimg image and booted the raspberry. U-boot runs and seems to select a rootfs but the boot process will eventually hangs at some point. In order to debug I attached a serial console to GPIO14/15 but minicom is giving rubbish on the output. The best I can give is the following;

Not sure why it doesn’t finish the boot process. Could you point me in the right direction based on this information? should I add enable_uart=1 in config.txt in boot partition to get proper output on serial console?

First of all thanks for the interesting webinar held a while ago and the follow up with this blogpost on how to reproduce the demonstration.

Thank you. Glad to hear it was useful.

should I add enable_uart=1 in config.txt in boot partition to get proper output on serial console?

Yeah, this will help further debugging.

I do see something strange in the boot log, it says

Waiting for root device /dev/mmcblk0p2fbcon=map:10...

It seems that there is a space missing in the kernel arguments. Can you check the contents of the cmdline.txt file on the boot partition to verify?

Good catch!

When i compare cmdline.txt of non-mender image

dwc_otg.lpm_enable=0 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait fbcon=map:10 fbcon=font:VGA8x8

To mender image

dwc_otg.lpm_enable=0 rootfstype=ext4 rootwait root=${mender_kernel_root}fbcon=map:10 fbcon=font:VGA8x8

Shows a missing space indeed. However just adding the space results in very weird output;

setting enable_uart=1 and connecting serial console will work fine and brings up the linux login.

Discarding the kernel arguments fbcon=map:10 fbcon=font:VGA8x8 all togetherwill result in a proper boot and I’m able to remote deploy my Qt application. So what is the function of these kernel arguments and where are they coming from?

So what is the function of these kernel arguments and where are they coming from?

Those configuration options come from, https://github.com/agherzan/meta-raspberrypi/blob/c3b3cd6efd300cd2f9ef0e952d2ebd5077bb17af/recipes-kernel/linux/linux-raspberrypi.inc#L136-L138

It is not something that is set in Mender layers so I suppose it comes from Boot2Qt.

The options are documented here,

Though it might be worth to update the logic in meta-mender adding a space at the end to avoid this issue,

https://github.com/mendersoftware/meta-mender/blob/master/meta-mender-raspberrypi/recipes-kernel/linux/linux-raspberrypi-mender.inc#L2

As the kernel arguments are appended upstream maybe this should be the place to prepend space. However, your suggestion works evenly well.

Although Raspberry is booting, the duplicated console output during boot isn’t resolved. Once booted, the screen goes black. Deploying Qt application does work and application is starting normally.

For some reason it’s switching display mode causing this behavior. The Linux kernel takes parameters from the boot loader, U-boot in the case of meta-mender. This should explain why this is happening only with meta-mender. Although I’m not sure, do you have any suggestions?

the duplicated console output during boot isn’t resolved

Can you clarify what this is?

Can you compare the kernel arguments by reading /proc/cmdline. I would expect them to be pretty much the same with and without meta-mender.

U-Boot will starta a console on display output by default which might causing this, but this can be disabled.

It has been a while but we still encounter the same issue (after boot no console is shown on display). It affects raspberrypi3 only and is related to following issue MEN-2239.

Please see following video for clarity.

I am not sure why this would be related to MEN-2239?

Can you compare the kernel arguments by reading /proc/cmdline . I would expect them to be pretty much the same with and without meta-mender.

Would still be interesting to see above.

Also can you try this patch

Hey Mirzak,
I am trying to follow this guide with my machine (imx8mm-var-dart) from varicite.
and changed a few things so the customization in local.conf will be appropriate for my machine.
but when i try to build i get this error:
ERROR: Task do_patch in {WORKDIR}/sources/meta-mender/meta-mender-core/recipes-bsp/u-boot/u-boot-fw-utils-mender-auto-provided_1.0.bb depends upon non-existent task do_mender_tar_src in {WORKDIR}/sources/meta-variscite-imx/recipes-bsp/u-boot/u-boot-variscite.bb
ERROR: Command execution failed: 1

what should i do? does it mean that mender will not work on my qt based machine?

Typically each board requires a custom integration for Mender, so you will need to sort that out first.

We do have support for various Variscite boards, https://github.com/mendersoftware/meta-mender-community/tree/zeus/meta-mender-variscite, and you might need to add that layer as well. (do not know if your specific board is supported, but it is a starting point at least.)