It’s not uncommon when developing IoT devices run the devices using different environments. For example, you may have a test server for working out the bugs in both your firmware and cloud interface. You may also have a dedicated production server which will run customer applications. As you can imagine, switching between the two can get hairy and error prone. One way we can fix that problem is through some crafty configuration management.
In this post, i’ll review some of the easiest way you can organize your projects for sanity (and fun!) So fire up your favorite text editor and let’s get rolling!
boards
directory
The boards
directory is a modern addition to Zephyr. Located usually in <your project root>/boards
, you can add configuration and device tree overlay files. Zephyr uses these files to configure the compilation pipeline and also used to enable/disable certain features. You should check out the talk I gave about device tree and setting up hardware at the Zephyr Development Summit. (Should be posted here very soon.)
These files usually contain same name as your board (ex. circuitdojo_feather_nrf9160ns.conf
and circuitdojo_feather_nrf9160ns.overlay
). Let me explain more about each so you have an idea of how to take advantage of this great feature of Zephyr.
.conf
files help you define board specific configuration variables. This allows you to turn on and off features if they’re needed by your board.
For example, in order to get the best low power sleep current the accelerometer needs to be enabled (counterintuitive I know):
# Add the accelerometer
CONFIG_I2C=y
CONFIG_SENSOR=y
CONFIG_LIS2DH=y
The reason why we enable the device is because Zephyr has built in power saving capabilities for devices. Additionally, we enable it in order to disconnect the pull-up connected to the LIS2DH12TR SA0 pin. (More on that in a second!)
.overlay
lets you edit your device tree entry for your device. Imagine it as a way of creating application specific patches to the .dts
files placed in the zepyr/boards
directory.
For the above example, the accelerometer needs to be defined in the device tree along with the disconnect-sdo-sa0-pull-up
flag:
// Enable accelerometer with SA0 pull-up disabled (saves 100uA)
&i2c1 {
lis2dh@18 {
compatible = "st,lis2dh";
label = "LIS2DH";
reg = <0x18>;
irq-gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>, <&gpio0 30 GPIO_ACTIVE_HIGH>;
disconnect-sdo-sa0-pull-up;
};
};
This flag disables the SA0 pull-up (25k) which will draw ~135µA no matter what. That’s no bueno especially when it comes to low power applications! When optimizing for low power on the nRF9160 Feather, this was the last step from going to about 150µA to about 35µA. (Nearly a 5x improvement!)
I will add that by default Zephyr will look for a directory called boards in your project root. For the following sections, that is not the case. So we’ll need to make sure that Zephyr knows about them using CMakeLists.txt
.
Let’s talk more about how we can split up our prj.conf
specifically in the next section.
conf directory
While you can specify all your configuration variables in prj.conf
you don’t need to. In this section we’ll create a folder called conf
and put all our remaining sub-configuration files in here. Then, depending on environment variables set during compilation, we can make Zephyr pick the right one for the job making your life simpler.
Backend
One way you can differentiate the configuration variables between production and development is by using different .conf
files. For example, you could have a dev.conf
and a prod.conf
. If you’re running Amazon AWS you can set the Broker Host Name for MQTT using
CONFIG_AWS_IOT_BROKER_HOST_NAME
.
For example you can set your test endpoint in dev.conf:
CONFIG_AWS_IOT_BROKER_HOST_NAME="test.endpoint.com"
While you can set your production endpoint in prod.conf
CONFIG_AWS_IOT_BROKER_HOST_NAME="prod.endpoint.com"
Then you can configure which file to load by using some simple logic in CMakeLists.txt:
# Print out build type
message(STATUS "Build type: ${BUILD_TYPE} 🚀")
# Define configuration files.
list(APPEND CONF_FILE
${CMAKE_CURRENT_SOURCE_DIR}/prj.conf
${CMAKE_CURRENT_SOURCE_DIR}/conf/${BUILD_TYPE}.conf
)
In this case i’m using BUILD_TYPE
to determine what file to import. BUILD_TYPE
simply is used as the prefix of the .conf
file. Setting BUILD_TYPE
to prod
will cause CMake to look for prod.conf
.
Not defined? No problem. You can add a check and set a default value for BUILD_TYPE
like so:
# Determine the build type
if (NOT BUILD_TYPE)
set(BUILD_TYPE debug)
endif()
This way when you’re building your project with west
you’ll always have a safe default so things don’t break! Remember, you’ll want to put this entry before importing/running list(APPEND
within CMakeLists.txt
.
MCUBoot
If you find yourself needing to configure MCUBoot, there is no need to edit the files within the zephyr/bootloader
folder. You can create .conf
and .overlay
files just like you can everywhere else in Zephyr!
For example, you can edit your device tree using an .overlay
. For example here’s circuitdojo_feather_nrf9160ns.overlay
from a project i’m working on:
/ {
aliases {
bootloader-led0 = &blue_led;
};
};
// Full speed ahead
&uart0 {
status = "okay";
current-speed = <1000000>;
tx-pin = <6>;
rx-pin = <5>;
};
I’m adding an alias for bootloader-led0
since it’s not included in the version of Zephyr i’m using at the moment. (Upstream has it so this is a temporary fix)
Also, importantly, since the nRF9160 Feather requires MCUBoot to use 1M BAUD, i’m also setting that here along with the TX and RX pins.
In order to use these .conf
and .overlay
files they’ll need to be imported in your project’s CMakeLists.txt. Here’s an example:
# MCUboot related
list(APPEND mcuboot_OVERLAY_CONFIG
"${CMAKE_CURRENT_SOURCE_DIR}/conf/mcuboot/mcuboot.conf"
)
# Adding custom overlay
message(STATUS "Adding .overlay for mcuboot.")
list(APPEND mcuboot_DTC_OVERLAY_FILE
"${CMAKE_CURRENT_SOURCE_DIR}/conf/mcuboot/circuitdojo_feather_nrf9160ns.overlay"
)
Specifically, Zephyr looks for mcuboot_OVERLAY_CONFIG
and mcuboot_DTC_OVERLAY_FILE
in order to append any further overlays for the MCUBoot compilation process to use.
Summing it up
Wrangling Zephyr’s configuration system is just one of the important facets that you’ll need to master in order to get the most of this amazing RTOS. Understanding CMake and how west
works is critical for your success in using Zephyr. You should now know that you can add board specific overlays, environment specific configurations and MCU configurations/overlays with ease. Give it a shot and let me know how it goes in the comments!
Last Modified: 2021.7.10