FastLED 3.9.14
Loading...
Searching...
No Matches
led_strip_rmt_encoder.c
1
2#ifdef ESP32
3
4#include "enabled.h"
5
6#if FASTLED_RMT5
7
8#include "fl/unused.h"
9
10
11/*
12 * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
13 *
14 * SPDX-License-Identifier: Apache-2.0
15 */
16
17#include "esp_check.h"
18#include "led_strip_rmt_encoder.h"
19
20static const char *TAG = "led_rmt_encoder";
21
22typedef struct {
23 rmt_encoder_t base;
24 rmt_encoder_t *bytes_encoder;
25 rmt_encoder_t *copy_encoder;
26 int state;
27 rmt_symbol_word_t reset_code;
28} rmt_led_strip_encoder_t;
29
30static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
31{
32 rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
33 rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
34 rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;
35 rmt_encode_state_t session_state = 0;
36 rmt_encode_state_t state = 0;
37 size_t encoded_symbols = 0;
38 switch (led_encoder->state) {
39 case 0: // send RGB data
40 encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);
41 if (session_state & RMT_ENCODING_COMPLETE) {
42 led_encoder->state = 1; // switch to next state when current encoding session finished
43 }
44 if (session_state & RMT_ENCODING_MEM_FULL) {
45 state |= RMT_ENCODING_MEM_FULL;
46 goto out; // yield if there's no free space for encoding artifacts
47 }
48 // fall-through
49 case 1: // send reset code
50 encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code,
51 sizeof(led_encoder->reset_code), &session_state);
52 if (session_state & RMT_ENCODING_COMPLETE) {
53 led_encoder->state = 0; // back to the initial encoding session
54 state |= RMT_ENCODING_COMPLETE;
55 }
56 if (session_state & RMT_ENCODING_MEM_FULL) {
57 state |= RMT_ENCODING_MEM_FULL;
58 goto out; // yield if there's no free space for encoding artifacts
59 }
60 }
61out:
62 *ret_state = state;
63 return encoded_symbols;
64}
65
66static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder)
67{
68 rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
69 rmt_del_encoder(led_encoder->bytes_encoder);
70 rmt_del_encoder(led_encoder->copy_encoder);
71 free(led_encoder);
72 return ESP_OK;
73}
74
75static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)
76{
77 rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
78 rmt_encoder_reset(led_encoder->bytes_encoder);
79 rmt_encoder_reset(led_encoder->copy_encoder);
80 led_encoder->state = 0;
81 return ESP_OK;
82}
83
84
85esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
86{
87 esp_err_t ret = ESP_OK;
88 FASTLED_UNUSED(ret);
89 ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
90 ESP_GOTO_ON_FALSE(config->led_model < LED_MODEL_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led model");
91 // Create a temporary config with the same base values
92 led_strip_encoder_config_t timing_config = *config;
93 const bool has_encoder_timings = config->timings.t0h || config->timings.t0l || config->timings.t1h || config->timings.t1l || config->timings.reset;
94
95 if (!has_encoder_timings) {
96 // Set the timing values based on LED model
97 if (config->led_model == LED_MODEL_SK6812) {
98 timing_config.timings = (led_strip_encoder_timings_t) {
99 .t0h = 300, // 0.3us = 300ns
100 .t0l = 900, // 0.9us = 900ns
101 .t1h = 600, // 0.6us = 600ns
102 .t1l = 600, // 0.6us = 600ns
103 .reset = 280 // 280us
104 };
105 } else if (config->led_model == LED_MODEL_WS2812) {
106 timing_config.timings = (led_strip_encoder_timings_t) {
107 .t0h = 300, // 0.3us = 300ns
108 .t0l = 900, // 0.9us = 900ns
109 .t1h = 900, // 0.9us = 900ns
110 .t1l = 300, // 0.3us = 300ns
111 .reset = 280 // 280us
112 };
113 } else if (config->led_model == LED_MODEL_WS2811) {
114 timing_config.timings = (led_strip_encoder_timings_t) {
115 .t0h = 500, // 0.5us = 500ns
116 .t0l = 2000, // 2.0us = 2000ns
117 .t1h = 1200, // 1.2us = 1200ns
118 .t1l = 1300, // 1.3us = 1300ns
119 .reset = 50 // 50us
120 };
121 } else {
122 return ESP_ERR_INVALID_ARG;
123 }
124 }
125
126
127 // Delegate to the timing-based encoder creation
128 return rmt_new_led_strip_encoder_with_timings(&timing_config, ret_encoder);
129
130err:
131 return ESP_ERR_INVALID_ARG;
132}
133
134
135esp_err_t rmt_new_led_strip_encoder_with_timings(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder) {
136 esp_err_t ret = ESP_OK;
137 FASTLED_UNUSED(ret);
138 rmt_led_strip_encoder_t *led_encoder = NULL;
139 ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
140
141 led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t));
142 ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
143 led_encoder->base.encode = rmt_encode_led_strip;
144 led_encoder->base.del = rmt_del_led_strip_encoder;
145 led_encoder->base.reset = rmt_led_strip_encoder_reset;
146
147 // Convert nanosecond timings to ticks using resolution
148 rmt_bytes_encoder_config_t bytes_encoder_config = {
149 .bit0 = {
150 .level0 = 1,
151 .duration0 = (float)config->timings.t0h * config->resolution / 1000000000, // Convert ns to ticks
152 .level1 = 0,
153 .duration1 = (float)config->timings.t0l * config->resolution / 1000000000,
154 },
155 .bit1 = {
156 .level0 = 1,
157 .duration0 = (float)config->timings.t1h * config->resolution / 1000000000,
158 .level1 = 0,
159 .duration1 = (float)config->timings.t1l * config->resolution / 1000000000,
160 },
161 .flags.msb_first = 1
162 };
163
164 ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
165 rmt_copy_encoder_config_t copy_encoder_config = {};
166 ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
167
168 // Convert reset time from microseconds to ticks
169 uint32_t reset_ticks = config->resolution / 1000000 * config->timings.reset / 2;
170 led_encoder->reset_code = (rmt_symbol_word_t) {
171 .level0 = 0,
172 .duration0 = reset_ticks,
173 .level1 = 0,
174 .duration1 = reset_ticks,
175 };
176
177 *ret_encoder = &led_encoder->base;
178 return ESP_OK;
179err:
180 if (led_encoder) {
181 if (led_encoder->bytes_encoder) {
182 rmt_del_encoder(led_encoder->bytes_encoder);
183 }
184 if (led_encoder->copy_encoder) {
185 rmt_del_encoder(led_encoder->copy_encoder);
186 }
187 free(led_encoder);
188 }
189 return ret;
190}
191
192
193#endif // FASTLED_RMT5
194
195#endif // ESP32
Type of led strip encoder configuration.
led_strip_encoder_timings_t timings
LED strip encoder timings.