FastLED 3.9.13
Loading...
Searching...
No Matches
I2SClockLessLedDriveresp32s3.h
1
2#if !__has_include("esp_memory_utils.h")
3#error \
4 "esp_memory_utils.h is not available, are you using esp-idf 4.4 or earlier?"
5#else
6
7#pragma GCC diagnostic push
8#pragma GCC diagnostic ignored "-Wattributes"
9#pragma GCC diagnostic ignored "-Wvolatile"
10
11#include "esp_attr.h"
12#include "esp_check.h"
13#include "esp_heap_caps.h"
14#include "esp_intr_alloc.h"
15#include "esp_memory_utils.h"
16#include "esp_pm.h"
17#include <stdint.h>
18#include <stdio.h> // ok include
19#include <string.h>
20// #include "esp_lcd_panel_io_interface.h"
21// #include "esp_lcd_panel_io.h"
22#include "driver/gpio.h"
23#include "esp_memory_utils.h"
24#include "esp_private/gdma.h"
25#include "esp_rom_gpio.h"
26#include "hal/dma_types.h"
27#include "hal/gpio_hal.h"
28#include "soc/rtc.h" // for `rtc_clk_xtal_freq_get()`
29#include "soc/soc_caps.h"
30// #include "esp_private/periph_ctrl.h"
31
32// #include "esp_lcd_common.h"
33#include "hal/lcd_hal.h"
34#include "hal/lcd_ll.h"
35#include "soc/lcd_periph.h"
36
37#include "esp_heap_caps.h"
38#include "esp_lcd_panel_interface.h"
39#include "esp_lcd_panel_io.h"
40#include "esp_lcd_panel_io_interface.h"
41#include "esp_lcd_panel_ops.h"
42#include "esp_log.h"
43#include "esp_timer.h"
44#include "soc/gdma_reg.h"
45#include "platforms/esp/esp_version.h"
46
47#define IDF_5_3_OR_EARLIER (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0))
48
49// According to bug reports, this driver does not work well with the new WS2812-v5b. This is
50// probably due to the extrrra long reset time requirements of this chipset. so we put in
51// a hack that will always add 300 uS to the reset time.
52#define FASTLED_EXPERIMENTAL_YVES_EXTRA_WAIT_MICROS 300
53
54#ifndef NUMSTRIPS
55#define NUMSTRIPS 16
56#endif
57
58#ifndef SNAKEPATTERN
59#define SNAKEPATTERN 1
60#endif
61
62#ifndef ALTERNATEPATTERN
63#define ALTERNATEPATTERN 1
64#endif
65
66#define I2S_DEVICE 0
67
68#define AA (0x00AA00AAL)
69#define CC (0x0000CCCCL)
70#define FF (0xF0F0F0F0L)
71#define FF2 (0x0F0F0F0FL)
72
73#ifndef MIN
74#define MIN(a, b) (((a) < (b)) ? (a) : (b))
75#endif
76
77#define __OFFSET 0 // (24*3*2*2*2+2)
78
79#define __OFFSET_END (24 * 3 * 2 * 2 * 2 + 2)
80#ifndef HARDWARESPRITES
81#define HARDWARESPRITES 0
82#endif
83
84#if HARDWARESPRITES == 1
85#include "hardwareSprite.h"
86#endif
87
88#ifdef COLOR_ORDER_GRBW
89#define _p_r 1
90#define _p_g 0
91#define _p_b 2
92#define _nb_components 4
93#else
94#ifdef COLOR_ORDER_RGB
95#define _p_r 0
96#define _p_g 1
97#define _p_b 2
98#define _nb_components 3
99#else
100#ifdef COLOR_ORDER_RBG
101#define _p_r 0
102#define _p_g 2
103#define _p_b 1
104#define _nb_components 3
105#else
106#ifdef COLOR_ORDER_GBR
107#define _p_r 2
108#define _p_g 0
109#define _p_b 1
110#define _nb_components 3
111#else
112#ifdef COLOR_ORDER_BGR
113#define _p_r 2
114#define _p_g 1
115#define _p_b 0
116#define _nb_components 3
117#else
118#ifdef COLOR_ORDER_BRG
119#define _p_r 1
120#define _p_g 2
121#define _p_b 0
122#define _nb_components 3
123#else
124#ifdef COLOR_ORDER_GRB
125#define _p_r 1
126#define _p_g 0
127#define _p_b 2
128#define _nb_components 3
129#else
130
131#define _p_r 1
132#define _p_g 0
133#define _p_b 2
134#define _nb_components 3
135#endif
136#endif
137#endif
138#endif
139#endif
140#endif
141#endif
142
143#ifdef USE_PIXELSLIB
144// #include "pixelslib.h"
145#else
146#include "___pixeltypes.h"
147#endif
148
149#define LCD_DRIVER_PSRAM_DATA_ALIGNMENT 64
150#define CLOCKLESS_PIXEL_CLOCK_HZ (24 * 100 * 1000)
151
152namespace fl {
153
154static bool IRAM_ATTR flush_ready(esp_lcd_panel_io_handle_t panel_io,
155 esp_lcd_panel_io_event_data_t *edata,
156 void *user_ctx);
157
158typedef union {
159 uint8_t bytes[16];
160 uint32_t shorts[8];
161 uint32_t raw[2];
162} Lines;
163
164enum colorarrangment {
165 ORDER_GRBW,
166 ORDER_RGB,
167 ORDER_RBG,
168 ORDER_GRB,
169 ORDER_GBR,
170 ORDER_BRG,
171 ORDER_BGR,
172};
173
174enum displayMode {
175 NO_WAIT,
176 WAIT,
177 LOOP,
178 LOOP_INTERUPT,
179};
180
181bool DRIVER_READY = true;
182
183typedef struct led_driver_t led_driver_t;
184
185struct led_driver_t {
186 size_t (*init)();
187 void (*update)(uint8_t *colors, size_t len);
188};
189volatile xSemaphoreHandle I2SClocklessLedDriverS3_sem = NULL;
190volatile bool isDisplaying = false;
191volatile bool iswaiting = false;
192
193static void IRAM_ATTR transpose16x1_noinline2(unsigned char *A, uint16_t *B) {
194
195 uint32_t x, y, x1, y1, t;
196
197 y = *(unsigned int *)(A);
198#if NUMSTRIPS > 4
199 x = *(unsigned int *)(A + 4);
200#else
201 x = 0;
202#endif
203
204#if NUMSTRIPS > 8
205 y1 = *(unsigned int *)(A + 8);
206#else
207 y1 = 0;
208#endif
209#if NUMSTRIPS > 12
210 x1 = *(unsigned int *)(A + 12);
211#else
212 x1 = 0;
213#endif
214
215 // pre-transform x
216#if NUMSTRIPS > 4
217 t = (x ^ (x >> 7)) & AA;
218 x = x ^ t ^ (t << 7);
219 t = (x ^ (x >> 14)) & CC;
220 x = x ^ t ^ (t << 14);
221#endif
222#if NUMSTRIPS > 12
223 t = (x1 ^ (x1 >> 7)) & AA;
224 x1 = x1 ^ t ^ (t << 7);
225 t = (x1 ^ (x1 >> 14)) & CC;
226 x1 = x1 ^ t ^ (t << 14);
227#endif
228 // pre-transform y
229 t = (y ^ (y >> 7)) & AA;
230 y = y ^ t ^ (t << 7);
231 t = (y ^ (y >> 14)) & CC;
232 y = y ^ t ^ (t << 14);
233#if NUMSTRIPS > 8
234 t = (y1 ^ (y1 >> 7)) & AA;
235 y1 = y1 ^ t ^ (t << 7);
236 t = (y1 ^ (y1 >> 14)) & CC;
237 y1 = y1 ^ t ^ (t << 14);
238#endif
239 // final transform
240 t = (x & FF) | ((y >> 4) & FF2);
241 y = ((x << 4) & FF) | (y & FF2);
242 x = t;
243
244 t = (x1 & FF) | ((y1 >> 4) & FF2);
245 y1 = ((x1 << 4) & FF) | (y1 & FF2);
246 x1 = t;
247
248 *((uint16_t *)(B)) =
249 (uint16_t)(((x & 0xff000000) >> 8 | ((x1 & 0xff000000))) >> 16);
250 *((uint16_t *)(B + 3)) =
251 (uint16_t)(((x & 0xff0000) >> 16 | ((x1 & 0xff0000) >> 8)));
252 *((uint16_t *)(B + 6)) =
253 (uint16_t)(((x & 0xff00) | ((x1 & 0xff00) << 8)) >> 8);
254 *((uint16_t *)(B + 9)) = (uint16_t)((x & 0xff) | ((x1 & 0xff) << 8));
255 *((uint16_t *)(B + 12)) =
256 (uint16_t)(((y & 0xff000000) >> 8 | ((y1 & 0xff000000))) >> 16);
257 *((uint16_t *)(B + 15)) =
258 (uint16_t)(((y & 0xff0000) | ((y1 & 0xff0000) << 8)) >> 16);
259 *((uint16_t *)(B + 18)) =
260 (uint16_t)(((y & 0xff00) | ((y1 & 0xff00) << 8)) >> 8);
261 *((uint16_t *)(B + 21)) = (uint16_t)((y & 0xff) | ((y1 & 0xff) << 8));
262}
263
264esp_lcd_panel_io_handle_t led_io_handle = NULL;
265
266class I2SClocklessLedDriveresp32S3 {
267
268 public:
269 int testcount;
270 uint16_t *buffers[2];
271 uint16_t *led_output = NULL;
272 uint16_t *led_output2 = NULL;
273 uint8_t *ledsbuff = NULL;
274 int num_leds_per_strip;
275 int _numstrips;
276 int currentframe;
277
278 uint8_t __green_map[256];
279 uint8_t __blue_map[256];
280 uint8_t __red_map[256];
281 uint8_t __white_map[256];
282 uint8_t _brightness;
283 float _gammar, _gammab, _gammag, _gammaw;
284
285 void setBrightness(int brightness) {
286 _brightness = brightness;
287 float tmp;
288 for (int i = 0; i < 256; i++) {
289 tmp = powf((float)i / 255, 1 / _gammag);
290 __green_map[i] = (uint8_t)(tmp * brightness);
291 tmp = powf((float)i / 255, 1 / _gammag);
292 __blue_map[i] = (uint8_t)(tmp * brightness);
293 tmp = powf((float)i / 255, 1 / _gammag);
294 __red_map[i] = (uint8_t)(tmp * brightness);
295 tmp = powf((float)i / 255, 1 / _gammag);
296 __white_map[i] = (uint8_t)(tmp * brightness);
297 }
298 }
299
300 void setGamma(float gammar, float gammab, float gammag, float gammaw) {
301 _gammag = gammag;
302 _gammar = gammar;
303 _gammaw = gammaw;
304 _gammab = gammab;
305 setBrightness(_brightness);
306 }
307
308 void setGamma(float gammar, float gammab, float gammag) {
309 _gammag = gammag;
310 _gammar = gammar;
311 _gammab = gammab;
312 setBrightness(_brightness);
313 }
314
315 void _initled(uint8_t *leds, const int *pins, int numstrip,
316 int NUM_LED_PER_STRIP) {
317
318 // esp_lcd_panel_io_handle_t init_lcd_driver(unsigned int
319 // CLOCKLESS_PIXEL_CLOCK_HZ, size_t _nb_components) {
320
321 esp_lcd_i80_bus_handle_t i80_bus = NULL;
322
323 esp_lcd_i80_bus_config_t bus_config;
324
325 bus_config.clk_src = LCD_CLK_SRC_PLL160M;
326 bus_config.dc_gpio_num = 0;
327 bus_config.wr_gpio_num = 0;
328 // bus_config.data_gpio_nums = (int*)malloc(16*sizeof(int));
329 for (int i = 0; i < numstrip; i++) {
330 bus_config.data_gpio_nums[i] = pins[i];
331 }
332 if (numstrip < 16) {
333 for (int i = numstrip; i < 16; i++) {
334 bus_config.data_gpio_nums[i] = 0;
335 }
336 }
337 bus_config.bus_width = 16;
338 bus_config.max_transfer_bytes =
339 _nb_components * NUM_LED_PER_STRIP * 8 * 3 * 2 + __OFFSET;
340 #if IDF_5_3_OR_EARLIER
341 #pragma GCC diagnostic push
342 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
343 #endif
344 // In IDF 5.3, psram_trans_align became deprecated. We kick the can down
345 // the road a little bit and suppress the warning until idf 5.4 arrives.
346 bus_config.psram_trans_align = LCD_DRIVER_PSRAM_DATA_ALIGNMENT;
347 bus_config.sram_trans_align = 4;
348 #if IDF_5_3_OR_EARLIER
349 #pragma GCC diagnostic pop
350 #endif
351
352 ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
353
354 esp_lcd_panel_io_i80_config_t io_config;
355
356 io_config.cs_gpio_num = -1;
357 io_config.pclk_hz = CLOCKLESS_PIXEL_CLOCK_HZ;
358 io_config.trans_queue_depth = 1;
359 io_config.dc_levels = {
360 .dc_idle_level = 0,
361 .dc_cmd_level = 0,
362 .dc_dummy_level = 0,
363 .dc_data_level = 1,
364 };
365 //.on_color_trans_done = flush_ready,
366 // .user_ctx = nullptr,
367 io_config.lcd_cmd_bits = 0;
368 io_config.lcd_param_bits = 0;
369 io_config.user_ctx = this;
370
371 io_config.on_color_trans_done = flush_ready;
372 ESP_ERROR_CHECK(
373 esp_lcd_new_panel_io_i80(i80_bus, &io_config, &led_io_handle));
374 }
375
376 void initled(uint8_t *leds, const int *pins, int numstrip,
377 int NUM_LED_PER_STRIP) {
378 currentframe = 0;
379 _gammab = 1;
380 _gammar = 1;
381 _gammag = 1;
382 _gammaw = 1;
383 setBrightness(255);
384 if (I2SClocklessLedDriverS3_sem == NULL) {
385 I2SClocklessLedDriverS3_sem = xSemaphoreCreateBinary();
386 }
387 // esp_lcd_panel_io_handle_t init_lcd_driver(unsigned int
388 // CLOCKLESS_PIXEL_CLOCK_HZ, size_t _nb_components) {
389 led_output = (uint16_t *)heap_caps_aligned_alloc(
390 LCD_DRIVER_PSRAM_DATA_ALIGNMENT,
391 8 * _nb_components * NUM_LED_PER_STRIP * 3 * 2 + __OFFSET +
392 __OFFSET_END,
393 MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
394 memset(led_output, 0,
395 8 * _nb_components * NUM_LED_PER_STRIP * 3 * 2 + __OFFSET +
396 __OFFSET_END);
397
398 led_output2 = (uint16_t *)heap_caps_aligned_alloc(
399 LCD_DRIVER_PSRAM_DATA_ALIGNMENT,
400 8 * _nb_components * NUM_LED_PER_STRIP * 3 * 2 + __OFFSET +
401 __OFFSET_END,
402 MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
403 memset(led_output2, 0,
404 8 * _nb_components * NUM_LED_PER_STRIP * 3 * 2 + __OFFSET +
405 __OFFSET_END);
406 buffers[0] = led_output;
407 buffers[1] = led_output2;
408 // led_output[0] = 0xFFFF; //the +1 because it's like the first value
409 // doesnt get pushed do not ask me why for now
410 // led_output2[0] = 0xFFFF;
411 led_output2 += __OFFSET / 2;
412 led_output += __OFFSET / 2;
413
414 for (int i = 0; i < NUM_LED_PER_STRIP * _nb_components * 8; i++) {
415 led_output[3 * i + 1] =
416 0xFFFF; // the +1 because it's like the first value doesnt get
417 // pushed do not ask me why for now
418 led_output2[3 * i + 1] = 0xFFFF;
419 }
420 ledsbuff = leds;
421 _numstrips = numstrip;
422 num_leds_per_strip = NUM_LED_PER_STRIP;
423 _initled(leds, pins, numstrip, NUM_LED_PER_STRIP);
424 }
425
426 void transposeAll(uint16_t *ledoutput) {
427
428 uint16_t ledToDisplay = 0;
429 Lines secondPixel[_nb_components];
430 uint16_t *buff =
431 ledoutput + 2; //+1 pour le premier empty +1 pour le 1 systématique
432 uint16_t jump = num_leds_per_strip * _nb_components;
433 for (int j = 0; j < num_leds_per_strip; j++) {
434 uint8_t *poli = ledsbuff + ledToDisplay * _nb_components;
435 for (int i = 0; i < _numstrips; i++) {
436
437 secondPixel[_p_g].bytes[i] = __green_map[*(poli + 1)];
438 secondPixel[_p_r].bytes[i] = __red_map[*(poli + 0)];
439 secondPixel[_p_b].bytes[i] = __blue_map[*(poli + 2)];
440 if (_nb_components > 3)
441 secondPixel[3].bytes[i] = __white_map[*(poli + 3)];
442 // #endif
443 poli += jump;
444 }
445 ledToDisplay++;
446 transpose16x1_noinline2(secondPixel[0].bytes, buff);
447 buff += 24;
448 transpose16x1_noinline2(secondPixel[1].bytes, buff);
449 buff += 24;
450 transpose16x1_noinline2(secondPixel[2].bytes, buff);
451 buff += 24;
452 if (_nb_components > 3) {
453 transpose16x1_noinline2(secondPixel[3].bytes, buff);
454 buff += 24;
455 }
456 }
457 }
458
459 void show() {
460 transposeAll(buffers[currentframe]);
461 if (isDisplaying) {
462 // Serial.println("on display dejà");
463 iswaiting = true;
464 if (I2SClocklessLedDriverS3_sem == NULL)
465 I2SClocklessLedDriverS3_sem = xSemaphoreCreateBinary();
466 xSemaphoreTake(I2SClocklessLedDriverS3_sem, portMAX_DELAY);
467 }
468 isDisplaying = true;
469
470 if (FASTLED_EXPERIMENTAL_YVES_EXTRA_WAIT_MICROS) {
471 delayMicroseconds(FASTLED_EXPERIMENTAL_YVES_EXTRA_WAIT_MICROS);
472 }
473
474 led_io_handle->tx_color(led_io_handle, 0x2C, buffers[currentframe],
475 _nb_components * num_leds_per_strip * 8 * 3 *
476 2 +
477 __OFFSET + __OFFSET_END);
478
479 currentframe = (currentframe + 1) % 2;
480 }
481};
482
483static bool IRAM_ATTR flush_ready(esp_lcd_panel_io_handle_t panel_io,
484 esp_lcd_panel_io_event_data_t *edata,
485 void *user_ctx) {
486 // printf("we're here");
487 DRIVER_READY = true;
488 isDisplaying = false;
489 I2SClocklessLedDriveresp32S3 *cont =
490 (I2SClocklessLedDriveresp32S3 *)user_ctx;
491 cont->testcount++;
492 if (iswaiting) {
493 portBASE_TYPE HPTaskAwoken = 0;
494 iswaiting = false;
495 xSemaphoreGiveFromISR(I2SClocklessLedDriverS3_sem, &HPTaskAwoken);
496 if (HPTaskAwoken == pdTRUE)
497 portYIELD_FROM_ISR(HPTaskAwoken);
498 }
499 return false;
500}
501
502#pragma GCC diagnostic pop
503
504} // namespace fl
505
506#endif // __has_include("esp_memory_utils.h")
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16