Devicetree overlays, CMake, and multi-image builds
In lesson 2, we covered the devicetree, a hierarchical data structure that describes hardware through nodes with belonging properties. It is not recommended to modify the devicetree directly, so instead we use devicetree overlays to do this. The overlay only needs to include the node and property it wants to modify.
The overlay file shown above will set node spi1 to have the status okay, essentially enabling this node. Then it is changing the pin configuration for the SPIM_MOSI line to pin 25 by changing the appropriate sub-nodes and properties in the &pinctrl node. Note that you must change the pin configuration for both the default and sleep states.
If an overlay file sets a node’s property to a value it already has, the node will just remain unchanged.
One easy way to create an overlay file is to create a file with the name of the board and the extension .overlay and place it directly in the application root directory. The build system will automatically search for this file type and include it if it finds one.
However, there are several other ways to include overlay files. See Set devicetree overlays for a list of ways to include a devicetree overlay in your application.
Overlays are also DTS files, the .overlay extension is just a convention that makes their purpose clear.
In the nRF Connect SDK, all applications are CMake projects. This means that the application controls the configuration and build process of itself, Zephyr, and all sourced libraries. The file CMakeLists.txt is the main CMake project file and the source of this build process configuration.
We will take a closer look at some of the functions in the exercise.
Now that we have covered all the different elements of an application in the nRF Connect SDK, it’s time to talk about images and multi-image builds. The firmware running on a device can consist of one application or image, or it can consist of multiple images, making it a multi-image build.
Multi-image builds consist of a parent image and one or more child images, where the child image is included by the parent image.
Multi-image builds are used in the following cases:
Applications that have DFU enabled (serial, USB-CDC, BLE, etc.)
Multi-core or multi-partition targets (nRF53 and nRF9160)
In these cases, the creation of the multi-image build happens by default so it isn’t something a developer needs to take care of. More details on Multi-Image builds can be found here.
A good example of a multi-image build happening automatically is when building for a non-secure domain in the nRF53 or the nRF91 series. If your application firmware is built for the non-secure domain, meaning you need to implement security measures, the build will produce two separate environments (a secure processing environment and a non-secure processing environment), which is also referred to as “Security by Separation”. The two separated images are the application firmware and the Trusted Firmware-M (TF-M).
The application firmware is run in the Non-secure Processing Environment, it is basically your application firmware which utilizes the nRF Connect SDK libraries and runs the Zephyr RTOS. The second image, is the TF-M which is created automatically when building for a non-secure domain and runs in a Secure Processing Environment (SPE). This secure image provides the security services needed to the application firmware. This separation ensures that security-sensitive data is in a secure processing environment and access to it is heavily restricted.
Whereas, if your application firmware is built for a secure domain, it means you trust the domain where the application will run and everything in your application is inherently trusted and you will not have Security by Separation. This will run the whole project in a Non-Secure Processing Environment (NSPE).
Lets use the nRF9160 as an example. When building for the nRF9160DK, you must build for either nrf9160dk_nrf9160 or nrf9160dk_nrf9160_ns.
nrf9160dk_nrf9160: Used for building for a secure domain. The application is built as a single image, without any separation.
nrf9160dk_nrf9160_ns: The “ns” means “building for a non-secure domain. This will create two images. First, the application will be built as a non-secure image. Second, the TF-M will automatically be built as the secure image. These two images will be merged to form a combined image that will be used when programming or updating the device.
As seen in the above figure, building for a secure domain and having only one image means that for example if sensitive data such as passwords is stored in the flash memory, the user application can access it easily. This can be a security hazard if the user application is buggy or compromised. Whereas, when building for a non-secure domain, the TF-M governs the access of the user application to the flash memory and handles security-related tasks, adding an extra layer of security through this separation.