Zephyr Devicetree 详解 Devicetree 覆盖

Zephyr Devicetree 详解-生成过程和结果 一文中提到过 Devicetree 覆盖文件 ( .overlay ) ,并简单介绍了其作用是针对板级 dts,新增/修改/禁用一些和硬件相关的功能。本文将详细说明如何设置和使用 Devicetree 覆盖文件。

设置 Devicetree 覆盖 链接到标题

在 CMake 变量 DTC_OVERLAY_FILE 中包含覆盖文件列表,文件之间以空格或分号分隔。如果 DTC_OVERLAY_FILE 指定多个文件,它们会按照指定的顺序被 C 预处理器包含。设置 DTC_OVERLAY_FILE 变量时,可以通过转义 Zephyr 模块目录变量 ( 例如${ZEPHYR_<module>_MODULE_DIR}/<path-to>/dts.overlay ) 来引用 Zephyr 模块中的文件。在 west build 的时候通过设置 DTC_OVERLAY_FILE 准确的指定使用的覆盖文件。 当需要指定多个覆盖文件时,请将文件列表用引号括起来,并用分号分隔每个文件名。例如

west build -b reel_board -- -DDTC_OVERLAY_FILE=enable-modem.overlay
west build -b reel_board -- -DDTC_OVERLAY_FILE="file1.overlay;file2.overlay"

覆盖文件的使用 链接到标题

如果未设置 DTC_OVERLAY_FILE ,构建系统将按下面步骤在应用程序配置目录 ( 由 APPLICATION_CONFIG_DIR 指定,没有指定就是应用程序的目录 ) 中查找覆盖文件

  • 如果文件 socs/<SOC>.overlay 存在,则会使用该文件
  • 如果文件 boards/<BOARD>.overlay 存在,附加使用它
  • 如果当前板有[多个修订版]并且 boards/<BOARD>_<revision>.overlay 存在,除上述之外还会附近使用它
  • 如果在前面的步骤中找到一个或多个文件,构建系统将停止查找并仅使用这些文件
  • 否则,如果<BOARD>.overlay 存在,则使用它,并且构建系统将停止查找更多文件
  • 否则,如果 app.overlay 存在,则会使用它
  • DTC_OVERLAY_FILE 或构建系统自动使用上述步骤中描述的覆盖生效后,EXTRA_DTC_OVERLAY_FILE 再提供额外的覆盖。
  • 如果使用 Shields 还将添加 Shields 的 Devicetree 覆盖文件

以上覆盖文件的生效留存如下图: alt text

你可以根据上图和应用程序目录以及指定的 DTC_OVERLAY_FILEEXTRA_DTC_OVERLAY_FILE 来判断最终有那些。overlay 会加入到覆盖。 例如有一个应用目录 ~/zephyr_samlpe,与 Devicetree 相关的文件如下

  .
  ├── app.overlay
  ├── boards
  │   ├── esp32c3_zgp.overlay
  │   └── halfcoder
  │       ├── esp32c3_zgp
  │       │   ├── esp32c3_zgp.dts
  │       │   ├── esp32c3_zgp.overlay
  ├── cover.overlay
  ├── ext_cover.overlay
  ├── esp32c3_zgp.overlay
  ├── socs
  │   └── esp32c3.overlay
  • 执行 west build -b esp32c3_zgp ~/zephyr_sample
    • esp32c3_zgp.dts+socs/esp32c3.overlay+boards/esp32c3_zgp.overlay
  • 执行 west build -b esp32c3_zgp ~/zephyr_sample -- -DDTC_OVERLAY_FILE=cover.overlay
    • esp32c3_zgp.dts+cover.overlay
  • 执行 west build -b esp32c3_zgp ~/zephyr_sample -- -DEXTRA_DTC_OVERLAY_FILE=ext_cover.overlay
    • esp32c3_zgp.dts+socs/esp32c3.overlay+boards/esp32c3_zgp.overlay + ext_cover.overlay
  • 执行 west build -b esp32c3_zgp ~/zephyr_sample -- -DDTC_OVERLAY_FILE=cover.overlay -DEXTRA_DTC_OVERLAY_FILE=ext_cover.overlay
    • esp32c3_zgp.dts+cover.overlay+ext_cover.overlay

构建过程中会打印找到的覆盖文件,可以通过该打印信息判断使用的覆盖文件是否符合预期:

