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?

1. はじめに

前回は、Device Tree の overlay を事前に作ったものを設定を変える運用で、いろんな設定を試しました。
今回は、その overlay の書き方の実践編として進めていきたいと思います。
この記事を読むことで、他のボードの overlay をある程度自前で設定できるようになるかと思います。

前回の記事は読まなくても進められる内容になると思いますが、読み物としてどうぞ。

2. 前回利用した overlay

今回の記事でも前回紹介した overlay をベースに話を進めます。

nucleo_g431kb 向けの overlay
/*
 * Copyright (c) 2026 Takayuki Goto <tkg.develop@gmail.com>
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/ {
	chosen {
		zephyr,console = &usart1;
		zephyr,shell-uart = &usart1;
	};
};

&lpuart1 {
    status = "disabled";
    current-speed = <115200>;

    // lpuart1_tx_pa2
    // lpuart1_rx_pa3
    pinctrl-0 = <&lpuart1_tx_pa2 &lpuart1_rx_pa3>;
    pinctrl-names = "default";

    // LL_DMAMUX_REQ_LPUART1_TX, LL_DMAMUX_REQ_LPUART1_RX
//  dmas = <&dmamux1 0 35 STM32_DMA_PERIPH_TX>,
//         <&dmamux1 1 34 STM32_DMA_PERIPH_RX>;
//  dma-names = "tx", "rx";
//  fifo-enable;
};

&usart1 {
    status = "okay";
    current-speed = <115200>;

    // usart1_tx_pa9, usart1_tx_pb6
    // usart1_rx_pa10, usart1_rx_pb7
    pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>;
    pinctrl-names = "default";

	// LL_DMAMUX_REQ_USART1_TX, LL_DMAMUX_REQ_USART1_RX
	dmas = <&dmamux1 2 25 STM32_DMA_PERIPH_TX>,
	       <&dmamux1 3 24 STM32_DMA_PERIPH_RX>;
	dma-names = "tx", "rx";
	fifo-enable;
};

&usart2 {
    status = "disabled";
    current-speed = <115200>;

    // usart2_tx_pa2, usart2_tx_pa14, usart2_tx_pb3
    // usart2_rx_pa3, usart2_rx_pa15, usart2_rx_pb4
    pinctrl-0 = < &usart2_tx_pa2 &usart2_rx_pa3 >;
    pinctrl-names = "default";

	// LL_DMAMUX_REQ_USART2_TX, LL_DMAMUX_REQ_USART2_RX
//  dmas = <&dmamux1 4 27 STM32_DMA_PERIPH_TX>,
//         <&dmamux1 5 26 STM32_DMA_PERIPH_RX>;
//  dma-names = "tx", "rx";
};

&dma1 {
	status = "okay";
};

&dmamux1 {
	status = "okay";
};

&i2c1 {
    status = "okay";
    clock-frequency = <I2C_BITRATE_STANDARD>;

    // i2c1_scl_pa13, i2c1_scl_pa15, i2c1_scl_pb8
    // i2c1_sda_pa14, i2c1_sda_pb7
    pinctrl-0 = < &i2c1_scl_pa15 &i2c1_sda_pb7 >;
    pinctrl-names = "default";
};

&i2c2 {
    status = "disabled";
    clock-frequency = <I2C_BITRATE_STANDARD>;

    // i2c2_scl_pa9
    // i2c2_sda_pa8, i2c2_sda_pf0
    pinctrl-0 = < &i2c2_scl_pa9 &i2c2_sda_pa8 >;
    pinctrl-names = "default";
};

&i2c3 {
    status = "disabled";
    clock-frequency = <I2C_BITRATE_STANDARD>;

    // i2c3_scl_pa8
    // i2c3_sda_pb5
    pinctrl-0 = < &i2c3_scl_pa8 &i2c3_sda_pb5 >;
    pinctrl-names = "default";
};

&spi1 {
    status = "disabled";
    clock-frequency = <8000000>;

    // spi1_sck_pa5, spi1_sck_pb3
    // spi1_miso_pa6, spi1_miso_pb4
    // spi1_mosi_pa7, spi1_mosi_pb5
    pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>;
    pinctrl-names = "default";
//  cs-gpios = <&gpiob 7 GPIO_ACTIVE_LOW>;
};

&spi2 {
    status = "disabled";
    clock-frequency = <8000000>;

    // spi2_sck_pf1
    // spi2_miso_pa10
    // spi2_mosi_pa11
    pinctrl-0 = <&spi2_sck_pf1 &spi2_miso_pa10 &spi2_mosi_pa11>;
    pinctrl-names = "default";
//  cs-gpios = <&gpioa 1 GPIO_ACTIVE_LOW>;
};

&spi3 {
    status = "okay";
    clock-frequency = <8000000>;

    // spi3_sck_pb3
    // spi3_miso_pb4
    // spi3_mosi_pb5
    pinctrl-0 = <&spi3_sck_pb3 &spi3_miso_pb4 &spi3_mosi_pb5>;
    pinctrl-names = "default";
    cs-gpios = <&gpiob 0 GPIO_ACTIVE_LOW>;

    sdhc0: sdhc@0 {
        compatible = "zephyr,sdhc-spi-slot";
        reg = <0>;
        status = "okay";
        mmc {
            compatible = "zephyr,sdmmc-disk";
            disk-name = "SD";
            status = "okay";
        };
        spi-max-frequency = <8000000>;
    };
};

&timers1 {
    status = "disabled";
    pwm1: pwm {
        status = "disabled";

        // tim1_ch1_pa8, tim1_ch1n_pa7, tim1_ch1n_pa11
        // tim1_ch2_pa9, tim1_ch2n_pa12, tim1_ch2n_pb0
        // tim1_ch3_pa10, tim1_ch3n_pf0
        // tim1_ch4_pa11,
        pinctrl-0 = <&tim1_ch1_pa8 &tim1_ch4_pa11>;
        pinctrl-names = "default";
    };
};

&timers2 {
    status = "disabled";
    pwm2: pwm {
        status = "disabled";

        // tim2_ch1_pa0, tim2_ch2_pa1, tim2_ch3_pa2, tim2_ch4_pa3
        // tim2_ch1_pa5, tim2_ch3_pa9, tim2_ch4_pa10, tim2_ch1_pa15
        // tim2_ch2_pb3
        pinctrl-0 = <&tim2_ch1_pa0>;
        pinctrl-names = "default";
    };
};

&timers3 {
    status = "disabled";
    pwm3: pwm {
        status = "disabled";

        // tim3_ch2_pa4, tim3_ch1_pa6, tim3_ch2_pa7, tim3_ch3_pb0
        // tim3_ch1_pb4, tim3_ch2_pb5, tim3_ch4_pb7
        pinctrl-0 = <&tim3_ch2_pa4>;
        pinctrl-names = "default";
    };
};

&timers4 {
    status = "disabled";
    pwm4: pwm {
        status = "disabled";

        // tim4_ch1_pa11, tim4_ch2_pa12, tim4_ch3_pa13, tim4_ch1_pb6
        // tim4_ch2_pb7, tim4_ch3_pb8
        pinctrl-0 = <&tim4_ch2_pa12>;
        pinctrl-names = "default";
    };
};

&timers8 {
    status = "disabled";
    pwm8: pwm {
        status = "disabled";

        // tim8_ch1n_pa7, tim8_ch2_pa14, tim8_ch1_pa15, tim8_ch2n_pb0
        // tim8_ch1n_pb3, tim8_ch2n_pb4, tim8_ch3n_pb5, tim8_ch1_pb6
        // tim8_ch2_pb8
        pinctrl-0 = <&tim8_ch2_pa14>;
        pinctrl-names = "default";
    };
};

&timers15 {
    status = "disabled";
    pwm15: pwm {
        status = "disabled";

        // tim15_ch1n_pa1, tim15_ch1_pa2, tim15_ch2_pa3
        pinctrl-0 = <&tim15_ch1n_pa1>;
        pinctrl-names = "default";
    };
};

&timers16 {
    status = "disabled";
    pwm16: pwm {
        status = "disabled";

        // tim16_ch1_pa6, tim16_ch1_pa12, tim16_ch1n_pa13, tim16_ch1_pb4
        // tim16_ch1n_pb6, tim16_ch1_pb8
        pinctrl-0 = <&tim16_ch1_pb8>;
        pinctrl-names = "default";
    };
};

&timers17 {
    status = "disabled";
    pwm17: pwm {
        status = "disabled";

        // tim17_ch1_pa7, tim17_ch1_pb5, tim17_ch1n_pb7
        pinctrl-0 = <&tim17_ch1_pa7>;
        pinctrl-names = "default";
    };
};
/*
&adc1 {
    status = "disabled";

    // adc1_in1_pa0, adc1_in2_pa1, adc1_in3_pa2
    // adc1_in4_pa3, adc1_in15_pb0, adc1_in10_pf0
    pinctrl-0 = <&adc1_in1_pa0>;
    #address-cells = <1>;
    #size-cells = <0>;
    st,adc-clock-source = "SYNC";
    st,adc-prescaler = <4>;
};

&adc2 {
    status = "disabled";

    // adc2_in1_pa0, adc2_in2_pa1, adc2_in17_pa4
    // adc2_in13_pa5, adc2_in3_pa6, adc2_in4_pa7
    // adc2_in10_pf1
//  pinctrl-0 = <&>;
};

&dac1 {
    status = "disabled";

    // dac1_out1_pa4, dac1_out2_pa5
//  pinctrl-0 = <&>;
};
*/

