Building a Zephyr Out of Tree Sensor Driver
Table of Contents
At Team Spatzenhirn, the Carolo-Cup (1:10 scale autonomous driving competition) team at Ulm University, we use Zephyr for the software on our interface board. Recently, we had the need to connect an PMW3389 sensor to the board, for which we didn’t find any already existing Zephyr drivers. This is not the first Zephyr driver we built, but the previous drivers have all been built in-tree, inside our fork of Zephyr. While it would be cool to upstream those eventually, the main goal would be to make the drivers easily usable by other Zephyr users, even if the driver is not included in Zephyr by default.
This post intends to give an overview of the layout of an out-of-tree sensor driver for zephyr, following our PMW3389 driver as an example:
West⌗
Zephyr makes use of the west tool to load external components, we even use west to download zephyr itself in our
application workspace.
To make the driver usable as a west module, a file
zephyr/module.yml
is
required in the repository.
It defines how the module is built, where to find additional Kconfig files and devicetree sources:
build:
cmake: .
kconfig: Kconfig
settings:
dts_root: .
Now, an application wishing to use the driver can add the following to its own west manifest. Our manifest looks something like this (the parts downloading zephyr itself omitted):
manifest:
remotes:
- name: teamspatzenhirn
url-base: https://github.com/teamspatzenhirn
projects:
- name: pmw3389_zephyr_driver
remote: teamspatzenhirn
revision: zephyr
path: modules/pmw3389
self:
path: manifest
DTS⌗
As with an in-tree driver, the DTS binding is defined at dts/bindings/sensor/vendor,device.yaml
, in our case that
would be
dts/bindings/sensor/pixart,pmw3389.yaml
.
Here is the DTS binding for our sensor, which is just the same as every other sensor DTS binding:
description: |
Motion Sensor
compatible: "pixart,pmw3389"
include: spi-device.yaml
properties:
resolution:
type: int
required: true
description: |
Resolution in counts per inch, multiples of 50, from 50 to 16000
Note that the vendor must be in the list of known vendor prefixes, so if the vendor is not known yet in upstream
zephyr, you can just provide dts/bindings/vendor-prefixes.txt
, which will be merged with the upstream file at build
time:
pixart PixArt Imaging Inc.
(Note that the separator between the vendor prefix and the description is a tab…)
Kconfig⌗
The main Kconfig
file just includes the sensor-specific Kconfig file next to the sources:
rsource "drivers/sensor/pmw3389/Kconfig"
Driver Sources⌗
The driver sources at drivers/sensor/pmw3389/
are just the same as any other in-tree driver.
Take a look at
our driver sources
or any other sensor driver as an example.
Headers⌗
As far as I can tell, the in-tree drivers don’t handle the headers in a special way, since the driver directory
is in the include path anyway.
For many drivers, the header is not needed by the application anyway, since the application just uses the generic sensor
API.
We did however need a header to make custom sensor channels and an additional raw-data readout function available,
see the header
at include/pmw3389.h
.
CMake⌗
The only addition we had to make to the usual add_subdirectory_ifdef(CONFIG_PMW3389 drivers/sensor/pmw3389)
was to
make the header mentioned above available.
See the full CMake file at
CMakeLists.txt
.
References⌗
These blog posts and samples have been helpful in figuring this out: