Skip to content

Commit ccd598e

Browse files
Pac72suda-morris
andauthored
led_strip: support for 4 components RGBW leds (SK6812) (#126)
* Support for 4 components RGBW leds (SK6812) Co-authored-by: suda-morris <[email protected]>
1 parent 4a0864b commit ccd598e

9 files changed

+129
-21
lines changed

led_strip/CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,12 @@
1212
- Support various RMT clock sources
1313
- Acquire and release the power management lock before and after each refresh
1414
- New driver flag: `invert_out` which can invert the led control signal by hardware
15+
16+
## 2.2.0
17+
18+
- Support for 4 components RGBW leds (SK6812):
19+
- in led_strip_config_t new fields
20+
led_pixel_format, controlling byte format (LED_PIXEL_FORMAT_GRB, LED_PIXEL_FORMAT_GRBW)
21+
led_model, used to configure bit timing (LED_MODEL_WS2812, LED_MODEL_SK6812)
22+
- new API led_strip_set_pixel_rgbw
23+
- new interface type set_pixel_rgbw

led_strip/idf_component.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: "2.1.0"
1+
version: "2.2.0"
22
description: Driver for Addressable LED Strip (WS2812, etc)
33
url: https://github.com/espressif/idf-extra-components/tree/master/led_strip
44
dependencies:

led_strip/include/led_strip.h

+16
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ extern "C" {
2929
*/
3030
esp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
3131

32+
/**
33+
* @brief Set RGBW for a specific pixel
34+
*
35+
* @param strip: LED strip
36+
* @param index: index of pixel to set
37+
* @param red: red part of color
38+
* @param green: green part of color
39+
* @param blue: blue part of color
40+
* @param white: separate white component (sk6812rgbw leds)
41+
*
42+
* @return
43+
* - ESP_OK: RGBW color succesfully set for the pixel
44+
* - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of an invalid argument
45+
*/
46+
esp_err_t led_strip_set_pixel_rgbw(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white);
47+
3248
/**
3349
* @brief Refresh memory colors to LEDs
3450
*

led_strip/include/led_strip_types.h

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@
1111
extern "C" {
1212
#endif
1313

14+
typedef enum {
15+
LED_PIXEL_FORMAT_GRB,
16+
LED_PIXEL_FORMAT_GRBW
17+
} led_pixel_format_t;
18+
19+
typedef enum {
20+
LED_MODEL_WS2812,
21+
LED_MODEL_SK6812
22+
} led_model_t;
23+
1424
/**
1525
* @brief LED strip handle
1626
*/
@@ -22,6 +32,8 @@ typedef struct led_strip_t *led_strip_handle_t;
2232
typedef struct {
2333
uint32_t strip_gpio_num; /*!< GPIO number that used by LED strip */
2434
uint32_t max_leds; /*!< Maximum LEDs in a single strip */
35+
led_pixel_format_t led_pixel_format;
36+
led_model_t led_model;
2537
struct {
2638
uint32_t invert_out: 1; /*!< Invert output signal */
2739
} flags;

led_strip/interface/led_strip_interface.h

+16
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,22 @@ struct led_strip_t {
3434
*/
3535
esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
3636

37+
/**
38+
* @brief Set RGBW for a specific pixel
39+
*
40+
* @param strip: LED strip
41+
* @param index: index of pixel to set
42+
* @param red: red part of color
43+
* @param green: green part of color
44+
* @param blue: blue part of color
45+
* @param white: separate white component (sk6812rgbw leds)
46+
*
47+
* @return
48+
* - ESP_OK: RGBW color succesfully set for the pixel
49+
* - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of an invalid argument
50+
*/
51+
esp_err_t (*set_pixel_rgbw)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white);
52+
3753
/**
3854
* @brief Refresh memory colors to LEDs
3955
*

led_strip/src/led_strip_api.c

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ esp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint32_t
1616
return strip->set_pixel(strip, index, red, green, blue);
1717
}
1818

19+
esp_err_t led_strip_set_pixel_rgbw(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)
20+
{
21+
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
22+
return strip->set_pixel_rgbw(strip, index, red, green, blue, white);
23+
}
24+
1925
esp_err_t led_strip_refresh(led_strip_handle_t strip)
2026
{
2127
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");

led_strip/src/led_strip_rmt_dev.c

+32-4
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,36 @@ typedef struct {
2222
rmt_channel_handle_t rmt_chan;
2323
rmt_encoder_handle_t strip_encoder;
2424
uint32_t strip_len;
25+
uint8_t bytes_per_pixel;
2526
uint8_t pixel_buf[];
2627
} led_strip_rmt_obj;
2728

2829
static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
2930
{
3031
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
3132
ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
32-
uint32_t start = index * 3;
33+
uint32_t start = index * rmt_strip->bytes_per_pixel;
3334
// In thr order of GRB, as LED strip like WS2812 sends out pixels in this order
3435
rmt_strip->pixel_buf[start + 0] = green & 0xFF;
3536
rmt_strip->pixel_buf[start + 1] = red & 0xFF;
3637
rmt_strip->pixel_buf[start + 2] = blue & 0xFF;
38+
if (rmt_strip->bytes_per_pixel > 3) {
39+
rmt_strip->pixel_buf[start + 3] = 0;
40+
}
41+
return ESP_OK;
42+
}
43+
44+
static esp_err_t led_strip_rmt_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)
45+
{
46+
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
47+
ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
48+
ESP_RETURN_ON_FALSE(rmt_strip->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "wrong LED pixel format, expected 4 bytes per pixel");
49+
uint8_t *buf_start = rmt_strip->pixel_buf + index * 4;
50+
// SK6812 component order is GRBW
51+
*buf_start = green & 0xFF;
52+
*++buf_start = red & 0xFF;
53+
*++buf_start = blue & 0xFF;
54+
*++buf_start = white & 0xFF;
3755
return ESP_OK;
3856
}
3957

@@ -46,7 +64,7 @@ static esp_err_t led_strip_rmt_refresh(led_strip_t *strip)
4664

4765
ESP_RETURN_ON_ERROR(rmt_enable(rmt_strip->rmt_chan), TAG, "enable RMT channel failed");
4866
ESP_RETURN_ON_ERROR(rmt_transmit(rmt_strip->rmt_chan, rmt_strip->strip_encoder, rmt_strip->pixel_buf,
49-
rmt_strip->strip_len * 3, &tx_conf), TAG, "transmit pixels by RMT failed");
67+
rmt_strip->strip_len * rmt_strip->bytes_per_pixel, &tx_conf), TAG, "transmit pixels by RMT failed");
5068
ESP_RETURN_ON_ERROR(rmt_tx_wait_all_done(rmt_strip->rmt_chan, -1), TAG, "flush RMT channel failed");
5169
ESP_RETURN_ON_ERROR(rmt_disable(rmt_strip->rmt_chan), TAG, "disable RMT channel failed");
5270
return ESP_OK;
@@ -56,7 +74,7 @@ static esp_err_t led_strip_rmt_clear(led_strip_t *strip)
5674
{
5775
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
5876
// Write zero to turn off all leds
59-
memset(rmt_strip->pixel_buf, 0, rmt_strip->strip_len * 3);
77+
memset(rmt_strip->pixel_buf, 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel);
6078
return led_strip_rmt_refresh(strip);
6179
}
6280

@@ -74,7 +92,14 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l
7492
led_strip_rmt_obj *rmt_strip = NULL;
7593
esp_err_t ret = ESP_OK;
7694
ESP_GOTO_ON_FALSE(led_config && rmt_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
77-
rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * 3);
95+
ESP_GOTO_ON_FALSE(led_config->led_pixel_format <= LED_PIXEL_FORMAT_GRBW, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format");
96+
uint8_t bytes_per_pixel;
97+
if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) {
98+
bytes_per_pixel = 4;
99+
} else {
100+
bytes_per_pixel = 3;
101+
}
102+
rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel);
78103
ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt strip");
79104
uint32_t resolution = rmt_config->resolution_hz ? rmt_config->resolution_hz : LED_STRIP_RMT_DEFAULT_RESOLUTION;
80105

@@ -96,12 +121,15 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l
96121

97122
led_strip_encoder_config_t strip_encoder_conf = {
98123
.resolution = resolution,
124+
.led_model = led_config->led_model
99125
};
100126
ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, "create LED strip encoder failed");
101127

102128

129+
rmt_strip->bytes_per_pixel = bytes_per_pixel;
103130
rmt_strip->strip_len = led_config->max_leds;
104131
rmt_strip->base.set_pixel = led_strip_rmt_set_pixel;
132+
rmt_strip->base.set_pixel_rgbw = led_strip_rmt_set_pixel_rgbw;
105133
rmt_strip->base.refresh = led_strip_rmt_refresh;
106134
rmt_strip->base.clear = led_strip_rmt_clear;
107135
rmt_strip->base.del = led_strip_rmt_del;

led_strip/src/led_strip_rmt_encoder.c

+35-16
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,41 @@ esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rm
8181
led_encoder->base.encode = rmt_encode_led_strip;
8282
led_encoder->base.del = rmt_del_led_strip_encoder;
8383
led_encoder->base.reset = rmt_led_strip_encoder_reset;
84-
// different led strip might have its own timing requirements, following parameter is for WS2812
85-
rmt_bytes_encoder_config_t bytes_encoder_config = {
86-
.bit0 = {
87-
.level0 = 1,
88-
.duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us
89-
.level1 = 0,
90-
.duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us
91-
},
92-
.bit1 = {
93-
.level0 = 1,
94-
.duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us
95-
.level1 = 0,
96-
.duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us
97-
},
98-
.flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0
99-
};
84+
rmt_bytes_encoder_config_t bytes_encoder_config;
85+
if (config->led_model == LED_MODEL_SK6812) {
86+
bytes_encoder_config = (rmt_bytes_encoder_config_t) {
87+
.bit0 = {
88+
.level0 = 1,
89+
.duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us
90+
.level1 = 0,
91+
.duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us
92+
},
93+
.bit1 = {
94+
.level0 = 1,
95+
.duration0 = 0.6 * config->resolution / 1000000, // T1H=0.6us
96+
.level1 = 0,
97+
.duration1 = 0.6 * config->resolution / 1000000, // T1L=0.6us
98+
},
99+
.flags.msb_first = 1 // SK6812 transfer bit order: G7...G0R7...R0B7...B0W7...W0
100+
};
101+
} else {
102+
// different led strip might have its own timing requirements, following parameter is for WS2812
103+
bytes_encoder_config = (rmt_bytes_encoder_config_t) {
104+
.bit0 = {
105+
.level0 = 1,
106+
.duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us
107+
.level1 = 0,
108+
.duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us
109+
},
110+
.bit1 = {
111+
.level0 = 1,
112+
.duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us
113+
.level1 = 0,
114+
.duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us
115+
},
116+
.flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0
117+
};
118+
}
100119
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
101120
rmt_copy_encoder_config_t copy_encoder_config = {};
102121
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");

led_strip/src/led_strip_rmt_encoder.h

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <stdint.h>
99
#include "driver/rmt_encoder.h"
10+
#include "led_strip_types.h"
1011

1112
#ifdef __cplusplus
1213
extern "C" {
@@ -17,6 +18,7 @@ extern "C" {
1718
*/
1819
typedef struct {
1920
uint32_t resolution; /*!< Encoder resolution, in Hz */
21+
led_model_t led_model;
2022
} led_strip_encoder_config_t;
2123

2224
/**

0 commit comments

Comments
 (0)