3. overlay を書く際に参照すべきファイル群

公式の手順通りに環境を構築した場合、ディレクトリ構成は以下の様になっています。

west update で取得した環境
$ ls -a
.  ..  .venv  .west  bootloader  modules  tools  zephyr

アプリ開発に於いては、その殆どは zephyr ディレクトリを参照することになるかと思いますが、
Devicetree に関しては zephyr と同じ階層にある modules ディレクトリを追いかける必要が出てきます。
これは、STM や NXP などの各ベンダーが提供している HAL 層やファイルシステム(fs)、暗号化やセキュアブートなどが含まれており、Zephyr とは別で管理されている外部モジュール群です。

overlay を記述する際、このMCUはどんなペリフェラルを持っていてどんな選択肢があるかを確認するために、ここで管理されている HAL を参照することになります。

4. 実際に参照されているファイルの確認方法

CMakeList.txt を追いかけるのが正攻法なのですが、v4.2.0 から追加された機能、build 時に 生成される zephyr.dts に参照した相対ファイルパスと行数がコメントとして付与される ようになっており、こちらを使ってショートカットします。

hello_world をビルドして modules を検索
west build -p -b nucleo_g431kb zephyr/samples/hello_world
grep modules build/zephyr/zephyr.dts
抽出結果
                        /* node '/soc/pin-controller@48000000/i2c2_scl_pa9' defined in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:299 */
                                pinmux = < 0x124 >; /* in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:300 */
                                bias-pull-up;       /* in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:301 */
                                drive-open-drain;   /* in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:302 */
                        /* node '/soc/pin-controller@48000000/i2c2_sda_pa8' defined in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:325 */
                                pinmux = < 0x104 >; /* in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:326 */
                                bias-pull-up;       /* in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:327 */
                                drive-open-drain;   /* in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:328 */
                        /* node '/soc/pin-controller@48000000/tim4_ch3_pb8' defined in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:862 */
                                pinmux = < 0x302 >; /* in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:863 */
                        /* node '/soc/pin-controller@48000000/lpuart1_rx_pa3' defined in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:993 */
                                pinmux = < 0x6c >; /* in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:994 */
                        /* node '/soc/pin-controller@48000000/lpuart1_tx_pa2' defined in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:1019 */
                                pinmux = < 0x4c >; /* in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:1020 */
                                bias-pull-up;      /* in modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi:1021 */

