Color wheel
Animate a circular HSV color space projection that spins around the centre of an RGB LED matrix, using the Display driver API.
Overview
This sample paints a color wheel onto an RGB LED matrix: the hue of each pixel follows its polar angle around the centre, so a full rainbow wraps once around the middle, while saturation rises with the radius. A bright white core in the centre blooms into fully saturated color towards the corners, and the whole wheel slowly spins. It drives the panel through the Display driver API rather than the LED strip API of the LED subsystem, so the same binary runs on panels of different geometry, wiring order and pixel format without any board specific code.
The panel is taken from the chosen { zephyr,display = ...; }; node, which
on all supported boards resolves to a led-strip-matrix device on top of a
WS2812 compatible LED strip. That driver maps a rectangular frame buffer onto
the serpentine or circulative pixel order of the physical strip.
Color model
A color wheel is much easier to express in HSL and HSV [1] than in RGB: hue is the angle, saturation is the radius, and value sets the brightness of the whole panel. The sample computes every pixel in HSV and converts it to RGB in samples/display/colorwheel/src/hsv.c.
Each pixel is placed in a polar coordinate system centered on the panel, and the HSV values computed as follows:
hue(x, y) = atan2(y - cy, x - cx) + phase
saturation(x, y) = 255 * dist((x, y), center) / (corner_radius * scale)
value(x, y) = CONFIG_COLORWHEEL_MAX_BRIGHTNESS
where (cx, cy) is the center of the panel and the radius is normalised
against a fraction of the corner distance, in percent, set by
CONFIG_COLORWHEEL_SAT_SCALE, at which the ramp reaches full saturation.
Configuration options
The following sample-specific Kconfig options are used in this sample (located in samples/display/colorwheel/Kconfig):
- CONFIG_COLORWHEEL_HUE_STEP
Hue rotation per frame [degrees]
How far the color wheel rotates around the centre of the panel between two consecutive frames. Set to 0 to render a static wheel.
- CONFIG_COLORWHEEL_FRAME_INTERVAL
Delay between two frames [milliseconds]
Time to sleep between two consecutive frames. Together with COLORWHEEL_HUE_STEP this defines the angular speed of the wheel. The default of 40 ms gives 25 frames per second.
- CONFIG_COLORWHEEL_SAT_SCALE
Radius of full saturation [% of corner distance]
Radius at which the saturation ramp reaches full saturation, as a percentage of the distance from the centre to a corner. Beyond this radius the color stays fully saturated all the way into the corners.
- CONFIG_COLORWHEEL_MAX_BRIGHTNESS
Brightness ceiling
The brightness every pixel is driven at. The radial ramp is carried by saturation alone, so this option sets the brightness of the whole panel directly.
Important
Keep CONFIG_COLORWHEEL_MAX_BRIGHTNESS low. A WS2812B pixel draws up to 60
㎃ at full white according to the WS2812B datasheet [2], so an 8×8 panel alone
can draw more than 3.5 A, far beyond what a typical board’s USB supply can
deliver.
Requirements
An RGB LED matrix assigned to the zephyr,display chosen node, with a
pixel format of either RGB_888 or ARGB_8888. Either one of the following
development boards with an on-board matrix:
RP2350-Matrix (Waveshare RP2350-Matrix), an 8×8 panel
RP2040-Matrix (Waveshare RP2040-Matrix), a 5×5 panel
or a Raspberry Pi Pico compatible board carrying the following shield:
Waveshare Pico RGB LED (Waveshare Pico-RGB-LED), a 16×10 panel
The sample supports the following platforms (located in samples/display/colorwheel/tests.yaml):
Hardware platforms |
Order number |
Board name |
Board target |
Shields |
|---|---|---|---|---|
RP2350 |
|
|||
RP2040 |
|
|||
RP2040 |
|
|||
RP2040 |
|
|||
RP2350 |
|
Building and Running
On RP2350-Matrix board, on ARM Cortex-M33:
west build -b waveshare_rp2350_matrix/rp2350a/m33 -p -S "usb-console" -d build/colorwheel-waveshare_rp2350_matrix bridle/samples/display/colorwheel west flash -r uf2 -d build/colorwheel-waveshare_rp2350_matrix
On RP2350-Matrix board, on Hazard3 RISC-V (RV32IMAC+):
west build -b waveshare_rp2350_matrix/rp2350a/hazard3 -p -S "usb-console" -d build/colorwheel-waveshare_rp2350_matrix bridle/samples/display/colorwheel west flash -r uf2 -d build/colorwheel-waveshare_rp2350_matrix
On Waveshare Pico RGB LED shield, on a Raspberry Pi Pico:
west build -b rpi_pico/rp2040/bbe -p -S "usb-console" --shield waveshare_pico_rgb_led -d build/colorwheel-rpi_pico bridle/samples/display/colorwheel west flash -r uf2 -d build/colorwheel-rpi_pico
Sample output
The following output is logged on the UART console, here for the 8×8 panel of the RP2350-Matrix board:
*** Booting Zephyr OS build v4.4.99… ***
[00:00:00.003,000] <inf> colorwheel: Color wheel on a 8x8 RGB matrix, 4 bytes per pixel, 40 ms per frame
Troubleshooting
- The panel stays dark
Check that the board assigns a matrix to the
zephyr,displaychosen node. The build fails when no such node exists, but a board that chooses a different kind of display reports an unsupported pixel format at run time instead.- The panel flickers or the board resets
The LED strip is almost certainly browning out the supply. Lower
CONFIG_COLORWHEEL_MAX_BRIGHTNESS, or feed the panel from a supply that can carry the current.- The centre of the wheel is not white
The centre should be a bright white core on any panel. If it is not, the matrix is most likely cropped by a
widthorheightsmaller than the physical panel, which moves the geometric centre off the true middle. Check thewidthandheightproperties of the matrix node against the panel.
Dependencies
This sample uses the following Zephyr libraries:
-
include/zephyr/drivers/display.h
Light-Emitting Diode (LED), by way of the LED strip matrix display driver
-
include/zephyr/kernel.h
Known issues and limitations
The sample redraws and rewrites the whole panel on every frame, even when
CONFIG_COLORWHEEL_HUE_STEP is 0 and nothing has changed. This keeps
the code simple at the cost of some unnecessary traffic to the LED strip.