Zephyr 片段(snippet)配置功能使用说明

本文介绍说明Zephyr片段功能和使用方法。

Zephyr v3.4.0 release中新增加了snippet功能,以此来简化原来对overlay配置文件和设备树的用法。

原来的overlay 链接到标题

Zephyr提供了对配置的文件和设备树的overlay,用于添加额外的配置选项,通常用于:

  • 灵活的开启调试和释放版本
  • 指定不同应用的配置选项 例如一般情况下编译应用zephyr_sample为释放版本:
west build -b esp32c3_zgp zephyr_sample/

它会引用zephyr_sample/prj.conf作为配置项,引用esp32c3_zgp的board下的设备树。 当我们想开启debug模式的时候,可以建立debug.conf和debug.overlay,开启debug mode并将串口重定位到uart2上

# debug.conf
CONFIG_SHELL=y
CONFIG_DEBUG=y
debug.overlay
/ {
	chosen {
        zephyr,console = &uart2;		/* 指定console使用uart1 */
		zephyr,shell-uart = &uart2;		/* 指定shell使用uart1*/
	};
};

再采用如下方式重新编译就可以编译出debug版本的image

west build -b esp32c3_zgp zephyr_sample/ -- -DDTC_OVERLAY_FILE="debug.overlay" -DOVERLAY_CONFIG="debug.conf"

这样做可以不用来回修改prj.conf和board下面设备,但当有多应用功能时就会略显麻烦,例如:

  • 使用wifi: wifi.conf, wifi.overlay
  • 使用eth: eth.conf, eth.overlay
  • 使用大尺寸flash: size.conf, size.overlay 如果全部开启就会变为
west build -b esp32c3_zgp zephyr_sample/ -- -DDTC_OVERLAY_FILE="wifi.overlay" -DDTC_OVERLAY_FILE="eth.overlay" -DDTC_OVERLAY_FILE="size.overlay" -DOVERLAY_CONFIG="wifi.conf" -DOVERLAY_CONFIG="eth.conf" -DOVERLAY_CONFIG="size.conf"

有两个问题(我是深有体会):

  1. 输入的命令太长
  2. 时间长了连命令都不记得了

snippet 链接到标题

zephyr v3.4.0引入了snippet可以简化overlay, 可以将snippet理解为替代overlay,一个snippet对应一组.conf和.overlay, 我们先看一组简单的使用方式:zephyr提供内置的cdc-acm-console snippet,放置在zephyr/snippets/cdc-acm-console下,提供了配置:

CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Zephyr USB console sample"
CONFIG_USB_DEVICE_PID=0x0004

CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_UART_LINE_CTRL=y

设备树的overlay

/ {
	chosen {
		zephyr,console = &snippet_cdc_acm_console_uart;
	};
};

&zephyr_udc0 {
	snippet_cdc_acm_console_uart: snippet_cdc_acm_console_uart {
		compatible = "zephyr,cdc-acm-uart";
	};
};

当要overlay这两个文件时只用执行

west build -b mm_swiftio -S cdc-acm-console ./zephyr_sample

是不是比下面要简洁一些:

west build -b mm_swiftio zephyr_sample/ -- -DDTC_OVERLAY_FILE="cdc-acm-console.overlay" -DOVERLAY_CONFIG="cdc-acm-console.conf"

如何使用 链接到标题

snippet放置位置 链接到标题

在zephyr/snippets下可以增加新的snippet, 但这样会污染zephyr的主目录,同时如果只是为我们自己开发的应用使用也不方便代码管理,有两种方式

  1. 在app的CMakeList.txt中指定SNIPPET_ROOT
# west构建时会从/path1和/path2去查找snippet,也可以指定一个或者更多的路径
set(SNIPPET_ROOT "/path1;/path2")
  1. 在app下建立snippets文件夹,并放置snippet
└── zephyr_sample
    ├── CMakeLists.txt
    ├── Kconfig
    ├── boards
    ├── prj.conf
    ├── snippets
    ├── src
    └── west.yml
  1. 在外部module的module.yml中添加snippet_root
settings:
  snippet_root: .

对于应用来说通常我们用第二种方法

演示 链接到标题

例如我们要为zephyr_sample建立一个remap-uart的snippet,当使用改snippet时调试串口会指向到uart1

  1. 建立zephyr_sample的snippets文件夹
└── zephyr_sample
    ├── snippets
  1. 建立remap-uart文件
└── remap-uart
    ├── remap-uart.conf
    ├── remap-uart.overlay
    └── snippet.yml
  1. 在snippet.yml中对snippet进行描述
name: remap-uart
boards:
  esp32c3_zgp:
    append:
      EXTRA_CONF_FILE: remap-uart.conf
      EXTRA_DTC_OVERLAY_FILE: remap-uart.overlay
