0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Zephyr RTOS 〜 Devicetree 序章 〜

Last updated at Posted at 2025-07-29

1. はじめに

本記事では、 Zephyr の特徴でかつ最大の鬼門だと思われる Devicetree について触れていきます。
まずは序章として、主要なファイルの配置や設定を変更する基本的な流れについて案内していきます。

なお、本記事では実機がなくても確認可能です。

2. 環境の準備

適宜 west build ができるところまで環境を準備してください。
環境構築は下記リポジトリの README.md に沿って行うことも可能です。

今回は下記を対象に話を進めます。

board Zephyr 環境 ビルド対象のアプリ
nucleo_f401re ~/zephyrproject zephyr/sample/basic/button

ビルドできることを確認しておきます。
(ビルドできない場合は環境を見直すこと)

nucleo_f401re 向けに button サンプルをビルド
cd ~/zephyrproject
source .venv/bin/activate
cd zephyr/samples/basic/button/

west build -b nucleo_f401re .
[3/141] Generating include/generated/zephyr/version.h
-- Zephyr version: 4.1.0 (/home/taka/zephyrproject/zephyr), build: v4.1.0
[141/141] Linking C executable zephyr/zephyr.elf
Memory region         Used Size  Region Size  %age Used
           FLASH:       16354 B       512 KB      3.12%
             RAM:        4544 B        96 KB      4.62%
        IDT_LIST:          0 GB        32 KB      0.00%
Generating files from /home/taka/zephyrproject/zephyr/samples/basic/button/build/zephyr/zephyr.elf for board: nucleo_f401re

3. Devicetree の役割

Devicetree とは、大雑把に説明すると H/W 構成を書くためのフォーマットで、ピン配やクロック、pull up/down などを設定していく仕組みを提供しています。

これを採用している最も有名なプロダクトは Linux kernel だと思いますが、採用に至った経緯は下記です。

これは、クロック設定などの些細な違いだけでボード毎のソースコードが乱立したために、「定義と実装は分けろ(超意訳)」という背景で採用に至っています。
つまり、Devicetree は C/C++ におけるヘッダーファイル的な役割で、定義だけを独立させ、実装(ソースコード)と分離する仕組みを提供しているということになります。

そして Zephyr もこの仕組みを採用しているわけですが、Linux は起動時に読み込んでデバイス構成を動的に決定するのに対し、Zephyr はビルド時に静的にデバイス構成を決定させるという大きな違いがあります。

Zephyr に於ける Devicetree は、下記ファイル群から構成されます。

ファイル名 概要
*.dts Devicetree source. これにベースに下記ファイルが連結されていく
*.dtsi dts から include して定義を追加できるようにしたファイル
*.overlay dts の定義を上書きで変更を加えるためのファイル
*.yaml dts / overlay 内で利用する左辺値(プロパティ名)の定義
*.h dts / overlay 内で利用する右辺値(プロパティ値)の定義
zephyr.dts ビルド時に上記ファイル群が結合され、最終的な dts として生成

次の章からは、これら各ファイルの配置や中身のデータ、変更方法などに触れていきます。

4. オリジナルの dts と 最終的に生成される dts

まずは、ベースとなる dts を確認します。このファイルはボード毎に配置されています。
命名ルールも決まっており、ターゲットのボード名 nucleo_f401re がそのまま dts のファイル名になっています。

dts を含む nucleo_f401re 固有のファイル群
$ ls ~/zephyrproject/zephyr/boards/st/nucleo_f401re
Kconfig.defconfig          board.cmake  nucleo_f401re.dts        st_morpho_connector.dtsi
Kconfig.nucleo_f401re      board.yml    nucleo_f401re.yaml       support
arduino_r3_connector.dtsi  doc          nucleo_f401re_defconfig

その中の user_button は以下の設定になっています。

zephyr/boards/st/nucleo_f401re/nucleo_f401re.dts の一部
        gpio_keys {
                compatible = "gpio-keys";
                user_button: button {
                        label = "User";
                        gpios = <&gpioc 13 GPIO_ACTIVE_LOW>;
                        zephyr,code = <INPUT_KEY_0>;
                };
        };

続いて 2. 環境の準備 でビルドした結果を確認していきます。
west build した際、最終的な dtsbuild/zephyr/zephyr.dts として生成されます。

zephyr/sample/basic/button/build/zephyr/zephyr.dts の一部
        gpio_keys {
                compatible = "gpio-keys";
                user_button: button {
                        label = "User";
                        gpios = < &gpioc 0xd 0x1 >;
                        zephyr,code = < 0xb >;
                };
        };

両者を比較すると、<> で囲われたラベルが16進数の値になっている事以外は、オリジナルの dts の内容と基本的に同じであることがわかります。
また、最終的な zephyr.dts は nucleo_f401re.dts よりも遥かに巨大なファイルになっていますが、これは dtsi などすべてが連結された結果となります。

