FastLED 3.9.14
Loading...
Searching...
No Matches
led_strip_rmt_dev.c
1
2
3#ifdef ESP32
4
5#include "enabled.h"
6
7#if FASTLED_RMT5
8
9#include "fl/unused.h"
10
11
12/*
13 * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
14 *
15 * SPDX-License-Identifier: Apache-2.0
16 */
17#include <stdlib.h>
18#include <string.h>
19#include <sys/cdefs.h>
20#include "esp_log.h"
21#include "esp_check.h"
22#include "driver/rmt_tx.h"
23#include "led_strip.h"
24#include "led_strip_interface.h"
25#include "led_strip_rmt_encoder.h"
26
27#define LED_STRIP_RMT_DEFAULT_RESOLUTION 10000000 // 10MHz resolution
28#define LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE 4
29
30#ifndef LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS_MULTIPLIER
31#if CONFIG_IDF_TARGET_ESP32C3
32// Fixes https://github.com/FastLED/FastLED/issues/1846
33#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS_MULTIPLIER 2
34#else
35#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS_MULTIPLIER 1
36#endif
37#endif
38
39// the memory size of each RMT channel, in words (4 bytes)
40#ifndef LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS
41#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
42#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS (LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS_MULTIPLIER * 64)
43#else
44#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS (LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS_MULTIPLIER * 48)
45#endif
46#endif
47
48
49static const char *TAG = "led_strip_rmt";
50
51typedef struct {
52 led_strip_t base;
53 rmt_channel_handle_t rmt_chan;
54 rmt_encoder_handle_t strip_encoder;
55 uint32_t strip_len;
56 uint8_t bytes_per_pixel;
57 led_color_component_format_t component_fmt;
58 uint8_t pixel_buf[];
59} led_strip_rmt_obj;
60
61static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
62{
63 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
64 ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
65
66 led_color_component_format_t component_fmt = rmt_strip->component_fmt;
67 uint32_t start = index * rmt_strip->bytes_per_pixel;
68 uint8_t *pixel_buf = rmt_strip->pixel_buf;
69
70 pixel_buf[start + component_fmt.format.r_pos] = red & 0xFF;
71 pixel_buf[start + component_fmt.format.g_pos] = green & 0xFF;
72 pixel_buf[start + component_fmt.format.b_pos] = blue & 0xFF;
73 if (component_fmt.format.num_components > 3) {
74 pixel_buf[start + component_fmt.format.w_pos] = 0;
75 }
76
77 return ESP_OK;
78}
79
80static 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)
81{
82 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
83 led_color_component_format_t component_fmt = rmt_strip->component_fmt;
84 ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
85 ESP_RETURN_ON_FALSE(component_fmt.format.num_components == 4, ESP_ERR_INVALID_ARG, TAG, "led doesn't have 4 components");
86
87 uint32_t start = index * rmt_strip->bytes_per_pixel;
88 uint8_t *pixel_buf = rmt_strip->pixel_buf;
89
90 pixel_buf[start + component_fmt.format.r_pos] = red & 0xFF;
91 pixel_buf[start + component_fmt.format.g_pos] = green & 0xFF;
92 pixel_buf[start + component_fmt.format.b_pos] = blue & 0xFF;
93 pixel_buf[start + component_fmt.format.w_pos] = white & 0xFF;
94
95 return ESP_OK;
96}
97
98static esp_err_t led_strip_rmt_refresh_async(led_strip_t *strip)
99{
100 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
101 rmt_transmit_config_t tx_conf = {
102 .loop_count = 0,
103 };
104
105 ESP_RETURN_ON_ERROR(rmt_enable(rmt_strip->rmt_chan), TAG, "enable RMT channel failed");
106 ESP_RETURN_ON_ERROR(rmt_transmit(rmt_strip->rmt_chan, rmt_strip->strip_encoder, rmt_strip->pixel_buf,
107 rmt_strip->strip_len * rmt_strip->bytes_per_pixel, &tx_conf), TAG, "transmit pixels by RMT failed");
108 return ESP_OK;
109}
110
111static esp_err_t led_strip_rmt_wait_for_done(led_strip_t *strip)
112{
113 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
114 ESP_RETURN_ON_ERROR(rmt_tx_wait_all_done(rmt_strip->rmt_chan, -1), TAG, "wait for RMT done failed");
115 ESP_RETURN_ON_ERROR(rmt_disable(rmt_strip->rmt_chan), TAG, "disable RMT channel failed");
116 return ESP_OK;
117}
118
119static esp_err_t led_strip_rmt_refresh(led_strip_t *strip)
120{
121 ESP_RETURN_ON_ERROR(led_strip_rmt_refresh_async(strip), TAG, "refresh async failed");
122 ESP_RETURN_ON_ERROR(led_strip_rmt_wait_for_done(strip), TAG, "wait for done failed");
123 return ESP_OK;
124}
125
126static esp_err_t led_strip_rmt_clear(led_strip_t *strip)
127{
128 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
129 // Write zero to turn off all leds
130 memset(rmt_strip->pixel_buf, 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel);
131 return led_strip_rmt_refresh(strip);
132}
133
134static esp_err_t led_strip_rmt_del(led_strip_t *strip)
135{
136 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
137 ESP_RETURN_ON_ERROR(rmt_del_channel(rmt_strip->rmt_chan), TAG, "delete RMT channel failed");
138 ESP_RETURN_ON_ERROR(rmt_del_encoder(rmt_strip->strip_encoder), TAG, "delete strip encoder failed");
139 free(rmt_strip);
140 return ESP_OK;
141}
142
143esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *rmt_config, led_strip_handle_t *ret_strip)
144{
145 led_strip_rmt_obj *rmt_strip = NULL;
146 esp_err_t ret = ESP_OK;
147 FASTLED_UNUSED(ret);
148 ESP_GOTO_ON_FALSE(led_config && rmt_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
149 led_color_component_format_t component_fmt = led_config->color_component_format;
150 // If R/G/B order is not specified, set default GRB order as fallback
151 if (component_fmt.format_id == 0) {
152 component_fmt = LED_STRIP_COLOR_COMPONENT_FMT_GRB;
153 }
154 // check the validation of the color component format
155 uint8_t mask = 0;
156 if (component_fmt.format.num_components == 3) {
157 mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos);
158 // Check for invalid values
159 ESP_RETURN_ON_FALSE(mask == 0x07, ESP_ERR_INVALID_ARG, TAG, "invalid order argument");
160 } else if (component_fmt.format.num_components == 4) {
161 mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos) | BIT(component_fmt.format.w_pos);
162 // Check for invalid values
163 ESP_RETURN_ON_FALSE(mask == 0x0F, ESP_ERR_INVALID_ARG, TAG, "invalid order argument");
164 } else {
165 ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "invalid number of color components: %d", component_fmt.format.num_components);
166 }
167 // TODO: we assume each color component is 8 bits, may need to support other configurations in the future, e.g. 10bits per color component?
168 uint8_t bytes_per_pixel = component_fmt.format.num_components;
169 rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel);
170 ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt strip");
171 uint32_t resolution = rmt_config->resolution_hz ? rmt_config->resolution_hz : LED_STRIP_RMT_DEFAULT_RESOLUTION;
172
173 // for backward compatibility, if the user does not set the clk_src, use the default value
174 rmt_clock_source_t clk_src = RMT_CLK_SRC_DEFAULT;
175 if (rmt_config->clk_src) {
176 clk_src = rmt_config->clk_src;
177 }
178 size_t mem_block_symbols = LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS;
179 // override the default value if the user sets it
180 if (rmt_config->mem_block_symbols) {
181 mem_block_symbols = rmt_config->mem_block_symbols;
182 }
183 rmt_tx_channel_config_t rmt_chan_config = {
184 .clk_src = clk_src,
185 .gpio_num = led_config->strip_gpio_num,
186 .mem_block_symbols = mem_block_symbols,
187 .resolution_hz = resolution,
188 .trans_queue_depth = LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE,
189 .flags.with_dma = rmt_config->flags.with_dma,
190 .flags.invert_out = led_config->flags.invert_out,
191 };
192 ESP_GOTO_ON_ERROR(rmt_new_tx_channel(&rmt_chan_config, &rmt_strip->rmt_chan), err, TAG, "create RMT TX channel failed");
193
194 led_strip_encoder_config_t strip_encoder_conf = {
195 .resolution = resolution,
196 .led_model = led_config->led_model,
197 .timings = led_config->timings,
198 };
199 ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, "create LED strip encoder failed");
200
201 rmt_strip->component_fmt = component_fmt;
202 rmt_strip->bytes_per_pixel = bytes_per_pixel;
203 rmt_strip->strip_len = led_config->max_leds;
204 rmt_strip->base.set_pixel = led_strip_rmt_set_pixel;
205 rmt_strip->base.set_pixel_rgbw = led_strip_rmt_set_pixel_rgbw;
206 rmt_strip->base.refresh = led_strip_rmt_refresh;
207 rmt_strip->base.refresh_async = led_strip_rmt_refresh_async;
208 rmt_strip->base.refresh_wait_done = led_strip_rmt_wait_for_done;
209 rmt_strip->base.clear = led_strip_rmt_clear;
210 rmt_strip->base.del = led_strip_rmt_del;
211
212 *ret_strip = &rmt_strip->base;
213 return ESP_OK;
214err:
215 if (rmt_strip) {
216 if (rmt_strip->rmt_chan) {
217 rmt_del_channel(rmt_strip->rmt_chan);
218 }
219 if (rmt_strip->strip_encoder) {
220 rmt_del_encoder(rmt_strip->strip_encoder);
221 }
222 free(rmt_strip);
223 }
224 return ret;
225}
226
227#endif // FASTLED_RMT5
228
229#endif // ESP32
LED Strip common configurations The common configurations are not specific to any backend peripheral.
led_color_component_format_t color_component_format
struct led_strip_config_t::led_strip_extra_flags flags
led_strip_encoder_timings_t timings
Type of led strip encoder configuration.
LED Strip RMT specific configuration.
struct led_strip_rmt_config_t::led_strip_rmt_extra_config flags
rmt_clock_source_t clk_src
LED strip interface definition.
LED color component format.
struct led_color_component_format_t::format_layout format