You are currently not logged in and your progress will not be saved. Register or Log in

Device driver model

In order to interact with a hardware peripheral or a system block, we need to use a device driver (or driver for short), which is software that deals with the low-level details of configuring the hardware the way we want. In nRF Connect SDK, the driver implementation is highly decoupled from its API. This basically means we are able to switch out the low-level driver implementation without modifying the application, because we can use the same generic API.

This decoupling has many benefits including a high level of portability as it makes it possible to use the same code on different boards without having to worry about manually modifying the underlying driver implementation.

Most of the time, the application code interacts with the hardware through a generic API, which is defined by the Zephyr RTOS. A binding between the generic API and the actual device driver implementation must be set through a device data structure as shown in the figure below. In the application, this device data structure is then obtained using the function device_get_binding(). The Zephyr device model is responsible for the association between generic APIs and device driver implementations.

Zephyr device model

The function device_get_binding() has the signature shown below: 

The name of the peripheral to look up its driver implementation must be passed as a string (const char *). The function will look up all the configured drivers and returns a pointer to the device driver implementation if there is a match. Otherwise, the function will return NULL.

The device name (left) maps to the label property of the node in the device tree (right).

device_get_binding("device_name")
a-node {
    subnode_label: a-sub-node {
        label = "device_name";
    };
};

For instance, the following device_get_binding() call will look up if there is a registered device driver implementation with the name GPIO_0. If yes, the dev pointer will provide us access to it. Otherwise, dev is set to NULL.

    dev = device_get_binding(“GPIO_0”);
    if (dev == NULL) {
        return;
    }

To use a device driver generic API, you must have a pointer of type const struct device to point to its implementation. You need to do this per peripheral instance. For example, if you have two UART peripherals (UART_0 and UART_1) and you want to use them both, you must have two separate pointers of type const struct device. In other words, you need to have two different calls to device_get_binding().

Note

Remember that any hardware (peripheral, or system block) is eventually accessed as a pointer of type const struct device.