Leverage Yocto/OpenEmbedded for your embedded software deployment

December 16, 2014

Story

Leverage Yocto/OpenEmbedded for your embedded software deployment

Developing an application and storing it on the device's ROM is no longer a simple deployment process on current embedded devices. Once you have your...

Developing an application and storing it on the device’s ROM is no longer a simple deployment process on current embedded devices.

Once you have your application ready for the next testing/release cycle, you still have to reintegrate it with your OS, tweak configuration files, enable the automatic start of your stuff, and so on, and package it into a form that allows updating the devices.

This article outlines how this integration can be automated for Embedded Linux-based devices with the help of Yocto/OpenEmbedded and thus make the process less error prone, more repeatable, and using well defined versions of each of the components you use.

Chances are high that your hardware supplier already uses Yocto/OpenEmbedded for its Linux BSP. Instead of using that generic BSP as is, simply integrate your application into the Yocto/OpenEmbedded build process and have a fully automated build of your finished deliverables.

Yocto/OpenEmbedded

Yocto and OpenEmbedded together form a build framework that creates kernel images, root file system images, and installable packages from source code.

The framework uses meta information (called recipes) for downloading/compiling/deploying of software packages on a x86/x86_64 Linux build host for a target device.

The recipes are structured into layers. Layers aggregate recipes for distribution, BSP functionalities for different CPU/SBC/Module vendors, the base system, domain specific software and so on. Many of the available layers and recipe can be found through this web interface.

A basic understanding of Yocto/OpenEmbedded is required to make full use of this article. The project comes with excellent documentation, see the above links or dive directly into the manual.

On top of that I can recommend Otavio Salvador and Daiana Angolini’s book to get you jump started.

Setting up Yocto/Openembedded

For this article we will use the Toradex Colibri T30 computer module. Follow the set up instructions.

Find and execute the instructions provided by your SoC or module supplier to get your initial set up.

Then test your installation by building one of the already provided targets to make sure that the installation worked before we start fiddling with it.

To save some time, build a simple image. Don’t forget that you will have to source a script to set the environment before any bitbake operation. In our case:

oe-core> . export
build> bitbake -k core-image-base
 

The build will take some time and then you’re hopefully greeted with a final message: “NOTE: Tasks Summary: Attempted 1806 tasks of which 23 didn’t need to be rerun and all succeeded.”

Now we are ready to customize the build for our product’s needs.

Creating the layer that holds your application and image recipe

This is explained in great detail here. Note that the layer described below can also be downloaded here.

We add a new layer in stuff/ that will hold our application’s recipe and the modifications to the image recipe. Lets call the new layer meta-product:

stuff> git init meta-product
stuff> mkdir -p meta-product/conf

meta-product> cat conf/layer.conf
BBPATH .= ":null{systemd_unitdir}/system/ null{sysconfdir}/systemd/system/
+    install -m 0644 ${WORKDIR}/fb-draw.service null{systemd_unitdir}/system
+    ln -s /dev/null null{sysconfdir}/systemd/system/[email protected]
 }
+
+NATIVE_SYSTEMD_SUPPORT = "1"
+SYSTEMD_PACKAGES = "${PN}"
+SYSTEMD_SERVICE_${PN} = "fb-draw.service"
 

Modifying the image

Now that we have a recipe that builds our application we have to add it to the list of deployed packages in our image. Also add some other stuff to make the resulting image more usable, a SSH server and the connman network manager adds some networking capabilities.

By default an image builds a root file system and binaries of the bootloader and kernel. Some BSPs provide additional logic to ease the deployment to the target hardware. For instance the meta-fsl-arm BSP for Freescale-based SoCs builds a SD card image file from which the target can directly boot. With the Toradex BSP one can build a tarball that contains all the tools and data to deploy the image onto a module.

The meta-fsl-arm deployment helpers are realized with classes/image_types_fsl.bbclass and are included through the machine configuration files. Nothing needs to be done in the image to have that functionality in place.

In order to use Toradex BSP’s deployment function the image recipe must define the variable IMAGE_NAME and include recipes/images/trdx-image-fstype.inc:

