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

Creative Commons
本作品采用知识共享署名

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

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

原来的overlay

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

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

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

1
2
3
# debug.conf
CONFIG_SHELL=y
CONFIG_DEBUG=y

1
2
3
4
5
6
7
debug.overlay
/ {
chosen {
zephyr,console = &uart2; /* 指定console使用uart1 */
zephyr,shell-uart = &uart2; /* 指定shell使用uart1*/
};
};

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

1
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
    如果全部开启就会变为
    1
    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下,提供了配置:

1
2
3
4
5
6
7
8
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

1
2
3
4
5
6
7
8
9
10
11
/ {
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这两个文件时只用执行

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

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

1
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

    1
    2
    # west构建时会从/path1和/path2去查找snippet,也可以指定一个或者更多的路径
    set(SNIPPET_ROOT "/path1;/path2")
  2. 在app下建立snippets文件夹,并放置snippet

    1
    2
    3
    4
    5
    6
    7
    8
    └── zephyr_sample
    ├── CMakeLists.txt
    ├── Kconfig
    ├── boards
    ├── prj.conf
    ├── snippets
    ├── src
    └── west.yml
  3. 在外部module的module.yml中添加snippet_root

    1
    2
    settings:
    snippet_root: .

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

演示

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

  1. 建立zephyr_sample的snippets文件夹

    1
    2
    └── zephyr_sample
    ├── snippets
  2. 建立remap-uart文件

    1
    2
    3
    4
    └── remap-uart
    ├── remap-uart.conf
    ├── remap-uart.overlay
    └── snippet.yml
  3. 在snippet.yml中对snippet进行描述

    1
    2
    3
    4
    5
    6
    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: 设备树文件
  4. EXTRA_CONF_FILE/EXTRA_DTC_OVERLAY_FILE文件内容

    1
    2
    3
    # remap-uart.conf
    # 启用kernel shell
    SHELL_KERNEL=y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* 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输出

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

指定board

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

1
2
3
4
5
6
7
8
9
10
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,例如

1
2
3
4
5
6
name: remap-uart
boards:
/esp32c3_*/:
append:
EXTRA_CONF_FILE: remap-uart.conf
EXTRA_DTC_OVERLAY_FILE: remap-uart.overlay

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

1
2
3
4
name: remap-uart
append:
EXTRA_CONF_FILE: remap-uart.conf
EXTRA_DTC_OVERLAY_FILE: remap-uart.overlay

多snippet

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

1
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.pyrequested_snippet_args转化为build\zephyr\snippets_generated.cmake
snippets_generated.cmake中设置EXTRA_CONF_FILEEXTRA_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如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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