5. overlay を用いた設定の上書き

5.1. dts と overlay の関連性

では、続いて dts の設定を変更してこのボタンを無効化してみます。

ただし、nucleo_f401re.dts を直接編集することも可能なのですが、お作法としてそれは推奨されません。

推奨される方法は boards/[board名].overlay というファイルを用意して、変更したい要素だけを記述していく事です。
今回でいうと、ターゲットは nucleo_f401re なので、boards/nucleo_f401re.overlay となります。

その状態で west build すると、その overlay が参照されて上書きや追加されるという仕組みとなっています。

実は overlay のファイル名やパスは色々と調整可能です。overlay の詳しい検索条件は以下を参照。

https://docs.zephyrproject.org/latest/build/dts/howtos.html#set-devicetree-overlays

5.2. overlay の記述方法

記述方法として、先述の overlay に対し上書きしたい対象のノード名に & を付けて指定し、変更を加えたいパラメータの設定値を記述します。
今回は user_button が対象のノード名で、変更を加えたいパラメータは status = "disabled"; で、これにより user_button を無効にする事ができます。
(逆に有効にする場合は status = "okay"; を用います)

実際に overlay として下記のように保存しておきます。

zephyr/sample/basic/button/boards/nucleo_f401re.overlay
&user_button {
        status = "disabled";
};

5.3. overlay を反映した結果の確認

では、この状態で改めて zephyr/sample/basic/button をビルドしてみます。

前回のビルド結果を削除して改めてビルド
$ cd ~/zephyrproject/zephyr/sample/basic/button
$ rm -rf build; west build -b nucleo_f401re .
                      :
zephyr/samples/basic/button/src/main.c:26:2: error: #error "Unsupported board: sw0 devicetree alias is not defined"
   26 | #error "Unsupported board: sw0 devicetree alias is not defined"
      |  ^~~~~
[37/141] Building C object zephyr/arch/arch/...ore/CMakeFiles/arch__arm__core.dir/nmi.c.obj
ninja: build stopped: subcommand failed.
FATAL ERROR: command exited with status 1: /usr/bin/cmake --build /home/taka/zephyrproject/zephyr/samples/basic/button/build

ビルドエラーが起きました。エラー発生箇所である zephyr/samples/basic/button/src/main.c:26 は以下の通り。

sw0 が STATUS_OKAY でなければエラーとして終了させるプリプロセッサ
 24 #define SW0_NODE        DT_ALIAS(sw0)
 25 #if !DT_NODE_HAS_STATUS_OKAY(SW0_NODE)
 26 #error "Unsupported board: sw0 devicetree alias is not defined"
 27 #endif
 28 static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios,

つまり、sw0 が STATUS_OKAY ではないためにエラーを発生させている事がわかります。
では実際に、生成された dts を確認してみます。

zephyr/sample/basic/button/build/zephyr/zephyr.dts の user_button の設定
        gpio_keys {
                compatible = "gpio-keys";
                user_button: button {
                        label = "User";
                        gpios = < &gpioc 0xd 0x1 >;
                        zephyr,code = < 0xb >;
                        status = "disabled";
                };
        };

ビルドが通っていた時と比較し status = "disabled"; が追加されている事がわかります。

さらに build/zephyr/zephyr.dts 内で user_button を検索すると、ファイル冒頭の aliasessw0 = &user_button; として割り当てられている事がわかります。

zephyr/sample/basic/button/build/zephyr/zephyr.dts の aliases の設定
        aliases {
                led0 = &green_led_2;
                sw0 = &user_button;
                pwm-led0 = &green_pwm_led; 
                watchdog0 = &wwdg;
                die-temp0 = &die_temp;
                volt-sensor0 = &vref;
                volt-sensor1 = &vbat;
        };

つまり sw0 の参照先である user_buttonstatusdisabled (つまり OKAY ではない) になっていて、ビルドエラーを発生させるプリプロセッサが機能したという事がわかります。

6. まとめ

今回は、敢えてビルドエラーを起こす方向で Devicetree の構成や変更方法についてご紹介しました。

本記事では以下の内容について触れています。

  • Devicetree の役割
  • ボード毎に用意されている dts の配置
  • ビルド時に生成される最終型の build/zephyr/zephyr.dts の把握
  • 機能の有効/無効の切り替えを overlay で変更する方法

これで既存の設定を変更する際、どこを参照して、どうやって変更するかの大まかな理解は得られるかと思います。
ただし、Devicetree では非常にたくさんの左辺値と右辺値があり、実用的に運用するためには、それらを把握した上で各種パラメータを設定していく必要があります(ここが鬼門)。

その辺の踏み込んだ内容については、次回の Devicetree の記事で解説していきたいと思います。

※ 国内の観測史上最高気温を出した日に、🎄2024年アドベントカレンダー🎅の投稿になっちゃいました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?