defined in 以降に書かれている通り modules/hal/stm32/dts/st/g4/stm32g431k(6-8-b)tx-pinctrl.dtsi ファイルを参照していることがわかります。

5. 利用できるペリフェラルの名称とピンの確認

例えば nucleo_g431kb の I2C1 は以下のように記述していました。

nucleo_g431kb.overlay の i2c1 設定と候補
&i2c1 {
    status = "okay";
    clock-frequency = <I2C_BITRATE_STANDARD>;
    
    // i2c1_scl_pa13, i2c1_scl_pa15, i2c1_scl_pb8
    // i2c1_sda_pa14, i2c1_sda_pb7
    pinctrl-0 = < &i2c1_scl_pa15 &i2c1_sda_pb7 >;
    pinctrl-names = "default";
};

ここで pinctrl-0 に利用できる名称は共通して i2c1_ が付いていることから、これをファイルから検索すればこのMCUで利用できるピンが見つかります。

'i2c1_' で抽出
grep -r i2c1_ modules/hal/stm32/dts/st/g4/stm32g431k\(6-8-b\)tx-pinctrl.dtsi
i2c1_ が付いた行の抽出結果
                        /omit-if-no-ref/ i2c1_scl_pa13: i2c1_scl_pa13 {
                        /omit-if-no-ref/ i2c1_scl_pa15: i2c1_scl_pa15 {
                        /omit-if-no-ref/ i2c1_scl_pb8: i2c1_scl_pb8 {
                        /omit-if-no-ref/ i2c1_sda_pa14: i2c1_sda_pa14 {
                        /omit-if-no-ref/ i2c1_sda_pb7: i2c1_sda_pb7 {
                        /omit-if-no-ref/ i2c1_smba_pb5: i2c1_smba_pb5 {

同様に spi1 で利用できる名称を探したい場合は以下のように探せます。

'spi1_' で抽出
grep -r spi1_ modules/hal/stm32/dts/st/g4/stm32g431k\(6-8-b\)tx-pinctrl.dtsi 
spi1_ が付いた行の抽出結果
                        /omit-if-no-ref/ spi1_miso_pa6: spi1_miso_pa6 {
                        /omit-if-no-ref/ spi1_miso_pb4: spi1_miso_pb4 {
                        /omit-if-no-ref/ spi1_mosi_pa7: spi1_mosi_pa7 {
                        /omit-if-no-ref/ spi1_mosi_pb5: spi1_mosi_pb5 {
                        /omit-if-no-ref/ spi1_nss_pa4: spi1_nss_pa4 {
                        /omit-if-no-ref/ spi1_nss_pa15: spi1_nss_pa15 {
                        /omit-if-no-ref/ spi1_sck_pa5: spi1_sck_pa5 {
                        /omit-if-no-ref/ spi1_sck_pb3: spi1_sck_pb3 {

あとは、過去の下記記事と組み合わせれば、Devicetree を組み立てるために必要な情報が一通り揃うはずです。

あとがき

直近の解説系の記事は Devicetree ばかりになってしまいましたが、ここまで書いている記事もあんまりなさそうですし、走りきった感はあります。

ですがいまだに Devicetree 周りは苦手意識が強く、何度もトライアルアンドエラーで解消させているのが現状です。

その背景として、Devicetree は、STM や NXP などベンダーそれぞれの設計思想や文化に強く引っ張られたデータ構造や階層になっているからだと思っています。

各ベンダーの異なる文化を柔軟に表現できる Devicetree の凄さとも言えますが、「データを編集するために設計思想を理解する」をある程度求められるため、「mbed の程良さ」を身にしみている今日この頃です。

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?