samples: drivers: led_strip: Unify led_apa102 and led_lpd8806 samples

Unify `led_apa102` and `led_lpd8806` samples into `led_strip`
and remove these.

Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
This commit is contained in:
TOKITA Hiroshi 2024-03-09 21:50:39 +09:00 committed by David Leach
parent 0929a8db37
commit ba9f49d7a0
27 changed files with 89 additions and 474 deletions

View file

@ -48,6 +48,7 @@
sw0 = &button0;
watchdog0 = &wdt0;
spi-flash0 = &gd25q16;
led-strip = &apa102;
};
};

View file

@ -123,7 +123,7 @@ The :zephyr:code-sample:`button` sample lets you test the buttons (switches) and
The :zephyr:code-sample:`blinky` sample lets you test the red LED.
The DotStar LED has been implemented as a SPI device and can be tested
with the :zephyr:code-sample:`led-apa102` sample application.
with the :zephyr:code-sample:`led-strip` sample application.
You can build and flash the examples to make sure Zephyr is running correctly on
your board. The button and LED definitions can be found in

View file

@ -25,6 +25,7 @@
aliases {
led0 = &led0;
pwm-led0 = &pwm_led0;
led-strip = &led1;
};
leds {

View file

@ -45,6 +45,7 @@
pwm-buzzer = &pwm0;
watchdog0 = &wdt0;
accel0 = &bmi270;
led-strip = &apa102;
};
};
@ -102,7 +103,7 @@
pinctrl-0 = <&spi1_default>;
pinctrl-1 = <&spi1_sleep>;
pinctrl-names = "default", "sleep";
apa102@0 {
apa102: apa102@0 {
compatible = "apa,apa102";
reg = <0>;
spi-max-frequency = <5250000>;

View file

@ -122,7 +122,7 @@ Flashing
Flashing Zephyr onto the ``blueclover_plt_demo_v2/nrf52832`` board requires
an external programmer. The programmer is attached to the SWD header.
Build the Zephyr kernel and the :zephyr:code-sample:`led-apa102` sample application.
Build the Zephyr kernel and the :zephyr:code-sample:`led-strip` sample application.
.. zephyr-app-commands::
:zephyr-app: samples/drivers/led_apa102

View file

@ -1,9 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(led_apa102)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})

View file

@ -1,90 +0,0 @@
.. zephyr:code-sample:: led-apa102
:name: APA102 LED strip
:relevant-api: led_strip_interface
Control an LED strip using an APA102, Adafruit DotStar, or compatible driver chip.
Overview
********
This sample application demonstrates basic usage of the APA102 LED
strip driver, for controlling LED strips using APA102, Adafruit DotStar,
and compatible driver chips.
Requirements
************
.. _Dotstar product from AdaFruit: https://www.adafruit.com/category/885
.. _74AHCT125: https://cdn-shop.adafruit.com/datasheets/74AHC125.pdf
- LED strip using APA102 or compatible, such as the any `Dotstar product
from AdaFruit`_.
- Zephyr board with SPI master driver. SPI communications must use 5V
signaling, which may require a level translator, such as the
`74AHCT125`_.
- 5V power supply.
Wiring
******
#. Ensure your Zephyr board, the 5V power supply, and the LED strip
share a common ground.
#. Connect the MOSI pin of your board's SPI master to the data input
pin of the first APA102 IC in the strip.
#. Connect the SCLK pin of your board's SPI master to the clock input
pin of the first APA102 IC in the strip.
#. Connect the 5V power supply pin to the 5V input of the LED strip.
Building and Running
********************
The sample application is located at ``samples/drivers/led_apa102/``
in the Zephyr source tree.
Configure For Your Board
========================
Now check if your board is already supported, by looking for a file
named ``boards/YOUR_BOARD_NAME.conf`` in the application directory.
If your board isn't supported yet, you'll need to configure the
application as follows.
#. Configure your board's SPI master in a configuration file under
``boards/`` in the sample directory.
To provide additional configuration for some particular board,
create a ``boards/YOUR_BOARD_NAME.conf`` file in the application
directory. It will be merged into the application configuration.
In this file, you must ensure that the SPI peripheral you want to
use for this demo is enabled. See ``boards/nucleo_l432kc.conf`` for
an example.
#. Configure your board's dts overlay. See ``nucleo_l432kc.overlay``
for an example.
#. Set the number of LEDs in your strip in the application sources.
This is determined by the macro ``STRIP_NUM_LEDS`` in the file
``src/main.c``.
Then build and flash the application:
.. zephyr-app-commands::
:zephyr-app: samples/drivers/led_apa102
:board: <board>
:goals: flash
:compact:
Refer to your :ref:`board's documentation <boards>` for alternative
flash instructions if your board doesn't support the ``flash`` target.
When you connect to your board's serial console, you should see the
following output:
.. code-block:: none
***** BOOTING ZEPHYR OS zephyr-v1.13.XX *****
[general] [INF] main: Found LED strip device APA102

