mirror of https://github.com/zmkfirmware/zmk.git
docs(feat): further generalize RGB information (#2485)
* docs(feat): Provide example of PIO SPI for RGB underglow * docs(feat): further generalize RGB information * docs: use nice_nano_v2 for board-specific shield config example Co-authored-by: Cem Aksoylar <caksoylar@users.noreply.github.com> --------- Co-authored-by: Cem Aksoylar <caksoylar@users.noreply.github.com>
This commit is contained in:
parent
40f59df2cc
commit
6e37f21f6b
|
|
@ -6,16 +6,16 @@ sidebar_label: RGB Underglow
|
|||
RGB underglow is a feature used to control "strips" of RGB LEDs. Most of the time this is called underglow and creates a glow underneath the board using a ring of LEDs around the edge, hence the name. However, this can be extended to be used to control anything from a single LED to a long string of LEDs anywhere on the keyboard.
|
||||
|
||||
:::info
|
||||
RGB underglow can also be used for under-key lighting. If you have RGB LEDs on your keyboard, this is what you want. For PWM/single color LEDs, see [Backlight](backlight.mdx).
|
||||
RGB underglow can also be used for per-key lighting. If you have RGB LEDs on your keyboard, this is what you want. For PWM/single color LEDs, see [Backlight](backlight.mdx).
|
||||
:::
|
||||
|
||||
ZMK supports all the RGB LEDs supported by Zephyr. Here's the current list supported:
|
||||
ZMK relies on Zephyr's `led-strip` drivers for this feature. The following LEDs/LED families have been implemented:
|
||||
|
||||
- WS2812-ish (WS2812B, WS2813, SK6812, or compatible)
|
||||
- WS2812 (includes WS2812B, WS2813, SK6812, and others)
|
||||
- APA102
|
||||
- LPD880x (LPD8803, LPD8806, or compatible)
|
||||
- LPD880x (includes LPD8803, LPD8806, and others)
|
||||
|
||||
Of the compatible types, the WS2812 LED family is by far the most popular type. Currently each of these types of LEDs are expected to be run using SPI with a couple of exceptions.
|
||||
The WS2812 LED family is by far the most popular of these types, so this page will primarily focus on working with it.
|
||||
|
||||
Here you can see the RGB underglow feature in action using WS2812 LEDs.
|
||||
|
||||
|
|
@ -34,16 +34,15 @@ CONFIG_ZMK_RGB_UNDERGLOW=y
|
|||
CONFIG_WS2812_STRIP=y
|
||||
```
|
||||
|
||||
See [Configuration Overview](/docs/config) for more instructions on how to
|
||||
use Kconfig.
|
||||
See [Configuration Overview](/docs/config) for more instructions on how to use Kconfig.
|
||||
|
||||
If your board or shield does not have RGB underglow configured, refer to [Adding RGB Underglow to a Board](#adding-rgb-underglow-to-a-board).
|
||||
|
||||
### Modifying the Number of LEDs
|
||||
|
||||
A common issue when enabling underglow is that some of the installed LEDs do not illuminate. This can happen when a board's default underglow configuration accounts only for either the downward facing LEDs or the upward facing LEDs under each key. On a split keyboard, a good sign that this may be the problem is that the unilluminated LEDs on each half are symmetrical.
|
||||
The number of LEDs specified in the default configuration for your board or shield may not match the number you have installed. For example, the `corne` shield specifies only 10 LEDs per side while supporting up to 27. On a split keyboard, a good sign of this mismatch is if the lit LEDs on each half are symmetrical.
|
||||
|
||||
The number of underglow LEDs is controlled by the `chain-length` property in the `led_strip` node. You can [change the value of this property](../config/index.md#changing-devicetree-properties) in the `<keyboard>.keymap` file by adding a stanza like this one outside of any other node (i.e. above or below the `/` node):
|
||||
The `chain-length` property of the `led_strip` node controls the number of underglow LEDs. If it is incorrect for your build, [you can change this property](../config/index.md#changing-devicetree-properties) in your `<keyboard>.keymap` file by adding a stanza like this one outside of any other node (i.e. above or below the `/` node):
|
||||
|
||||
```dts
|
||||
&led_strip {
|
||||
|
|
@ -51,7 +50,7 @@ The number of underglow LEDs is controlled by the `chain-length` property in the
|
|||
};
|
||||
```
|
||||
|
||||
where the value is the total count of LEDs (per half, for split keyboards).
|
||||
For split keyboards, set `chain-length` to the number of LEDs installed on each half.
|
||||
|
||||
## Configuring RGB Underglow
|
||||
|
||||
|
|
@ -59,16 +58,23 @@ See [RGB underglow configuration](/docs/config/underglow).
|
|||
|
||||
## Adding RGB Underglow to a Board
|
||||
|
||||
RGB underglow is always added to a board, not a shield. This is a consequence of needing to configure SPI to control the LEDs.
|
||||
If you have a shield with RGB underglow, you must add a `boards/` directory within your shield folder to define the RGB underglow individually for each board that supports the shield.
|
||||
Inside the `boards/` folder, you define a `<board>.overlay` for each different board.
|
||||
For example, the Kyria shield has a `boards/nice_nano.overlay` file that defines the RGB underglow for the `nice_nano` board specifically.
|
||||
Support for RGB underglow is always added to a board, not a shield. This is because the LED strip drivers rely on hardware-specific interfaces (e.g. SPI, I2S) and configurations, which shields do not control.
|
||||
|
||||
Shields written for boards which support RGB underglow should add a `boards/` folder underneath the shield folder. Inside this `boards/` folder, create a `<board>.overlay` for any of the boards the shield can be used with. Place all hardware-specific configurations in these `.overlay` files.
|
||||
|
||||
For example: the `kyria` shield has a [`boards/nice_nano_v2.overlay`](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/kyria/boards/nice_nano_v2.overlay) and a [`boards/nrfmicro_13.overlay`](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/kyria/boards/nrfmicro_13.overlay), which configure a WS2812 LED strip for the `nice_nano_v2` and `nrfmicro_13` boards respectively.
|
||||
|
||||
### nRF52-Based Boards
|
||||
|
||||
With nRF52 boards, you can just use `&spi3` and define the pins you want to use.
|
||||
Using an SPI-based LED strip driver on the `&spi3` interface is the simplest option for nRF52-based boards. If possible, avoid using pins which are limited to low-frequency I/O for this purpose. The resulting interference may result in poor wireless performance.
|
||||
|
||||
Here's an example on a definition that uses P0.06:
|
||||
:::info
|
||||
|
||||
The list of low frequency I/O pins for the nRF52840 can be found [here](https://docs.nordicsemi.com/bundle/ps_nrf52840/page/pin.html).
|
||||
|
||||
:::
|
||||
|
||||
The following example uses `P0.06` as the "Data In" pin of a WS2812-compatible LED strip:
|
||||
|
||||
```dts
|
||||
#include <dt-bindings/led/led.h>
|
||||
|
|
@ -89,38 +95,31 @@ Here's an example on a definition that uses P0.06:
|
|||
};
|
||||
|
||||
&spi3 {
|
||||
compatible = "nordic,nrf-spim";
|
||||
status = "okay";
|
||||
compatible = "nordic,nrf-spim";
|
||||
status = "okay";
|
||||
|
||||
pinctrl-0 = <&spi3_default>;
|
||||
pinctrl-1 = <&spi3_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <&spi3_default>;
|
||||
pinctrl-1 = <&spi3_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
||||
led_strip: ws2812@0 {
|
||||
compatible = "worldsemi,ws2812-spi";
|
||||
led_strip: ws2812@0 {
|
||||
compatible = "worldsemi,ws2812-spi";
|
||||
|
||||
/* SPI */
|
||||
reg = <0>; /* ignored, but necessary for SPI bindings */
|
||||
spi-max-frequency = <4000000>;
|
||||
/* SPI */
|
||||
reg = <0>; /* ignored, but necessary for SPI bindings */
|
||||
spi-max-frequency = <4000000>;
|
||||
|
||||
/* WS2812 */
|
||||
chain-length = <10>; /* number of LEDs */
|
||||
spi-one-frame = <0x70>;
|
||||
spi-zero-frame = <0x40>;
|
||||
color-mapping = <LED_COLOR_ID_GREEN
|
||||
LED_COLOR_ID_RED
|
||||
LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
/* WS2812 */
|
||||
chain-length = <10>; /* number of LEDs */
|
||||
spi-one-frame = <0x70>;
|
||||
spi-zero-frame = <0x40>;
|
||||
color-mapping = <LED_COLOR_ID_GREEN
|
||||
LED_COLOR_ID_RED
|
||||
LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
:::info
|
||||
|
||||
If you are configuring SPI for an nRF52 based board, double check that you are using pins that aren't restricted to low frequency I/O.
|
||||
Ignoring these restrictions may result in poor wireless performance. You can find the list of low frequency I/O pins for the nRF52840 [here](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fpin.html&cp=4_0_0_6_0).
|
||||
|
||||
:::
|
||||
|
||||
:::note
|
||||
|
||||
Standard WS2812 LEDs use a wire protocol where the bits for the colors green, red, and blue values are sent in that order.
|
||||
|
|
@ -130,34 +129,60 @@ If your board/shield uses LEDs that require the data sent in a different order,
|
|||
|
||||
### Other Boards
|
||||
|
||||
For other boards, you must select an SPI definition that has the `MOSI` pin as your data pin going to your LED strip.
|
||||
Be sure to check the Zephyr documentation for the LED strip and necessary hardware bindings. Not every board has an `spi3` node, or configures `pinctrl` the same way. Reconcile this with any hardware restrictions found in the manufacturer's datasheet. Additional hardware interfaces may need to be enabled via Kconfig.
|
||||
|
||||
Here's another example for a non-nRF52 board on `spi3`:
|
||||
For example: the `sparkfun_pro_micro_rp2040` board can utilize SPI via PIO to run a WS2812 strip on `GP0`:
|
||||
|
||||
```dts
|
||||
#include <dt-bindings/led/led.h>
|
||||
|
||||
&spi3 {
|
||||
&pinctrl {
|
||||
pio0_spi0_default: pio0_spi0_default {
|
||||
group1 {
|
||||
pinmux = <PIO0_P0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
led_strip: ws2812@0 {
|
||||
compatible = "worldsemi,ws2812-spi";
|
||||
&pio0 {
|
||||
status = "okay";
|
||||
|
||||
/* SPI */
|
||||
reg = <0>;
|
||||
spi-max-frequency = <5250000>;
|
||||
pio0_spi0: pio0_spi0 {
|
||||
pinctrl-0 = <&pio0_spi0_default>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
/* WS2812 */
|
||||
chain-length = <10>; /* number of LEDs */
|
||||
spi-one-frame = <0x70>; /* make sure to configure this properly for your SOC */
|
||||
spi-zero-frame = <0x40>; /* make sure to configure this properly for your SOC */
|
||||
color-mapping = <LED_COLOR_ID_GREEN
|
||||
LED_COLOR_ID_RED
|
||||
LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
compatible = "raspberrypi,pico-spi-pio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&system_clk>;
|
||||
clock-frequency = <4000000>;
|
||||
|
||||
clk-gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>; /* Must be defined. Select a pin that is not used elsewhere. */
|
||||
mosi-gpios = <&pro_micro 1 GPIO_ACTIVE_HIGH>; /* Data In pin. */
|
||||
miso-gpios = <&pro_micro 1 GPIO_ACTIVE_HIGH>; /* Must be defined. Re-using the DI pin is OK for WS2812. */
|
||||
|
||||
led_strip: ws2812@0 {
|
||||
compatible = "worldsemi,ws2812-spi";
|
||||
|
||||
/* SPI */
|
||||
reg = <0>; /* ignored, but necessary for SPI bindings */
|
||||
spi-max-frequency = <4000000>;
|
||||
|
||||
/* WS2812 */
|
||||
chain-length = <10>; /* number of LEDs */
|
||||
spi-one-frame = <0x70>;
|
||||
spi-zero-frame = <0x40>;
|
||||
color-mapping = <LED_COLOR_ID_GREEN
|
||||
LED_COLOR_ID_RED
|
||||
LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Once you have your `led_strip` properly defined you need to add it to the root devicetree node `chosen` element:
|
||||
### Final Steps
|
||||
|
||||
Once the `led_strip` is properly defined, add it to the `chosen` node under the root devicetree node:
|
||||
|
||||
```dts
|
||||
/ {
|
||||
|
|
@ -166,11 +191,3 @@ Once you have your `led_strip` properly defined you need to add it to the root d
|
|||
};
|
||||
};
|
||||
```
|
||||
|
||||
Finally you need to enable the `CONFIG_ZMK_RGB_UNDERGLOW` and `CONFIG_*_STRIP` configuration values in the `.conf` file of your board (or set a default in the `Kconfig.defconfig`):
|
||||
|
||||
```ini
|
||||
CONFIG_ZMK_RGB_UNDERGLOW=y
|
||||
# Use the STRIP config specific to the LEDs you're using
|
||||
CONFIG_WS2812_STRIP=y
|
||||
```
|
||||
|
|
|
|||
Loading…
Reference in New Issue