Modify The BSP

There can be a significant learning curve to working with The Yocto Project and this guide will serve as a resource for developers to quickly test changes to the BSP. After working through this guide, you should be able to comfortably navigate the BSP and manually introduce custom modifications on-top of it in order to evaluate the interfaces and functionality required by your custom application.

Note

In order to follow this guide, you must have first built the BSP in its entirety and have your BSP environment initialized. Checkout the Build the BSP guide if you haven’t yet!

The built BSP has two primary directories at its root and these are the /sources and /build directories. These two directories are significant and here is a summary of why (the paths here may be slightly different for you if you deviated from the instructions):

  • ~/BSP-Yocto-NXP-i.MX7-PD23.1.2/sources - This directory contains meta-layers. Meta-layers are repositories that contain instructions for fetching, building and deploying certain software packages (those instructions are referred to as recipes). Layers can also contain instructions for changing recipes and settings introduced by other layers. This powerful override capability is what allows you to customize the supplied meta-phytec or community layers to suit your product requirements. The instructions included in meta-layers are typically referred to as recipes.

  • ~/BSP-Yocto-NXP-i.MX7-PD23.1.2/build - This directory is used by the build system during the build process and is generally referred to as $BUILDDIR in the documentation (which is a handy environment variable that gets exported automatically when you source the build environment). Packages called for by the build target, as defined by their recipes are fetched, unpacked, compiled and staged for deployment here.

Note

It is important to distinguish between modifying the local sources of a particular package and modifying the recipe for a given package!

If you are new to working with The Yocto Project, then the Yocto Project Overview and Concepts Manual will be a good document to read through to get a high level understanding of what is going on. The Yocto Project Reference Manual is the best resource for in-depth documentation regarding directory structure, recipes, tasks, and other aspects of actually working with the BSP’s build system.

Adding Packages to the BSP

The best way to see what packages are available on the target image is to check the image manifest, which is a file that is deployed along with the phytec-qt6demo-image build target. Use the following to open this file:

Host (Linux)
vim $BUILDDIR/deploy/images/phyboard-zeta-imx7d-1/phytec-qt6demo-image-phyboard-zeta-imx7d-1.manifest

If there is a package that you need that wasn’t included in the target image by default, then you should first check if the package was included in the build tree.

Host (Linux)
cd $BUILDDIR

#lists all available packages
bitbake -s

#search for specific packages by name
bitbake -s | grep <package name>

If the package you need is listed then you can add the package to the image by simply adding the following line to the end of your build’s conf/local.conf file:

conf/local.conf

IMAGE_INSTALL:append = " <package name1> <package name2>"

Adding these packages to the target image by way of the conf/local.conf file is some-what of a temporary way to introduce packages, and you will eventually add these in a more permanent way in your custom meta layer using a machine or distro configuration file (depending on which is more appropriate).

Note

The IMAGE_INSTALL variable can hold a space separated list of packages you wish to add to the default BSP. Note that the leading space in the list is necessary when appending to it!

If the package you need is not listed, then this means that PHYTEC did not include the support for the recipe in the build tree by default. If this is the case, you may need to find a community layer which introduces the recipe/package you need or create your own. Community layers can be searched on the Open Embedded Layer Index, just make sure you are searching the correct Yocto version for your BSP, BSP-Yocto-NXP-i.MX7-PD23.1.2 uses Yocto 4.0.20 Kirkstone.

Note

Adding meta-layers to the BSP that aren’t included in the build tree by default is discussed in the Create a Custom Meta-Layer guide.

Modify the Kernel Config

The BSP’s build system also includes kernel development tasks for interacting with the Linux kernel’s own menuconfig tool, which is a graphical tool for configuring the driver support included in the kernel.

In order to launch menuconfig, you’ll need these additional Host dependencies:

host:~$ sudo apt-get install libncurses5-dev libncursesw5-dev

Launch the menuconfig tool with the following command:

host:~$ bitbake linux-imx -c menuconfig

Once menuconfig launches, you can navigate the available configuration options using the arrow keys on your keyboard to enable or disable support as required.

Image of the Linux Kernel's MenuConfig utility for customizing driver support

Remember to save any changes to the kernel configuration to a .config file before exiting menuconfig.

The .config used by the build system can be found at $BUILDDIR/tmp/work/phyboard_zeta_imx7d_1-phytec-linux-gnueabi/linux-imx/5.15.71-r0.0/build/.config and you could back this up to a safe location outside of the BSP to eventually define your defconfig in your custom meta layer like so:

Host (Linux)
cp $BUILDDIR/tmp/work/phyboard_zeta_imx7d_1-phytec-linux-gnueabi/linux-imx/5.15.71-r0.0/build/.config ~/.config

Note

Files that start with a ‘.’ are typically hidden in the filesystem. If you are having trouble seeing the .config file then try the following command to list everything (including hidden files) in the directory you are searching:

host:~$ ls -a <path to .config>

Feel free to open the .config file with a text editor to verify that your change made it there. You’ll notice that the previous and original .config files are also backed up, which you could diff against to see what has changed.

Once you have saved your changes to the .config using the menuconfig utility, you can force bitbake to re-compile just the kernel to make those changes take a effect:

Host (Linux)
cd $BUILDDIR
bitbake linux-imx -c compile --force && bitbake linux-imx -c deploy --force

The do_deploy task follows the do_compile task and both must be run in order to update the binaries in your deploy directory with the changes. In order for the change to also make its way into the overall target image:

host:~$ bitbake phytec-qt6demo-image

Modify the BSP’s Kernel Source Directly

Once the BSP is built the first time, you will have access to deployed binaries as well as the local sources that were used to build them. It is possible to make changes to these local sources and re-compile them directly in the BSP. This guide will use the linux-imx package as an example but the information outlined here will be applicable to other packages such as the bootloader and others too.

Warning

The Yocto Project isn’t really intended for serious development of the individual packages called for by the recipes in the BSP’s meta-layers, it’s really meant to generate production-ready images. If you are considering significant modifications to the Linux kernel (perhaps you need to port an upstream driver), you are better off cloning the kernel repo independently, outside the scope of the Yocto BSP to focus on that development alone first with a Cross-Compilation toolchain, see Standalone Kernel Development for more information. Once major changes for a package are finalized, a new recipe-append can be created that extends the existing kernel recipe in the BSP and just applies your changes as a set of patches to the base package or just pulls from your own repo and preferred commit ID. Checkout the Standalone Kernel Development guide for more information on this.

Changes made directly to the local sources of a package should not be considered permanent, they can be easily destroyed if the package is cleaned and re-fetched by the build system.

The goal of this guide is to provide you with a way to perform quick and informal changes to the kernel or other packages for testing on the phyCORE-i.MX7 development kit. This is handy if you need to quickly enable a driver or GPIO instance and you already have the BSP built, for example.

This section of the guide won’t focus on applying changes to the BSP components in the “correct way” by use of a custom meta-layer. For instructions on that process, checkout the Create a Custom Meta-Layer guide when you are ready to begin consolidating all your changes to the stock BSP.

Change the Linux Kernel Device Tree

Let’s try making a small change to the kernel’s device tree and enable a heartbeat LED using the User LED1 (D13) to let us know that the system is alive automatically upon boot (this User LED1 is automatically on by default, checkout the GPIO guide to learn more about controlling it as-is):

phyCORE-i.MX7 User LED

Use your favorite text editor to open the device tree file corresponding to the phyCORE-i.MX7 development kit’s carrier board:

Host (Ubuntu)

vi $BUILDDIR/tmp/work/phyboard_zeta_imx7d_1-phytec-linux-gnueabi/linux-imx/5.15.71-r0.0/git/arch/arm/boot/dts/imx7s-pba-c-09.dtsi

Edit the file according to the following diff:

Device Tree Diff