View file

@ -1,5 +0,0 @@
# This file expresses generic requirements ONLY; see README.rst.
CONFIG_LOG=y
CONFIG_LED_STRIP=y
CONFIG_POLL=y

View file

@ -1,8 +0,0 @@
sample:
description: Demonstration of the APA102 LED strip driver
name: APA102 sample
tests:
sample.drivers.led.apa102:
platform_allow: nucleo_l432kc
tags: LED
depends_on: spi

View file

@ -1,88 +0,0 @@
/*
* Copyright (c) 2017 Linaro Limited
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <string.h>
#define LOG_LEVEL 4
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(main);
#include <zephyr/kernel.h>
#include <zephyr/drivers/led_strip.h>
#include <zephyr/device.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/sys/util.h>
/*
* Number of RGB LEDs in the LED strip, adjust as needed.
*/
#define STRIP_NUM_LEDS 20
#define DELAY_TIME K_MSEC(40)
static const struct led_rgb colors[] = {
{ .r = 0xff, .g = 0x00, .b = 0x00, }, /* red */
{ .r = 0x00, .g = 0xff, .b = 0x00, }, /* green */
{ .r = 0x00, .g = 0x00, .b = 0xff, }, /* blue */
};
static const struct led_rgb black = {
.r = 0x00,
.g = 0x00,
.b = 0x00,
};
struct led_rgb strip_colors[STRIP_NUM_LEDS];
const struct led_rgb *color_at(size_t time, size_t i)
{
size_t rgb_start = time % STRIP_NUM_LEDS;
if (rgb_start <= i && i < rgb_start + ARRAY_SIZE(colors)) {
return &colors[i - rgb_start];
} else {
return &black;
}
}
#define DELAY_TIME K_MSEC(40)
int main(void)
{
const struct device *strip;
size_t i, time;
strip = DEVICE_DT_GET_ANY(apa_apa102);
if (!strip) {
LOG_ERR("LED strip device not found");
return 0;
} else if (!device_is_ready(strip)) {
LOG_ERR("LED strip device %s is not ready", strip->name);
return 0;
} else {
LOG_INF("Found LED strip device %s", strip->name);
}
/*
* Display a pattern that "walks" the three primary colors
* down the strip until it reaches the end, then starts at the
* beginning. This has the effect of moving it around in a
* circle in the case of rings of pixels.
*/
LOG_INF("Displaying pattern on strip");
time = 0;
while (1) {
for (i = 0; i < STRIP_NUM_LEDS; i++) {
memcpy(&strip_colors[i], color_at(time, i),
sizeof(strip_colors[i]));
}
led_strip_update_rgb(strip, strip_colors, STRIP_NUM_LEDS);
k_sleep(DELAY_TIME);
time++;
}
return 0;
}

View file

@ -1,9 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(led_lpd8806)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})

View file

