Adapting to Changing Hardware: Devicetree Overlays
Introduction
We showed off the
"Devicetree" in the Zephyr Project RTOS in the earlier blogs. We can
tell the OS about the hardware in our system thanks to the Devicetree. Zephyr
supports a large number of well-known System-On-Chips (SoCs) and related
development boards, as was evident in the first blog post. For every board and
associated SoC, Zephyr already has a Devicetree. A development board with the
SoC that will be utilized in the finished product design is the first thing I
aim for when I start writing firmware for a new project.
That being said, the development
board's configuration—including pinouts and other peripheral features—usually
differs from the final design. I use "Devicetree overlays," a
Zephyr-supported method of overriding an existing Devicetree's configuration,
to address these discrepancies. I'll walk through how to use a Devicetree
overlay in this blog post.
I2C On A
Nordic nRF52840
An example is the most effective way to demonstrate how to
use Devicetree overlays. This blog post will demonstrate how to change the pin
on the Nordic nRF52840 development kit
(https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dk) that is
utilized for one of the I2C peripherals. Finding the default pins for the
nRF52840 development kit's "I2C0" peripheral is the first step. The
Devicetree for this board is listed in our Zephyr checkout under
boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts, as I demonstrated in a
prior blog post. Searching for "i2c0" in this file yields the
following entry:
arduino_i2c: &i2c0 {
compatible = "nordic,nrf-twi";
status = "okay";
pinctrl-0 = <&i2c0_default>;
pinctrl-1 = <&i2c0_sleep>;
pinctrl-names = "default", "sleep";
};
The "pinctrl-0" and
"pinctrl-1" entries in the node, which point to the
"i2c0_default" and "i2c0_sleep" nodes, respectively,
specify the pins used for the i2c0 peripheral. Nevertheless, this file does not
contain "i2c0_default." Rather, it can be found in the same directory
under "nrf52840dk_nrf52840-pinctrl.dtsi." The following entries
appear if we open this file and perform another search for "i2c0.":
i2c0_default: i2c0_default {
group1 {
psels =
<NRF_PSEL(TWIM_SDA, 0, 26)>,
<NRF_PSEL(TWIM_SCL, 0, 27)>;
};
};
i2c0_sleep: i2c0_sleep {
group1 {
psels =
<NRF_PSEL(TWIM_SDA, 0, 26)>,
<NRF_PSEL(TWIM_SCL, 0, 27)>;
low-power-enable;
};
};
According to the listing above, the nRF52840 development
kit's I2C0 peripheral's default pins are 0.26 (for SDA) and 0.27 (for SCL).
I'll explain the distinction between the "default" and
"sleep" nodes in a later blog post, along with why it might be advantageous
to designate distinct pins for each. To view the final device tree with the
default configuration, we must first create an application that targets the
nRF52840 development kit. Any example will do, and we've built the blinky
application as follows in this blog post:
[zephyr_3.2 09:14:57]$ west build -p
always -b nrf52840dk_nrf52840 zephyr/samples/basic/bli
If we
search for “i2c0” in this file, we find the following:
i2c0: arduino_i2c: i2c@40003000 { compatible = "nordic,nrf-twi"; #address-cells = < 0x1 >; #size-cells = < 0x0 >; reg = < 0x40003000 0x1000 >; clock-frequency = < 0x186a0 >; interrupts = < 0x3 0x1 >; status = "okay"; pinctrl-0 = < &i2c0_default >; pinctrl-1 = < &i2c0_sleep >; pinctrl-names = "default", "sleep";};
The fully specified pin that
corresponds to "0.26" and "0.27" for the "SDA"
and "SCL" lines, respectively, can be found by searching for
"i2c0_default."
i2c0_default: i2c0_default { phandle = < 0x4 >; group1 { psels = < 0xc001a >, < 0xb001b >; };};
Pin
Customization Using An Overlay
I will then show you how to modify the I2C0 peripheral's
default pin configuration. Let's start by moving the "blinky" application
to a different directory from the Zephyr source tree:
[zephyr_3.2 09:32:31]$ cp -r zephyr/samples/basic/blinky ./
Then,
let’s create a “boards” directory inside the application:
[zephyr_3.2 09:39:08]$ mkdir blinky/boards
Finally,
let’s create a file called “nrf52840dk_nrf52840.overlay” inside “blinky/boards”
with the following content:
&pinctrl { custom_i2c: custom_i2c { group1 { psels = <NRF_PSEL(TWIM_SDA, 1, 15)>, <NRF_PSEL(TWIM_SCL, 1, 14)>; }; };};&arduino_i2c { pinctrl-0 = <&custom_i2c>; pinctrl-1 = <&custom_i2c>; pinctrl-names = "default", "sleep";};
The "&" symbol in the overlay above refers to
the "pinctrl" node. Inside the pinctrl node, it generates a new node
named "custom_i2c" and specifies that pins "1.15" and
"1.14" should be used for the SDA and SCL lines, respectively. The
"arduino_i2c" node is then referenced in the file, replacing the
current pin definitions with the node above. This file can be saved, and our
custom blinky application can be rebuilt:
[zephyr_3.2 09:53:09]$ west build -p always -b nrf52840dk_nrf52840 blinky/
Searching for i2c0 in the final
Devicetree file (keep in mind that it's under build/zephyr/zephyr.dts) reveals
that the node refers to our "custom_i2c" pin definition:
i2c0: arduino_i2c: i2c@40003000 { compatible = "nordic,nrf-twi"; #address-cells = < 0x1 >; #size-cells = < 0x0 >; reg = < 0x40003000 0x1000 >; clock-frequency = < 0x186a0 >; interrupts = < 0x3 0x1 >; status = "okay"; pinctrl-0 = < &custom_i2c >; pinctrl-1 = < &custom_i2c >; pinctrl-names = "default", "sleep";};
If we
search for the “custom_i2c” node, we can confirm that the resulting pin
configuration is different from the configuration specified by the
“i2c0_default” node:
custom_i2c: custom_i2c { phandle = < 0x4 >; group1 { psels = < 0xc002f >, < 0xb002e >; };};
Summary
In this blog post, I showed how to
use Zephyr Devicetree overlays to override the pin configuration that a
standard Devicetree describes for a board that Zephyr supports. In this blog
post, I demonstrated how to modify the nRF52840 development kit's default I2C
pins to a custom set in the overlay. As previously stated, I will show how
various pin configurations for the "default" and "sleep"
modes can be useful as power-saving features in a subsequent blog post.
Adapting hardware configurations efficiently is crucial for ensuring the
success of your embedded projects. At Silicon Signals, we specialize in
creating custom solutions tailored to your needs, from Devicetree overlays to
complete hardware and software development. Whether you're looking to modify
peripherals or optimize your power-saving features, our team is here to guide
you through the complexities and help you build the perfect solution.
👉 Contact Us Today and let's work
together to enhance your embedded systems with expert hardware design and
software development!

Comments
Post a Comment