Device Drivers and Device Model
The Zephyr kernel supports a variety of device drivers. The specific set of
device drivers available for an application's board configuration varies
according to the associated hardware components and device driver software.
The Zephyr device model provides a consistent device model for configuring the
drivers that are part of a system. The device model is responsible
for initializing all the drivers configured into the system.
Each type of driver (UART, SPI, I2C) is supported by a generic type API.
In this model the driver fills in the pointer to the structure containing the
function pointers to its API functions during driver initialization. These
structures are placed into the RAM section in initialization level order.
Device drivers which are present on all supported board configurations
are listed below.
* **Interrupt controller**: This device driver is used by the kernel's
interrupt management subsystem.
* **Timer**: This device driver is used by the kernel's system clock and
hardware clock subsystem.
* **Serial communication**: This device driver is used by the kernel's
system console subsystem.
* **Random number generator**: This device driver provides a source of random
Certain implementations of this device driver do not generate sequences of
values that are truly random.
Zephyr provides a set of device drivers for multiple platforms. Each driver
should support an interrupt-based implementation, rather than polling, unless
the specific hardware does not provide any interrupt.
High-level calls accessed through devices's specific API, such as i2c.h
or spi.h, are usually intended as synchronous. Thus, these calls should be
Due to the fact that Zephyr provides two types of execution contexts (task
and fiber) on a microkernel, drivers need to act accordingly. For example, a
nanokernel semaphore cannot be used when the context is a task, so the
:file:`include/device.h` exposes a helper API to handle this case transparently;
no other means ought to be used instead.
Zephyr API exposes 1 type and 3 inline functions to solve this issue.
This type provides a nanokernel semaphore, always present in both nanokernel
and microkernel use cases. It is meant to be used within a fiber context.
Then, and only on a microkernel type, it will provide a kernel semaphore
meant to be used within a task context. A boolean marker is used to remember
the caller's context when running a microkernel.
This function initializes the ``device_sync_call_t`` type semaphores and the
marker. This function should be used only once in the device driver's instance
lifetime. Thus, the driver's initialization function is the best place for
This function will block - that is, it will perform a "take wait" - on the
relevant semaphore. The exposed driver's API function can then be used as a
blocking function until the relevant semaphore is released by a ``give``.
This is therefore used to start a synchronous call, and waits until being
signaled for synchronization.
This function releases the relevant semaphore and thus will unlock the blocking
function. Most frequently will it be called in the driver's ISR handler. It is
used to signal the completion of the synchronous call (error or success).
The following APIs for device drivers are provided by :file:`device.h`. The APIs
are intended for use in device drivers only and should not be used in
create device object and set it up for boot time initialization.
Create device object and set it up for boot time initialization.
This also takes a pointer to driver API struct for link time
Expands to the full name of a global device object.
Obtain a pointer to a device object by name.
Declare a device object.