@ -1,89 +0,0 @@
.. zephyr:code-sample:: led-lpd8806
:name: LPD880x LED strip
:relevant-api: led_strip_interface
Control an LED strip using an LPD880x-compatible driver chip.
Overview
********
This sample application demonstrates basic usage of the lpd880x LED
strip driver, for controlling LED strips using LPD8803, LPD8806, and
compatible driver chips.
Requirements
************
.. _these strips from AdaFruit: https://www.adafruit.com/product/306
.. _74AHCT125: https://cdn-shop.adafruit.com/datasheets/74AHC125.pdf
- LED strip using LPD8806 or compatible, such as `these strips from AdaFruit`_.
- Zephyr board with SPI master driver. SPI communications must use 5V
signaling, which may require a level translator, such as the
`74AHCT125`_.
- 5V power supply.
Wiring
******
#. Ensure your Zephyr board, the 5V power supply, and the LED strip
share a common ground.
#. Connect the MOSI pin of your board's SPI master to the data input
pin of the first LPD8806 IC in the strip.
#. Connect the SCLK pin of your board's SPI master to the clock input
pin of the first LPD8806 IC in the strip.
#. Connect the 5V power supply pin to the 5V input of the LED strip.
Building and Running
********************
The sample application is located at ``samples/drivers/led_lpd8806/``
in the Zephyr source tree.
Before running the application, configure it as follows.
#. Configure your board's SPI master in a configuration file under
``boards/`` in the sample directory.
To provide additional configuration for some particular board,
create a ``boards/YOUR_BOARD_NAME.conf`` file in the application
directory. It will be merged into the application configuration.
In this file, you must ensure that the SPI peripheral you want to
use for this demo is enabled, and that its name is "lpd8806_spi".
See ``boards/96b_carbon.conf`` for an example, and refer to your
board's configuration options to set up your desired SPI master.
#. Set the number of LEDs in your strip in the application sources.
This is determined by the macro ``STRIP_NUM_LEDS`` in the file
``src/main.c``. The value in the file was chosen to work with one
meter of the AdaFruit strip.
Then build and flash the application:
.. zephyr-app-commands::
:zephyr-app: samples/drivers/led_lpd8806
:board: <board>
:goals: flash
:compact:
Refer to your :ref:`board's documentation <boards>` for alternative
flash instructions if your board doesn't support the ``flash`` target.
When you connect to your board's serial console, you should see the
following output:
.. code-block:: none
***** BOOTING ZEPHYR OS v1.9.99 *****
[general] [INF] main: Found SPI device lpd8806_spi
[general] [INF] main: Found LED strip device lpd880x_strip
[general] [INF] main: Displaying pattern on strip
References
**********
- `LPD8806 datasheet <https://cdn-shop.adafruit.com/datasheets/lpd8806+english.pdf>`_
- `74AHCT125 datasheet <https://cdn-shop.adafruit.com/datasheets/74AHC125.pdf>`_

View file

@ -1 +0,0 @@
CONFIG_SPI_STM32_INTERRUPT=y

View file

@ -1,7 +0,0 @@
# This file expresses generic requirements ONLY; see README.rst.
CONFIG_LOG=y
CONFIG_BOOT_BANNER=y
CONFIG_POLL=y
CONFIG_LED_STRIP=y

View file

@ -1,7 +0,0 @@
sample:
description: Demonstration of the lpd880x LED driver
name: LPD880x sample
tests:
sample.drivers.led.lpd8806:
platform_allow: 96b_carbon/stm32f401xe
tags: LED

View file

@ -1,84 +0,0 @@
/*
* Copyright (c) 2017 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <string.h>
#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(main);
#include <zephyr/kernel.h>
#include <zephyr/drivers/led_strip.h>
#include <zephyr/device.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/sys/util.h>
/*
* Number of RGB LEDs in the LED strip, adjust as needed.
*/
#define STRIP_NUM_LEDS 32
#define DELAY_TIME K_MSEC(40)
static const struct led_rgb colors[] = {
{ .r = 0xff, .g = 0x00, .b = 0x00, }, /* red */
{ .r = 0x00, .g = 0xff, .b = 0x00, }, /* green */
{ .r = 0x00, .g = 0x00, .b = 0xff, }, /* blue */
};
static const struct led_rgb black = {
.r = 0x00,
.g = 0x00,
.b = 0x00,
};
struct led_rgb strip_colors[STRIP_NUM_LEDS];
static const struct device *const strip = DEVICE_DT_GET_ANY(greeled_lpd8806);
const struct led_rgb *color_at(size_t time, size_t i)
{
size_t rgb_start = time % STRIP_NUM_LEDS;
if (rgb_start <= i && i < rgb_start + ARRAY_SIZE(colors)) {
return &colors[i - rgb_start];
} else {
return &black;
}
}
int main(void)
{
size_t i, time;
if (!strip) {
LOG_ERR("LED strip device not found");
return 0;
} else if (!device_is_ready(strip)) {
LOG_INF("LED strip device %s is not ready", strip->name);
return 0;
}
LOG_INF("Found LED strip device %s", strip->name);
/*
* Display a pattern that "walks" the three primary colors
* down the strip until it reaches the end, then starts at the
* beginning.
*/
LOG_INF("Displaying pattern on strip");
time = 0;
while (1) {
for (i = 0; i < STRIP_NUM_LEDS; i++) {
memcpy(&strip_colors[i], color_at(time, i),
sizeof(strip_colors[i]));
}
led_strip_update_rgb(strip, strip_colors, STRIP_NUM_LEDS);
k_sleep(DELAY_TIME);
time++;
}
return 0;
}

View file

@ -9,6 +9,14 @@ config SAMPLE_LED_UPDATE_DELAY
help
Delay between LED updates in ms.
config SAMPLE_LED_STRIP_LENGTH
int "LED strip length"
default 0
help
Number of LEDs in the strip.
If the value is zero, use the 'chain-length' property in
devicetree instead to determine LED numbers.
endmenu
source "Kconfig.zephyr"