...
/ {
    pbac09_leds: pbac09-leds {
            compatible = "gpio-leds";
            pinctrl-names = "default";
            pinctrl-0 = <&pinctrl_pbac09_leds>;

            pbac09-led-1 {
                    gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
-                   linux,default-trigger = "gpio";
+                   linux,default-trigger = "heartbeat";
                    default-state = "on";
            };
    };
...

This diff outlines changes to the User LED device node. Essentially, we are changing the default trigger for the LED to “heartbeat” in order to configure it to blink with a heartbeat pattern by default (useful for knowing if the SOM is booted into Linux or not).

Force the Change to Get Compiled

When testing changes applied directly to the build’s local sources (in $BUILDDIR/tmp/work/), the build system will not automatically detect that the local source has changed unless you specifically instruct the build system to recompile it first. This means that you can’t just modify the kernel source at $BUILDDIR/tmp/work/phyboard_zeta_imx7d_1-phytec-linux-gnueabi/linux-imx/5.15.71-r0.0/git/ and expect the build system to automatically take the change into account the next time phytec-qt6demo-image is built.

The following command should be used after applying some change directly to the local kernel source in the $BUILDDIR/tmp/work/phyboard_zeta_imx7d_1-phytec-linux-gnueabi/linux-imx/5.15.71-r0.0/git/, such as we did above when we added the code to enable the heartbeat LED:

Host (Linux)
cd $BUILDDIR
bitbake linux-imx -c compile --force && bitbake linux-imx -c deploy --force

Once the kernel is forcefully recompiled and deployed independently, you can re-deploy it as a part of the overall target image:

host:~$ bitbake phytec-qt6demo-image

Using the newly deployed image to boot the phyCORE-i.MX7 development kit should quickly confirm that the User LED1 is blinking and that the kernel modification was successfully applied.

Save the Change

Keep in mind that manual changes applied directly to the sources in $BUILDDIR/tmp/work/ are temporary since they aren’t being tracked by the build system yet (the changes will be destroyed upon “cleaning” the package, see below for more information). For this section of the guide, we will assume you made some kernel change (such as the heartbeat LED change demonstrated above) and that you are satisfied enough with the change that you would like it to apply it automatically to the BSP whenever it is built.

The first thing to do is to export the change as a patch file. To do this, navigate to the package repository you modified:

Host (Linux)
cd $BUILDDIR/tmp/work/phyboard_zeta_imx7d_1-phytec-linux-gnueabi/linux-imx/5.15.71-r0.0/git/

Before actually creating the patch, you may want to review the changes made to the repository to ensure everything is as you expect it. Use git to do this:

host:~$ git diff
host:~$ git status

Export a patch file based on the current changes applied on-top of the base kernel and save it to a safe location outside the BSP (such as your home directory):

host:~$ git add <modified files>
host:~$ git commit
host:~$ git format-patch -1

Patch files work best when they capture changes that are very specific in their purpose. For example, instead of having one “mega” patch that enables all the unique features of your custom system, break up your customizations such that each patch is responsible for a specific interface or driver. This will make maintaining your meta-layer much easier later on.

Note

Eventually, you will have a set of patches that modify the functionality of the phyCORE-i.MX7 SOM in a way that is specific to your application requirements and the design of your custom carrier board (if applicable). This collection of patches should eventually be consolidated into a custom Meta-Layer specific to your system and added in a modular way to the BSP. Checkout the Create a Custom Meta-Layer guide when you are ready to begin finalizing your production image.

Clean Packages

When testing changes, it will be necessary to get back to a known working-starting point at some time or another. To do this, all recipes have a do_clean task defined that instructs the build system to delete all the unpacked sources for a given target (including the changes manually applied there). The next time the same package is built, it will be re-unpacked from the cached source tarball which effectively reverts your changes back to their original BSP defaults.

Clean the package:

host:~$ bitbake linux-imx -c clean

Alternatively, the do_cleanall task will delete the unpacked sources AND the cached source tarball. Running the ‘cleanall’ task on a package will require the package sources to be re-fetched on the next build.

Modifying the BSP Sources With ‘devtool’

Modifying the sources directly in the build directory (such as at the source locations described above) is a viable way to test small changes to your target software. In order to do that, you just have to force bitbake to re-run the do_compile and do_deploy tasks for the changed package since the build system won’t know that you changed any sources. One thing to note about this method is that the changes are volatile in that if you clean and rebuild any component of a software image, the changes you have in place will be destroyed (this is because the sources are re-fetched and then re-compiled).

A better method for reliably testing, tracking and incorporating incremental changes to any component or package called for within a Yocto based BSP is to leverage devtool. Devtool can be used to setup workspace environments (that persist between cleans) that allow you to modify components, here is an example:

  • Run the following to modify the Linux kernel used in PHYTEC’s BSP-Yocto-NXP-i.MX7-PD23.1.2 release:

host:~$ devtool modify linux-imx

You should now see a new ‘workspace’ directory at $BUILDDIR/workspace, this is a workspace meta-layer that is automatically enabled within the BSP’s active layers (listed in conf/bblayers.conf). Changes can be made directly to the linux-imx source at $BUILDDIR/workspace/sources/linux-imx and this directory will automatically be used whenever linux-imx is re-built using bitbake. From here, you could use git to add a remote repository to push changes to and you could export patches for incorporation into your own meta-layer.

Note

devtool is a good method for modifying individual packages called for in a BSP but it still introduces a lot of overhead since you have to leverage the entire Yocto build system (which is best suited for generating production-ready disk images) to iterate changes on individual packages. When applicable, it is better to install a compatible cross-compilation toolchain and perform development on the individual packages, outside of Yocto, to further accelerate development. Checkout the Standalone Kernel Development guide for an example of doing this with the Linux kernel (you can generate your patches faster this way throughout development).