Now that we have examined the devicetree, device driver model, and the GPIO generic API, let’s dissect the blinky sample program to understand how it works.
In the following paragraphs, we will examine the blinky sample line by line to understand how this program is working. The blinky sample comes with the nRF Connect SDK and can be downloaded below:

1. Include modules
The blinky sample uses the following modules in the nRF Connect SDK:
- Kernel services
<zephyr.h>for the sleep functionk_msleep(). - Device Driver Model
<device.h>for the functiondevice_get_binding()and the device structure. - Devicetree
<devicetree.h>for the macrosDT_ALIAS(),DT_NODE_HAS_STATUS(),DT_GPIO_LABEL(),DT_GPIO_PIN(),DT_GPIO_FLAGS(). - The generic GPIO interface
<drivers/gpio.h>for the functionsgpio_pin_configure()andgpio_pin_set().
The header files of these modules are included in main.c through the following include lines.
#include <zephyr.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>2. Define the node identifier
The line below uses the devicetree macro DT_ALIAS() to get the node identifier symbol LED0_NODE, which will represent LED1 (node led_0). Remember from the Devicetree section that led_0 node is defined in the devicetree of the DK. LED0_NODE is now the source code symbol that represents the hardware for LED1.
The DT_ALIAS() macro gets the node identifier from the node’s alias, which as we saw in the Devicetree section, is led0.
#define LED0_NODE DT_ALIAS(led0) // LED0_NODE = led0 defined in the .dts file3. Extract information from the node identifier
The symbol LED0_NODE contains information about the GPIO port, PIN, flags, and a label embedded inside its gpios property. The macro calls below extract this information from the LED0_NODE. Note the second parameter for these macros gpios. This is the name of the property containing all this information.
//get the port - in the case of the nRF52833 DK, LED0 = "GPIO_0"
#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios)
//get the pin - in the case of the nRF52833 DK, PIN = 13
#define PIN DT_GPIO_PIN(LED0_NODE, gpios)
//get the flags - in the case of the nRF52833 DK, FLAGS = GPIO_ACTIVE_LOW
#define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios) 4. Catch statement for error handling
The following lines will only be executed if the devicetree file of the selected board does not contain an alias node named led0, which is not the case for the nRF52833 DK or any other Nordic Semiconductor official development kit, so they are simply skipped.
#error "Unsupported board: led0 devicetree alias is not defined"
#define LED0 ""
#define PIN 0
#define FLAGS 0Now let’s examine main().
5. Define a pointer to the device structure
As we mentioned before, for each hardware instance (i.e peripheral or system block) you plan to access in your application, you need to have a device driver associated with it. In the blinky example, we only have one peripheral to interact with, which is the GPIO peripheral. Therefore, we need to declare one pointer of type const struct device to point to its driver implementation as shown below:
const struct device *dev;6. Extract the device driver implementation
We will use the function device_get_binding() to get the device driver implementation associated with the GPIO peripheral on the board.
dev = device_get_binding(LED0);
if (dev == NULL) {
return;
}The device_get_binding() function expects a string as a parameter to look up the driver implementation associated with the hardware, as explained in the Device Driver Model section.
7. Configure the GPIO pin
The generic GPIO API function gpio_pin_configure() is used to configure GPIO pin 13 as an output (active low) and initializes it to a logic 1, as explained in the GPIO Generic API section.
ret = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS);
if (ret < 0) {
return;
}8. Continuously set GPIO pin value to variable led_is_on
Finally, the blinky main function will enter an infinite loop where we continuously set GPIO pin 13 to the value of the boolean variable led_is_on. Note that in every iteration, we are inverting this variable through the logical negation operator (!). We are also calling the kernel service function k_msleep(), which puts the main function to sleep for 1 second, resulting in the blinking behavior at 1-second intervals.
while (1) {
gpio_pin_set(dev, PIN, (int)led_is_on);
led_is_on = !led_is_on;
k_msleep(SLEEP_TIME_MS);
}