View file

@ -2,41 +2,57 @@
:name: LED strip sample
:relevant-api: led_strip_interface
Control an LED strip using a WS2812 (or compatible) driver chip.
Control an LED strip example.
Overview
********
This sample application demonstrates basic usage of the WS2812 LED
strip driver, for controlling LED strips using WS2812, WS2812b,
SK6812, Everlight B1414 and compatible driver chips.
This sample application demonstrates basic usage of the LED strip.
Requirements
************
.. _NeoPixel Ring 12 from AdaFruit: https://www.adafruit.com/product/1643
.. _74AHCT125: https://cdn-shop.adafruit.com/datasheets/74AHC125.pdf
Zephyr supports various LED strip chips. For example,
- LED strip using WS2812 or compatible, such as the `NeoPixel Ring 12
from AdaFruit`_.
- WS2812, such as the `NeoPixel(WS2812 compatible) LED Strip from AdaFruit`_.
- APA102, such as the `Dotstar(APA102 compatible) LED Strip from AdaFruit`_.
- LPD8806, such as the `LPD8806 LED Strip from AdaFruit`_.
- Note that 5V communications may require a level translator, such as the
`74AHCT125`_.
- Power supply. These LED strips usually require a 5V supply.
- LED power strip supply. It's fine to power the LED strip off of your board's
IO voltage level even if that's below 5V; the LEDs will simply be dimmer in
this case.
- If the LED strip connects to the SPI bus, SPI communications usually use 5V
signaling, which may require a level translator, such as the
`74AHCT125 datasheet`_.
.. _NeoPixel(WS2812 compatible) LED Strip from AdaFruit: https://www.adafruit.com/product/3919
.. _Dotstar(APA102 compatible) LED Strip from AdaFruit: https://www.adafruit.com/product/2242
.. _LPD8806 LED Strip from AdaFruit: https://www.adafruit.com/product/1948
.. _74AHCT125 datasheet: https://cdn-shop.adafruit.com/datasheets/74AHC125.pdf
Wiring
******
APA020 and LPD880x
==================
#. Ensure your Zephyr board, the 5V power supply, and the LED strip
share a common ground.
#. Connect the MOSI pin of your board's SPI master to the data input
pin of the first IC in the strip.
#. Connect the SCLK pin of your board's SPI master to the clock input
pin of the first IC in the strip.
#. Connect the 5V power supply pin to the 5V input of the LED strip.
WS2812
======
#. Ensure your Zephyr board, and the LED strip share a common ground.
#. Connect the LED strip control pin (either I2S SDOUT, SPI MOSI or GPIO) from
your board to the data input pin of the first WS2812 IC in the strip.
#. Power the LED strip at an I/O level compatible with the control pin signals.
Wiring on a thingy52
********************
Note about thingy52
-------------------
The thingy52 has integrated NMOS transistors, that can be used instead of a level shifter.
The I2S driver supports inverting the output to suit this scheme, using the ``out-active-low`` dts
@ -46,37 +62,12 @@ property. See the overlay file
Building and Running
********************
.. _blog post on WS2812 timing: https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
This sample's source directory is :zephyr_file:`samples/drivers/led_strip/`.
To make sure the sample is set up properly for building, you must:
- select the correct WS2812 driver backend for your SoC. This currently should
be :kconfig:option:`CONFIG_WS2812_STRIP_SPI` unless you are using an nRF51 SoC, in
which case it will be :kconfig:option:`CONFIG_WS2812_STRIP_GPIO`.
For the nRF52832, the SPI peripheral might output some garbage at the end of
transmissions, and that might confuse older WS2812 strips. Use the I2S driver
in those cases.
- create a ``led-strip`` :ref:`devicetree alias <dt-alias-chosen>`, which refers
to a node in your :ref:`devicetree <dt-guide>` with a
``worldsemi,ws2812-i2s``, ``worldsemi,ws2812-spi`` or
``worldsemi,ws2812-gpio`` compatible. The node must be properly configured for
the driver backend (I2S, SPI or GPIO) and daisy chain length (number of WS2812
chips).
For example devicetree configurations for each compatible, see
:zephyr_file:`samples/drivers/led_ws2812/boards/thingy52_nrf52832.overlay`,
:zephyr_file:`samples/drivers/led_ws2812/boards/nrf52dk_nrf52832.overlay` and
:zephyr_file:`samples/drivers/led_ws2812/boards/nrf51dk_nrf51822.overlay`.
Some boards are already supported out of the box; see the :file:`boards`
directory for this sample for details.
The sample updates the LED strip periodically. The update frequency can be
modified by changing the :kconfig:option:`CONFIG_SAMPLE_LED_UPDATE_DELAY`.
If there is no chain-length property in the devicetree node, you need to set
the number of LEDs in the :kconfig:option:`CONFIG_SAMPLE_LED_STRIP_LENGTH` option.
Then build and flash the application:
.. zephyr-app-commands::
@ -94,35 +85,18 @@ following output:
[00:00:00.005,920] <inf> main: Found LED strip device WS2812
[00:00:00.005,950] <inf> main: Displaying pattern on strip
Supported drivers
*****************
This sample uses different drivers depending on the selected board:
I2S driver:
- thingy52/nrf52832
- nrf5340dk/nrf5340 (3.3V logic level, a logic level shifter may be required)
- should work for other boards featuring an nRF5340 host processor
SPI driver:
- mimxrt1050_evk
- nrf52dk/nrf52832
- nucleo_f070rb
- nucleo_g071rb
- nucleo_h743zi
- nucleo_l476rg
GPIO driver (cortex-M0 only):
- bbc_microbit
- nrf51dk/nrf51822
References
**********
- `RGB LED strips: an overview <http://nut-bolt.nl/2012/rgb-led-strips/>`_
- `74AHCT125 datasheet
<https://cdn-shop.adafruit.com/datasheets/74AHC125.pdf>`_
- `WS2812 datasheet`_
- `LPD8806 datasheet`_
- `APA102C datasheet`_
- `74AHCT125 datasheet`_
- `RGB LED strips: an overview`_
- An excellent `blog post on WS2812 timing`_.
.. _WS2812 datasheet: https://cdn-shop.adafruit.com/datasheets/WS2812.pdf
.. _LPD8806 datasheet: https://cdn-shop.adafruit.com/datasheets/lpd8806+english.pdf
.. _APA102C datasheet: https://cdn-shop.adafruit.com/product-files/2477/APA102C-iPixelLED.pdf
.. _blog post on WS2812 timing: https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
.. _RGB LED strips\: an overview: http://nut-bolt.nl/2012/rgb-led-strips/