meta-product> cat recipes-core/images/product-image.bb:
SUMMARY = "A console-image for our fb-test product."

IMAGE_FEATURES += "ssh-server-openssh"
IMAGE_INSTALL += "fb-draw"
IMAGE_INSTALL += "connman connman-systemd connman-plugin-loopback connman-plugin-ethernet"

LICENSE = "MIT"

#create the deployment directory-tree
PV = "V1.0"
IMAGE_NAME = "${MACHINE}_product"
require recipes/images/trdx-image-fstype.inc

inherit core-image
 

Tweaking U-Boot and the Linux kernel

As we use the framebuffer directly with our application we need to remove the framebuffer console from the kernel’s configuration or the kernel will keep displaying a cursor in an area of the screen.

(Alternatively just define the vt.global_cursor_default=0 kernel boot argument, see http://developer.toradex.com/knowledge-base/splash-screen-linux)

Additionally, just for the exercise we will be changing the U-Boot environment to remove the kernel console output to the framebuffer console as well as changing the display resolution.

Recipes can be altered by providing a file with the same basename as the recipe but the extension bbappend. The content of the original file will be appended with what is in the bbappend file. With this mechanism we can inject a patch file used to alter the kernel and U-Boot sources:

meta-product> cat recipes-kernel/linux/linux-toradex_git.bbappend
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
SRC_URI += "file://defconfig-product.patch" 

meta-product> cat recipes-kernel/linux/linux-toradex/defconfig-product.patch
diff --git a/arch/arm/configs/colibri_t30_defconfig b/arch/arm/configs/colibri_t30_defconfig
index 050351d..e1ef222 100644
--- a/arch/arm/configs/colibri_t30_defconfig
+++ b/arch/arm/configs/colibri_t30_defconfig
@@ -253,7 +253,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_GENERIC is not set
 CONFIG_BACKLIGHT_PWM=y
 CONFIG_BACKLIGHT_TEGRA_PWM=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y

meta-product> cat recipes-bsp/u-boot/u-boot-toradex_git.bbappend
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
SRC_URI_T30 += "file://u-boot-product.patch"

meta-product> cat recipes-bsp/u-boot/u-boot-toradex/u-boot-product.patch
diff --git a/include/configs/colibri_t30.h b/include/configs/colibri_t30.h
index ffcf88f..b5d889e 100644
--- a/include/configs/colibri_t30.h
+++ b/include/configs/colibri_t30.h
@@ -185,12 +185,12 @@
   NFS_BOOTCMD \
   SD_BOOTCMD \
   "setup=setenv setupargs asix_mac=${ethaddr} " \
-      "consoleblank=0  no_console_suspend=1 console=tty1 " \
+      "consoleblank=0  no_console_suspend=1 " \
       "console=${console},${baudrate}n8 debug_uartport=lsport,0 " \
       "${memargs}\0" \
   "setupdate=load mmc 1:1 ${kernel_addr_r} flash_mmc.img " \
       "&& source ${kernel_addr_r}\0" \
   USB_BOOTCMD \
-  "vidargs=video=tegrafb0:640x480-16@60\0"
+  "vidargs=video=tegrafb0:800x600-16@60\0"
 
#endif /* __CONFIG_H */
 

Now we are ready to build our image:

oe-core> . export
build> bitbake product-image
 

The image can be found in build/out-eglibc/deploy/images/colibri-t30/colibri-t30_productV1.0_20141128.tar.bz2.

Next steps

With little additional effort we can make use of vendor supplied Yocto/OpenEmbedded meta-data to create a tailored Linux image that contains all necessary components to deploy a product’s software.

The process ensures automated creation of our image with well-defined versions of third party as well as our own components and simplifies the error prone process of going though deployment checklists to put together an image manually out of bits and pieces grabbed from several different sources.

To go even further one could incorporate the meta-product layer into the initial Yocto/OpenEmbedded set up process, such as adding it to the repo manifest in our case.

Max Krummenacher is an Embedded Software Engineer at Toradex.

Max Krummenacher, Toradex
Categories
Open Source