-- Found Dtc: /home/frank/work/zpro/tools/zephyr-sdk-0.16.8/sysroots/x86_64-pokysdk-linux/usr/bin/dtc ( found suitable version "1.6.0", minimum required is "1.4.6" )
-- Found BOARD.dts: /home/frank/work/zpro/book_sample/zephyr_sample/boards/halfcoder/esp32c3_zgp/esp32c3_zgp.dts
-- Found devicetree overlay: /home/frank/work/zpro/book_sample/zephyr_sample/socs/esp32c3.overlay
-- Found devicetree overlay: /home/frank/work/zpro/book_sample/zephyr_sample/boards/esp32c3_zgp.overlay
-- Found devicetree overlay: cover.overlay
-- Generated zephyr.dts: /home/frank/work/zpro/book_sample/build/zephyr/zephyr.dts

覆盖文件的优先级 链接到标题

覆盖文件优先级由覆盖的顺序决定:谁后覆盖谁优先级高,覆盖的顺序见前面流程图。 例如:

  • esp32c3_zgp.dts 原本设置 uart0 的波特率为 115200
  • cover.overlay 将 uart0 的波特率为 9600
  • ext_cover.overlay 将 uart0 的波特率为 38400

按照 esp32c3_zgp.dts+cover.overlay+ext_cover.overlay 从前到后的顺序,最后 uart0 的波特率应为 38400

使用 Devicetree 覆盖 链接到标题

覆盖可以通过多种方式覆盖节点属性值。例如,如果 BOARD.dts 包含节点:

/ {
    soc {
            serial0: serial@40002000 {
                    status = "okay";
                    current-speed = <115200>;
                    /* ... */
            };
    };
};

下面是覆盖 current-speed 值的等效方法:

/* 使用 lable */
&serial0 {
    current-speed = <9600>;
};

/* 使用节点全路径 */
&{/soc/serial@40002000} {
    current-speed = <9600>;
};

为了简洁,我们更常使用 lable。

在覆盖文件中可以添加,覆盖,删除属性和子节点,例如下面是一个 board.dts

/ {
    model = "esp32c3_zgp";
    compatible = "espressif,esp32c3";

    chosen {
        zephyr,sram = &sram0;
        zephyr,console = &uart0;
        zephyr,uart-mcumgr=&uart0;
    };

    buttons: buttons {
        compatible = "gpio-keys";
        button0: button_0 {
            gpios = <&gpio0 9 ( GPIO_PULL_UP | GPIO_ACTIVE_LOW )>;
            label = "User SW1";
            zephyr,code = <INPUT_KEY_0>;
        };
    };
}

&uart0 {
    status = "okay";
    current-speed = <115200>;
    pinctrl-0 = <&uart0_default>;
    pinctrl-names = "default";
};

&usb_serial {
    /* requires resoldering of resistors on the board */
    status = "okay";
};

&i2c0 {
    status = "okay";
    clock-frequency = <I2C_BITRATE_STANDARD>;
    pinctrl-0 = <&i2c0_default>;
    pinctrl-names = "default";
};

我用一个 cover.overlay 去覆盖,达到下面目的:

  • 添加一个别名,my-serial = &uart0;
  • 将 uart1 启用,并修改 console 使用 uart1
  • 修改 uart0 的默认波特率为 9600
  • 删除 zephyr,uart-mcumgr
  • 在 i2c0 下增加一个 bmg160 子节点

cover.overlay 的内容应该如下

/* 删除的内容也可以放到后面的/{chosen{}}内,但为了好辨认,通常会被集中到一起放在/{}下 */
/ {
    chosen {
        /*删除属性 zephyr,uart-mcumgr*/
        /delete-property/ zephyr,uart-mcumgr;
    };
};

/ {
    chosen {
            /* 修改属性 */
            zephyr,console = &uart1;

            /* /delete-property/ zephyr,uart-mcumgr; 也可以放到这里 */
    };

    aliases {
            /* 添加别名 */
            my-serial = &uart1;
    };
};

/* 启用 uart1 */
&uart1 {
    status = "okay";
};

/* 修改 uart0 的默认波特率 */
&uart0 {
    current-speed = <9600>;
};

/* 在 i2c0 下添加节点 bmg160 */
&i2c0 {
    bmg160@68 {
        compatible = "bosch,bmg160";
        reg = <0x68>;
        int-gpios = <&gpioc 6 0>;
    };
};

参考 链接到标题

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