View file

@ -0,0 +1,3 @@
CONFIG_SPI_STM32_INTERRUPT=y
CONFIG_SAMPLE_LED_STRIP_LENGTH=1

View file

@ -6,9 +6,15 @@
&spi2 {
led_strip@0 {
lpd8806: lpd8806@0 {
compatible = "greeled,lpd8806";
reg = <0>;
spi-max-frequency = <2000000>;
};
};
/ {
aliases {
led-strip = &lpd8806;
};
};

View file

@ -0,0 +1 @@
CONFIG_SAMPLE_LED_STRIP_LENGTH=4

View file

@ -0,0 +1 @@
CONFIG_SAMPLE_LED_STRIP_LENGTH=1

View file

@ -1,2 +1,3 @@
# Enable LED 5V Regulator
CONFIG_REGULATOR=y
CONFIG_SAMPLE_LED_STRIP_LENGTH=4

View file

@ -0,0 +1 @@
CONFIG_SAMPLE_LED_STRIP_LENGTH=1

View file

@ -6,9 +6,15 @@
&spi1 {
apa102@0 {
apa102: apa102@0 {
compatible = "apa,apa102";
reg = <0>;
spi-max-frequency = <5250000>;
};
};
/ {
aliases {
led-strip = &apa102;
};
};

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2017 Linaro Limited
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2024 TOKITA Hiroshi
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -19,7 +20,14 @@ LOG_MODULE_REGISTER(main);
#include <zephyr/sys/util.h>
#define STRIP_NODE DT_ALIAS(led_strip)
#if CONFIG_SAMPLE_LED_STRIP_LENGTH != 0
#define STRIP_NUM_PIXELS CONFIG_SAMPLE_LED_STRIP_LENGTH
#elif DT_NODE_HAS_PROP(DT_ALIAS(led_strip), chain_length)
#define STRIP_NUM_PIXELS DT_PROP(DT_ALIAS(led_strip), chain_length)
#else
#error Unable to determine length of LED strip
#endif
#define DELAY_TIME K_MSEC(CONFIG_SAMPLE_LED_UPDATE_DELAY)
@ -31,7 +39,7 @@ static const struct led_rgb colors[] = {
RGB(0x00, 0x00, 0x0f), /* blue */
};
struct led_rgb pixels[STRIP_NUM_PIXELS];
static struct led_rgb pixels[STRIP_NUM_PIXELS];
static const struct device *const strip = DEVICE_DT_GET(STRIP_NODE);