【実践編】Linux/ZephyrのDevicetree(DTS)の書き方を深掘り!アドレス、参照、pinctrlを徹底解説

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

前回の記事では、Devicetree(デバイスツリー)の基本的な仕組みや、JSONに似たツリー構造の全体像について解説しました。

しかし、実際の組み込みLinuxやZephyr OSのボードポーティング(基板対応)を行うと、「#address-cells って何?」「ほかのノードをどうやって参照するの?」「ピンの割り当て(pinctrl)はどう書くの?」といった具体的な疑問にぶつかります。

今回は「実践編」として、実際の開発で頻繁に登場するDTS特有の構文と、より高度なプロパティの書き方について、一歩踏み込んで解説します。

1. アドレス指定のルール(#address-cells と #size-cells)

DTSを読んでいると、必ずと言っていいほど目にするのが #address-cells と #size-cells というプロパティです。これらは、子ノードの reg プロパティ(メモリアドレスやレジスタサイズ)を「32ビット(4バイト)の数値をいくつ使って表現するか」を定義する重要なルールです。

soc {
    /* アドレスは32bit(1セル)、サイズも32bit(1セル)で表現する */
    #address-cells = <1>;
    #size-cells = <1>;

    serial@101f1000 {
        compatible = "arm,pl011";
        /* reg = <アドレス(1セル) サイズ(1セル)> */
        reg = <0x101f1000 0x1000>;
    };

    i2c@40003000 {
        compatible = "fsl,imx-i2c";
        reg = <0x40003000 0x4000>;
        
        /* I2Cバス上のデバイスにはアドレスしかない(サイズという概念がない) */
        #address-cells = <1>;
        #size-cells = <0>;

        sensor@5c {
            compatible = "vendor,sensor";
            /* reg = <スレーブアドレス(1セル)> ※サイズ指定なし */
            reg = <0x5c>;
        };
    };
};

このように、親ノードでセル数(1セル = 32bit)を宣言し、子ノードはそのルールに従って reg を記述します。64bitアーキテクチャで広大なメモリ空間を扱う場合は、#address-cells = <2>;(32bit × 2 = 64bit)となることもあります。

2. ノード間の参照(ラベルと Phandle)

Devicetreeでは、あるデバイスが別のデバイス(GPIO、クロック、割り込みコントローラなど)に依存しているケースが多々あります。この「紐付け」を行うのがラベルと参照(&)です。

コンパイル時、参照されたノードには一意のID(phandleと呼ばれます)が自動的に割り当てられ、バイナリ上ではそのIDを使ってリンクされます。

/* GPIOコントローラ(参照元としてラベル「gpio1」をつける) */
gpio1: gpio@20000000 {
    compatible = "vendor,gpio-controller";
    reg = <0x20000000 0x1000>;
    gpio-controller;
    #gpio-cells = <2>;
};

/* LEDノード(gpio1を参照する) */
leds {
    compatible = "gpio-leds";

    led_red {
        label = "Red LED";
        /* <&ラベル ピン番号 アクティブ状態> の形式で参照 */
        gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
    };
};

gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; の部分は、「gpio1 の 5番ピンを使い、Highになった時にON(アクティブ)とする」という意味になります。GPIO_ACTIVE_HIGH はマクロ定義であり、実態は数値です。

3. 実践:ピンマルチプレクス(pinctrl)の書き方

SoCの物理ピンは、GPIO、I2C、UARTなど複数の機能を切り替えて使えるようになっています(ピンマルチプレクス)。どのピンに何の機能を割り当てるかを定義するのが pinctrl ノードです。

基板固有の .dts ファイルで最もよく編集するのがこの部分です。

/* 1. ピンの設定を定義する(通常はSoC固有の記述ルールに従う) */
&iomuxc {
    pinctrl_uart1: uart1grp {
        fsl,pins = <
            /* ピンの物理ID    機能割り当て   プルアップ等の設定値 */
            MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
            MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
        >;
    };
};

/* 2. デバイス側からピン設定を参照する */
&uart1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_uart1>; /* 定義したラベルを参照 */
    status = "okay";
};

pinctrl-names = "default"; と指定することで、デバイスドライバがロードされた(プローブされた)瞬間に、自動的に pinctrl-0 で指定したピン設定が適用されます。スリープ時用の設定("sleep")などを複数持たせることも可能です。

4. 割り込み(Interrupts)のルーティング

デバイスがCPUに対してイベントを通知するための「割り込み(IRQ)」も、Devicetreeで配線を定義します。

sensor@5c {
    compatible = "vendor,sensor";
    reg = <0x5c>;
    
    /* どの割り込みコントローラに繋がっているか */
    interrupt-parent = <&gpio1>;
    
    /* 割り込み番号とトリガー条件(例:8番ピン, 立ち下がりエッジ) */
    interrupts = <8 IRQ_TYPE_EDGE_FALLING>;
};

ここでも interrupt-parent で親となる割り込みコントローラ(またはGPIOコントローラ)を参照し、interrupts でそのコントローラ内での番号やトリガーの条件(エッジトリガーか、レベルトリガーか等)を指定します。

5. OSの挙動を制御する特殊なノード(aliases と chosen)

Devicetreeには、純粋なハードウェアの記述ではなく、OSやブートローダに情報を渡すための特殊なノードが存在します。

aliasesノード

デバイスに分かりやすい「通し番号」を割り当てます。例えば、複数のUARTがある場合、どれを /dev/ttyS0 にするかを固定できます。

aliases {
    serial0 = &uart1;
    serial1 = &uart2;
};

chosenノード

ブートローダ(U-Bootなど)からカーネルへ、動的なパラメータ(起動引数など)を渡すためのノードです。Zephyr OSの場合は、コンソール出力をどのシリアルポートに行うかなどをここで指定します。

chosen {
    /* Linuxの場合:カーネルの起動引数 */
    bootargs = "console=ttyS0,115200 root=/dev/mmcblk0p2 rw";

    /* Zephyr OSの場合:標準出力先を割り当て */
    zephyr,console = &uart1;
    zephyr,shell-uart = &uart1;
};

まとめ

今回はDTSの実践的な書き方として、アドレス指定のルール、Phandleによる参照、ピンマルチプレクス(pinctrl)、割り込み、特殊ノード(aliases / chosen)について解説しました。

  • #address-cells / #size-cells: reg プロパティの配列要素数を決定する重要なルール。
  • ラベルと参照(&): 物理的な配線の繋がり(GPIOや割り込みなど)をソフトウェア上で表現する仕組み。
  • pinctrl: 一つの物理ピンが持つ複数の機能の中から、基板設計に合わせた機能を選択・固定する。
  • chosen / aliases: ハードウェア構成だけでなく、OSのシステム設定(ブート引数やコンソール指定)を行う。

Devicetreeは単なる設定ファイルではなく、ハードウェアのデータシートをソフトウェアの言語に翻訳した設計図です。最初はプロパティの多さに圧倒されるかもしれませんが、データシートと見比べながらDTSを読み解くことで、ハードウェアとOS(Linux/Zephyr)の密接な連携が見えてくるはずです。ぜひ実際のプロジェクトで .dts をカスタマイズする際の参考にしてください。

コメント

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