【第5回】Zephyr OSの真骨頂!全体構成とDeviceTree・Kconfigによるハードウェア完全抽象化(連載最終回)

この記事は約8分で読めます。

こんにちは!「Zephyr OS入門」連載の第5回(最終回)です。

[第4回:スレッド間通信とPOSIXライクな同期] では、ミューテックスやメッセージキュー、そしてPOSIX互換の k_poll を使ったスマートなイベント駆動プログラミングについて解説しました。

連載の締めくくりとなる今回は、Zephyr OSのアーキテクチャ(全体構成)を解き明かしながら、従来のRTOS(FreeRTOS等)と一線を画す「DeviceTree(デバイスツリー)」と「Kconfig(menuconfig)」を深掘りします!

「マイコンを別のメーカーに変えたら、C言語コードを大量に修正しなければならない…」

そんな組み込み開発あるあるの悩みを完全に解決する仕組みを、WSL2+QEMU環境で体験してみましょう!

1. Zephyr OSの全体構成(アーキテクチャ)

Zephyr OSがなぜこれほど高いポータビリティ(移植性)と豊富な機能を持っているのか、その秘密は緻密にレイヤー化(階層化)されたOS構成にあります。

まずはシステム全体の構成図を見てみましょう。

各階層(レイヤー)の役割

  1. Application Layer(アプリケーション層)ユーザーが作成する main.c などの固有コードです。下層のハードウェア型番を直接意識しない記述を行います。
  2. Subsystems / POSIX API Layer(サブシステム層)Bluetoothスタック、VFS(仮想ファイルシステム)、ネットワークプロトコル、POSIX互換レイヤーなど、高度なミドルウェア機能群が標準提供されています。
  3. OS Kernel Layer(カーネル層)第3回・第4回で解説したスケジューラや、スレッド間通信(ミューテックス・セマフォ・メッセージキュー)を管理する最小限かつ高速なカーネルコアです。
  4. Hardware Abstraction / Driver Layer(ハードウェア抽象化・ドライバ層)★今回の主役です!マイコン個別のレジスタ操作を隠蔽する「統一Driver API」と、基板上の接続情報を保持する「DeviceTree」で構成されます。
  5. Hardware(ハードウェア層)実機のマイコン(STM32, nRF52等)や、WSL2上で動作するQEMU仮想マシンです。

2. なぜZephyrはハードウェア依存コードを書かなくていいのか?(DeviceTreeとDriver)

一般的なマイコン開発では、STM32なら HAL_GPIO_WritePin()、ESP32なら gpio_set_level() のように、メーカー固有のHAL(ハードウェア抽象化レイヤー)関数をC言語内に直接記述します。

一方、Zephyr OSではLinuxカーネルと同じ「DeviceTree」という技術を採用しています。