- name: snippet的名字
- boards: 对esp32c3_zgp这种开发板生效
- EXTRA_CONF_FILE: 配置文件
- EXTRA_DTC_OVERLAY_FILE: 设备树文件
  1. EXTRA_CONF_FILE/EXTRA_DTC_OVERLAY_FILE文件内容
# remap-uart.conf
# 启用kernel shell
SHELL_KERNEL=y
/* remap-uart.overlay */
/ {
	chosen {
        zephyr,console = &uart1;		/* 指定console使用uart1 */
		zephyr,shell-uart = &uart1;		/* 指定shell使用uart1*/
	};
};

/* 指定UART的pinctrl */
&pinctrl {
	uart1_default: uart1_default {
		group1 {
			pinmux = <UART1_TX_GPIO4>;
            output-high;
		};
		group2 {
			pinmux = <UART1_RX_GPIO5>;
		};
	};
};

/* UART1的配置 */
&uart1 {
	status = "okay";
	current-speed = <115200>;
	pinctrl-0 = <&uart1_default>;
	pinctrl-names = "default";
};

5 使用 构建时加上-S remap-uart后console和shell都通过uart输出

west build -b esp32c2_zgp -S remap-uart ./zephyr_sampe

指定board 链接到标题

前面示例看到可以通过boards指定不同的board生效的不同的snippet,例如

name: remap-uart
boards:
  esp32c3_zgp:
    append:
      EXTRA_CONF_FILE: remap-uart.conf
      EXTRA_DTC_OVERLAY_FILE: remap-uart.overlay
  esp32c3_devkit:
    append:
      EXTRA_CONF_FILE: remap-uart-kit.conf
      EXTRA_DTC_OVERLAY_FILE: remap-uart-kit.overlay

也可以使用正则表达式指定同类的board生效相同的snippet,例如

name: remap-uart
boards:
  /esp32c3_*/:
    append:
      EXTRA_CONF_FILE: remap-uart.conf
      EXTRA_DTC_OVERLAY_FILE: remap-uart.overlay

还可以不指定board,对所有board都生效相同的snippet,例如

name: remap-uart
    append:
      EXTRA_CONF_FILE: remap-uart.conf
      EXTRA_DTC_OVERLAY_FILE: remap-uart.overlay

多snippet 链接到标题

当我们制作了多个snippet,例如最前面的有wifi,eth,debug,那么构建的时候就使用

west build -b mm_swiftio -S wifi -S eth -s debug ./zephyr_sampe

实现分析指引 链接到标题

zephyr/scripts/west_commands/build.py 收集-S参数加入到-DSNIPPET中 zephyr/cmake/modules/zephyr_default.cmake 使用list(APPEND zephyr_cmake_modules snippets) 加载zephyr\cmake\modules\snippets.cmake执行zephyr_process_snippets zephyr_process_snippets查找SNIPPET_ROOT并根据-DSNIPPET生成requested_snippet_args zephyr_process_snippets调用zephyr/scripts/snippets.py将requested_snippet_args转化为build\zephyr\snippets_generated.cmake snippets_generated.cmake中设置EXTRA_CONF_FILE和EXTRA_DTC_OVERLAY_FILE zephyr/cmake/modules/kconfig.cmake引用EXTRA_CONF_FILE zephyr/cmake/modules/dts.cmake引用EXTRA_DTC_OVERLAY_FILE

例如remap-uart例子中生成的snippets_generated.cmake如下

set(SNIPPET_NAMES "cdc-acm-console" "remap-uart")
# The paths to all the snippet.yml files. One snippet
# can have multiple snippet.yml files.
set(SNIPPET_PATHS "/mnt/e/book/sample/zephyr/snippets/cdc-acm-console/snippet.yml" "/mnt/e/book/sample/zephyr_sample/snippets/remap-uart/snippet.yml")

# Create variable scope for snippets build variables
zephyr_create_scope(snippets)

###############################################################################
# Snippet 'remap-uart'

# Common variable appends.
# Appends for board 'esp32c3_zgp'
if("${BOARD}" STREQUAL "esp32c3_zgp")
  zephyr_set(EXTRA_CONF_FILE "/mnt/e/book/sample/zephyr_sample/snippets/remap-uart/remap-uart.conf" SCOPE snippets APPEND)
  zephyr_set(EXTRA_DTC_OVERLAY_FILE "/mnt/e/book/sample/zephyr_sample/snippets/remap-uart/remap-uart.overlay" SCOPE snippets APPEND)
endif()

参考 链接到标题

https://docs.zephyrproject.org/latest/build/snippets/index.html