More functions

Some other functions need to be implemented so that the driver can be fully (color mode) and efficiently driven.

Set led color

int dm163_set_color(const struct device *dev, uint32_t led, uint8_t num_colors,
                    const uint8_t *color);

This function sets a led color. color contains the red, green, and blue component, in order. If some are missing, you can assume them to be 0. Don't forget to send the new channels value to the chip after doing so. As always, an incorrect led number or too great the number of colors will return -EINVAL instead of 0.

This corresponds to the set_color entry in the struct led_driver_api definition.

Set channels in bulk

int dm163_write_channels(const struct device *dev, uint32_t start_channel,
                         uint32_t num_channels, const uint8_t *buf);

Write channels in bulk. Make sure you check the bounds. This corresponds to the write_channels entry in the struct led_driver_api definition.

Using the functions

You can now use the shell led set_color dm163 4 0 0 255 to display a beautiful blue led. Of course, it might be easier to stop the animation first to see it, and activate only one line.

Driving the whole matrix

Create a new image structure made of 8×3×8 channels representing the whole led matrix. Make a thread which waits on a semaphore and display the next line using led_write_channels() when the semaphore is signaled. Make a timer signal the semaphore approximately every 1÷(8×60) second. Enjoy your beautiful image.

Prevent race conditions

There is a risk that some thread changes the brightness (and sends the brightness information to the DM163) while another thread is changing a channel color value (and sends this information to the DM163): both threads will try to talk to the DM163 at the same time.

Add a mutex to the dm163_data structure, and take the mutex before flushing the colors or the brightness to the DM163.

To go further

Add a function with the following prototype in dm163_module/zephyr/dm163.h:

void dm163_turn_off_row(const struct device *dev, const struct gpio_dt_spec *row);

(with the missing includes, and protection against multiple inclusion)

This function will remember the given row in the dm163_data structure. The next time flush_channels() is sending data to the DM163, as soon as data for the first six leds have been sent, the given row GPIO will be turned off. Then data for the remaining two leds will be sent and row will be forgotten by storing NULL instead.

By using this function, you might be able to turn a row off soon enough so that it has time to turn off completely before new data is latched, and late enough to keep a maximum of brightness. For example, this code

  gpio_pin_set_dt(&rows[row], 0);     // Turn row "row" off
  led_write_channels(&dm163_dev, …);  // Send data for row "row+1"
  gpio_pin_set_dt(&rows[row+1], 1);   // Turn row "row+1" on

would be replaced by

  dm163_turn_off_row(&dm163_dev, &rows[row]); // Remember the row to turn off
  led_write_channels(&dm163_dev, …);          // Send data for row "row+1". As a side
                                              // effect, row "row" will be turned off
                                              // when 6/8th of the data has been sent.
  gpio_pin_set_dt(&rows[row+1], 1);

and give a better visual effect.