ポイント

  • C言語ソースには、マイコンのピン番号やレジスタアドレスを直接書かない
  • ハードウェア構成(「どのピンにLEDが接続されているか」等)は DeviceTreeファイル(.dts / .overlay に外出しする
  • アプリからは全マイコン共通の Zephyr Driver API を呼ぶだけ!

これにより、マイコンボード(ターゲット)を切り替えても、C言語コードは1行も修正せずにコンパイルし直すだけで動かすことができます。

3. Kconfig と DeviceTree の役割分担(menuconfig の活用)

Zephyrプロジェクトには、ビルド時にシステム構成を決める2つの重要な設定ファイルが存在します。

設定ファイル拡張子役割・イメージ
Kconfigprj.conf「OS機能のON/OFF(ソフトウェア構成)」マルチスレッド有効化、GPIOドライバの組み込み、ログ機能(CONFIG_LOG=y
DeviceTree.dts / .overlay「ハードウェア接続情報の記述(物理構成)」GPIOピンの役割定義、I2Cアドレス、UARTボーレート設定

💡 Linuxでお馴染み!視覚的に機能を設定できる menuconfig

一般的なRTOSでは FreeRTOSConfig.h などのヘッダーファイルをテキストエディタで手作業編集しますが、Zephyr OSでは Linuxカーネル開発と同じ menuconfig(ターミナルUI) が使えます。

WSL2のターミナルで以下のコマンドを実行するだけで、インタラクティブな設定画面が立ち上がります。

west build -t menuconfig
Zephyr menuconfig画面

menuconfig の利点

  • 依存関係を自動解決: たとえば「BLE機能をONにしたら、必要な暗号化ライブラリも自動で有効化される」といった依存制御をOSが自動で行ってくれます。
  • マクロ名の暗記が不要: 画面上でスペースキーを押してチェックを入れるだけで設定完了。変更内容は自動的に prj.conf やビルド設定へ反映されます。

4. WSL2+QEMUで体験!DeviceTreeオーバーレイの書き方

QEMU仮想環境上でも、オーバーレイファイル(app.overlay)を作成することで、独自の仮想ペリフェラル(LEDやボタン)を定義できます。

app.overlay の作成

プロジェクトディレクトリ直下に app.overlay というファイルを作成し、仮想のLEDエイリアスを定義します。

/ {
    aliases {
        /* 自作のLEDエイリアス "status-led" を定義 */
        status-led = &my_led;
    };

    leds {
        compatible = "gpio-leds";
        my_led: led_0 {
            gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
            label = "Status LED";
        };
    };
};

② C言語側のコード(main.c

C言語側からは、マイコンのポート番号やピン番号ではなく、DeviceTreeのエイリアス名(status-led)経由でアクセスします。

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>

/* DeviceTreeからエイリアス "status_led" の情報を取得 */
#define LED_NODE DT_ALIAS(status_led)

/* ノードからGPIOスペック構造体を自動生成 */
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED_NODE, gpios);

int main(void)
{
    /* DeviceTree上でデバイスが有効化されているかチェック */
    if (!gpio_is_ready_dt(&led)) {
        printk("Error: GPIO device is not ready\n");
        return 0;
    }

    /* GPIOピンを出力モードに初期化 */
    gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);

    while (1) {
        /* 1秒ごとにLED出力をトグル(反転) */
        gpio_pin_toggle_dt(&led);
        printk("LED Toggled!\n");
        k_msleep(1000);
    }

    return 0;
}

prj.conf(Kconfig)の設定

GPIOドライバ機能とログ出力を有効にするため、prj.conf に以下を記述します。(※ menuconfig 上で設定して保存しても同じ内容が書き込まれます)

# GPIOドライバを有効化
CONFIG_GPIO=y

# ログ出力機能を有効化
CONFIG_LOG=y

5. なぜこの設計が強いのか?(ポータビリティの真価)

上記のCコードを見て分かる通り、PORTAGPIO_PIN_15 といったマイコン固有の型番が一切存在しません。

もし明日「QEMU仮想環境」から「STM32NUCLEO実機」や「Nordic nRF52 DevKit」に開発ターゲットが変わったとしても、アプリケーションコード(main.c)は一切変更不要です。

west build -b nucleo_f401rewest build -b nrf52840dk_nrf52840 とビルド時のボード名を変更するだけで、Zephyrが各ボードのDeviceTreeを自動読み込みし、それぞれのマイコンに適したバイナリを生成してくれます。

6. 【連載まとめ】Zephyr OSがもたらす新しい組み込み開発

全5回にわたる「Zephyr OS入門」連載はお楽しみいただけたでしょうか?

  1. [第1回] Zephyr OSの概要・マルチプラットフォームとLinux Foundationの強み
  2. [第2回] WSL2+Ubuntuでの環境構築と west ツール&QEMUによるHello World
  3. [第3回] マルチスレッドの仕組みとプリエンプティブ/ラウンドロビンスケジューリング
  4. [第4回] スレッド間通信(ミューテックス/セマフォ/メッセージキュー)とPOSIXライクな k_poll 同期待機
  5. [第5回] OSアーキテクチャとDeviceTree・Kconfig(menuconfig)によるハードウェア抽象化

従来のRTOS開発の常識を壊し、「Linuxアプリ開発のような快適性とポータビリティ」をマイコン世界にもたらすZephyr OSは、今後のIoT・組み込み開発における標準技術になっていくことは間違いありません。

手元のWSL2環境だけでもQEMUを使って高度なマルチスレッドやDeviceTree制御を体験できますので、ぜひご自身のアイデアをZephyr OSで形にしてみてください!

最後までお読みいただき、ありがとうございました!

コメント

タイトルとURLをコピーしました