Driving the lines
We want to add the information about the 8 lines to the device tree. Let's invent a new node type to do this, we'll call it "rgb_matrix".
Add a dts/bindings/rgb_matrix.yaml
file:
description: RGB matrix
compatible: "rgb_matrix"
properties:
rows-gpios:
type: phandle-array
required: true
Any node identified as compatible with "rgb_matrix" in the device tree will need to have a row-gpios
property in which we will store the lines information.
Let's add such a node in our board overlay boards/disco_l475_iot1.overlay
which now becomes:
/ {
dm163: dm163 {
compatible = "siti,dm163";
selbk-gpios = <&gpioc 5 0>;
lat-gpios = <&gpioc 4 GPIO_ACTIVE_LOW>;
rst-gpios = <&gpioc 3 GPIO_ACTIVE_LOW>;
gck-gpios = <&gpiob 1 0>;
sin-gpios = <&gpioa 4 0>;
};
rgb_matrix: rgb_matrix {
compatible = "rgb_matrix";
rows-gpios = <&gpiob 2 0>, <&gpioa 15 0>, <&gpioa 2 0>, <&gpioa 7 0>,
<&gpioa 6 0>, <&gpioa 5 0>, <&gpiob 0 0>, <&gpioa 3 0>;
};
};
Using GPIO_DT_SPEC_GET_BY_IDX
, we can retrieve one item from the phandle-array by its index. Here is the new content of main.c
:
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/led.h>
#include <zephyr/kernel.h>
#define DM163_NODE DT_NODELABEL(dm163)
static const struct device *dm163_dev = DEVICE_DT_GET(DM163_NODE);
#define RGB_MATRIX_NODE DT_NODELABEL(rgb_matrix)
BUILD_ASSERT(DT_PROP_LEN(RGB_MATRIX_NODE, rows_gpios) == 8);
static const struct gpio_dt_spec rows[] = {
GPIO_DT_SPEC_GET_BY_IDX(RGB_MATRIX_NODE, rows_gpios, 0),
GPIO_DT_SPEC_GET_BY_IDX(RGB_MATRIX_NODE, rows_gpios, 1),
GPIO_DT_SPEC_GET_BY_IDX(RGB_MATRIX_NODE, rows_gpios, 2),
GPIO_DT_SPEC_GET_BY_IDX(RGB_MATRIX_NODE, rows_gpios, 3),
GPIO_DT_SPEC_GET_BY_IDX(RGB_MATRIX_NODE, rows_gpios, 4),
GPIO_DT_SPEC_GET_BY_IDX(RGB_MATRIX_NODE, rows_gpios, 5),
GPIO_DT_SPEC_GET_BY_IDX(RGB_MATRIX_NODE, rows_gpios, 6),
GPIO_DT_SPEC_GET_BY_IDX(RGB_MATRIX_NODE, rows_gpios, 7),
};
int main() {
if (!device_is_ready(dm163_dev)) {
return -ENODEV;
}
for (int row = 0; row < 8; row++)
gpio_pin_configure_dt(&rows[row], GPIO_OUTPUT_INACTIVE);
// Set brightness to 5% for all leds so that we don't become blind
for (int i = 0; i < 8; i++)
led_set_brightness(dm163_dev, i, 5);
// Animate the leds on every row and every column
for (;;) {
for (int row = 0; row < 8; row++) {
gpio_pin_set_dt(&rows[row], 1);
for (int col = 0; col < 8; col++) {
led_on(dm163_dev, col);
k_sleep(K_MSEC(30));
led_off(dm163_dev, col);
}
gpio_pin_set_dt(&rows[row], 0);
}
}
}
Nice, isn't it? Notice the BUILD_ASSERT()
macro which checks at compile time that the rows-gpios
property contains exactly eight items.
Why have we created a new node type instead of adding a property to the "siti,dm163" node? Because this has nothing to do with the DM163 which can perfectly be used to drive a single line of led.