Zephyr应用的代码结构--自定义驱动

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

本文说明如何将新增的驱动纳入到Zephyr应用的目录下进行管理。

本篇是<<Zephyr应用的代码结构>>系列的终篇和下面两篇文章一起可以构建出一个有app独立管理的zephyr项目
Zephyr个人项目的代码结构–West提货单: zephyr和zephyr外部项目纳入到应用代码目录管理
Zephyr应用的代码结构–自定义开发板: 将自定义board纳入到应用代码目录管理
除了上面两个场景外,我们的硬件可能也有新的驱动需求,而该驱动不被Zephyr支持,如果不想将驱动放入Zephyr中,就需要将驱动纳入到应用代码目录。

Zephyr驱动的添加可以分为3个级别:

  1. 有驱动API抽象,有设备树绑定: 只用添加驱动代码
  2. 有驱动API抽象,无设备树绑定:添加设备树绑定文件和驱动代码
  3. 无驱动API抽象,无设备树绑定: 添加抽象API头文件,添加设备树绑定文件,添加驱动代码

驱动代码目录

驱动代码目录添加

在app/目录下添加drivers目录,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
app
├── drivers
│   └── zephyr
│   ├── CMakeLists.txt
│   ├── Kconfig
│   └── sensor
│   ├── CMakeLists.txt
│   ├── Kconfig
│   └── rotary_encoder
├── CMakeLists.txt
├── Kconfig
├── rotary_encoder.c
└── rotary_encoder.h

在drivers/zephyr下的将要添加的驱动类型分类,例如我需要添加传感器类型的驱动,就增加一个sensor文件夹
zephyr/CMakeLists.txt中指定该文件夹, 如果有其它驱动类型的文件夹也加入到该文件中

1
add_subdirectory(sensor)

zephyr/Kconfig包含各个驱动类型文件夹的Kconfig

1
rsource "sensor/Kconfig"

zephyr/sensor/CMakeLists.txt中指定要使用的驱动文件夹,例如这里要指定选择编码器

1
add_subdirectory_ifdef(CONFIG_ROTARY_ENCODER rotary_encoder)

zephyr/sensor/Kconfig包含该类型下各个驱动的Kconfig

1
rsource "rotary_encoder/Kconfig"

zephyr/sensor/rotary_encoder/CMakeLists.txt指定驱动的源代码

1
2
3
zephyr_include_directories(.)
zephyr_library()
zephyr_library_sources(rotary_encoder.c)

zephyr/sensor/rotary_encoder/Kconfig则是该驱动代码rotary_encoder.c要使用的配置选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
menuconfig ROTARY_ENCODER
bool "Rotary Encoder Sensor"
depends on GPIO
help
Enable driver for Rotary encoder sensors.

if ROTARY_ENCODER

config ROTARY_ENCODER_THREAD_PRIORITY
int "Thread priority"
default 10
help
Priority of thread used by the driver to handle interrupts.

config ROTARY_ENCODER_THREAD_STACK_SIZE
int "Thread stack size"
default 1024
help
Stack size of thread used by the driver to handle interrupts.

驱动代码由rotary_encoder.c和rotary_encoder.h组成,不是本文说明重点,如何实现驱动可以参考Zephyr驱动模型实现方式

指定使用驱动目录

Zephyr建议将外部目录的驱动作为module添加,在app/CMakeLists.txt中添加下面内容,构建时就会编译app/drivers

1
2
3
list(APPEND ZEPHYR_EXTRA_MODULES
${CMAKE_CURRENT_SOURCE_DIR}/drivers
)

设备树绑定文件目录

为了硬件上的灵活性,Zephyr引入了设备树,通过设备树绑定的方式将设备树转换为C宏来使用。Zephyr的设备树绑定文件可能不包含我们要用的硬件设备,这就需要我们自己添加。同样设备树绑定文件也可以纳入app的目录进行管理,在app目录下添加dts目录,里面放置设备树绑定文件

1
2
3
4
5
app
├── dts
│   └── bindings
│   └── sensor
│   └── rotary-encoder.yaml

rotary-encoder.yaml的编写和使用方法不是本文重点,详细可以参考Zephyr添加旋转编码器驱动
在app/CMakeLists.txt中添加下面内容,构建时编译设备树会查找到app/dts目录

1
list(APPEND DTS_ROOT ${CMAKE_SOURCE_DIR})

设备驱动API头文件目录

对于个人项目开发来说,设备驱动API一般是项目内使用,API抽象的普遍覆盖性并不一定要非常全,此外使用的人员也不需要大范围讨论,根据需求进行自定义就可以, 所形成的头文件放到对应的驱动目录即可,例如zephyr/sensor/rotary_encoder/rotary_encoder.h, 为了方便应用直接使用,可以在app/CMakeLists中添加

1
include_directories(drivers/zephyr/sensor/rotary_encoder/)

之后应用代码中就可以直接”#include “rotary_encoder.h”

结束语

到此为止我们通过三篇文章可以将Zephyr代码, Zephyr外部项目,自定义board, 驱动都纳入到一个app的仓库进行管理,通过一个独立的app仓库可以驱动编译所必须的代码,既方便管理,又十分精简。
如果你使用的SOC都还未被Zephyr支持,也可以将soc的移植纳入到应用目录下进行管理,这部分目前我并没有使用过无法做实例解释可以参考https://docs.zephyrproject.org/latest/application/index.html#soc-definitions进行操作。

参考

https://github.com/zephyrproject-rtos/zephyr/tree/main/samples/application_development/out_of_tree_driver
https://docs.zephyrproject.org/latest/samples/application_development/out_of_tree_driver/README.html