Skip to content

Commit 89a419b

Browse files
committed
Change default to I2S driver, explain how to use RMT if you really want to
1 parent 8f0da6f commit 89a419b

File tree

5 files changed

+261
-55
lines changed

5 files changed

+261
-55
lines changed

README.md

Lines changed: 88 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
This port of FastLED 3.3 runs under the 4.x ESP-IDF development environment. Enjoy.
66

77
Updates: Aug, Sept 2020:
8+
- I2S hardware working and now default.
89
- RMT interface well tested.
910
- WS2812FX library ported and working.
10-
- I2S hardware working ( see below )
1111

1212
There are some new tunables, and if you're also fighting glitches, you need to read `components/FastLED-idf/ESP-IDF.md`.
1313

@@ -58,10 +58,8 @@ At first, I focused the port on RMT, as it seemed the hardware everyone talked a
5858
below, the RMT interface even has a Espressif provided example! Thus the journey of getting the MEM_BUFS
5959
code working and soak up the interrupt latency.
6060

61-
But, the I2S hardware is almost certainly cooler than RMT. It has more parallelism, and less code.
62-
63-
Right now, the code is still checked in with default RMT simply because I haven't tested I2S as much,
64-
but please see the I2S section below on enabling it.
61+
But, the I2S hardware is almost certainly better than RMT. It has more parallelism, and less code,
62+
and seems enormously resistant to glitches. The default is I2S, see below.
6563

6664
# TL;DR about this repo
6765

@@ -79,6 +77,8 @@ For master, either use the standard `sdkconfig` or build your own. Remove this o
7977
and `idf.py menuconfig`, and set whatever paramenters you need. There is
8078
nothing in this library that's specific to any particular version.
8179

80+
I tend to set the compiler into -O2 mode.
81+
8282
# a note about level shifting
8383

8484
I've now read a lot of reddit posts about people saying "but I hook LEDs up to an Arudino and it works,
@@ -90,8 +90,66 @@ and using a 4-pin package isn't so cool as an 8 pin package, since an ESP32 can
9090
8 channels. That's SN74HCT245N , and they're to be had from Digikey at $0.60. Read the datasheet
9191
carefully and get the direction and the enable pins right - they can't float.
9292

93+
# Use of ESP32 I2S hardware for 3 wire LEDs
94+
95+
## this is really good
96+
97+
Mid 2019, The following post showed up on reddit:
98+
https://www.reddit.com/r/FastLED/comments/bjq0sm/new_24way_parallel_driver_for_esp32/
99+
which announced using I2S hardware instead of RMT hardware that had been used in the past.
100+
101+
I2S hardware is aimed to generate sound, but it can also be configured (as it is in this case)
102+
to provide a parallel bus interface. It is best understood by reading the Espressif documentation.
103+
104+
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html
105+
106+
What you'll see is there's 12 parallel pins that can be supported with each hardware module,
107+
and frankly if you need more than 12 way parallelism I worry about you. That should be enough
108+
for a module of this size.
109+
110+
## Which to use?
111+
112+
From Sam's post: WARNINGS and LIMITATIONS
113+
114+
-- **All strips must use the same clockless chip (e.g., WS2812)**. Due to the way the I2S peripheral works, it would be much more complicated to drive strips that have different timing parameters, so we punted on it. If you need to use multiple strips with different chips, use the default RMT-base driver.
115+
116+
-- Yves has written some mad code to compute the various clock dividers, so that the output is timing-accurate. If you see timing problems, however, let us know.
117+
118+
-- This is new software. We tested it on our machines. If you find bugs or other issues, please let us know!
119+
120+
Of course, new in 2019 is not so new now :-).
121+
122+
I have set the default to I2S, because it ran all of my torture tests immediately and flawlessly.
123+
I am somewhat unclear why it's so good. It's hard to suss out how deep the DMA queue is at a glance in time,
124+
and it seems that the interupt handler might be running at a different priority. I don't know
125+
if I can argue that it's doing less work. Since it's written for audio, there might be more
126+
attention paid to the driver.
127+
128+
Obviously, if you need the I2S hardware for something else, you'll want RMT, but there are two I2S components
129+
on an ESP32 and one on a ESP32-S2. The other uses of I2S include ( according to the documentation ) LCD
130+
master transmitting mode, camera slave receiving mode, and ADC / DAC mode ( feed directly to the DAC for output ).
131+
132+
You can still fall back to RMT, see below.
133+
134+
## the code is a little inscrutable
135+
136+
The I2S code uses the underlying hardware interface ( `ll` ) fast and furious. For this reason, nothing
137+
you see in the official documentation about I2S matches what the code is written to. Just to beware.
138+
93139
# Use of ESP32 RMT hardware for 3 wire LEDs
94140

141+
## Cookbook - enable it
142+
143+
There's a `#define` at the top of fastled.h which chooses I2S or RMT. Switch to RMT by commenting out.
144+
145+
Comment back in `"platforms/esp/32/clockless_rmt_esp32.cpp"` from `components\FastLED-idf\CMakeLists.txt`
146+
147+
To compile the default I2S, you need to remove the RMT file from the compile because you don't want to waste RAM,
148+
and there are colliding symbols. You can't use both because there's no current way to define which strings
149+
use which hardware. If there was a new interface, you'd fix the colliding symbols and enable both.
150+
151+
## background
152+
95153
The ESP32 has an interesting module, called RMT. It's a module that's
96154
meant to make arbitrary waveforms on pins, without having to bang each pin at
97155
the right time. While it was made for IR Remote Control devices,
@@ -117,29 +175,9 @@ The FastLED ESP32 RMT use has two modes: one which uses the "driver", and
117175
one which doesn't, and claims to be more efficient due to when it's converting
118176
between LED RGB and not.
119177

120-
Whether you can use the "direct" mode or not depends on whether you have other
121-
users of the RMT driver within ESP-IDF.
122-
123-
Essentially, if you have the Driver turned on, you shouldn't use the direct mode,
124-
and if you want to use the direct mode, you should turn off the driver.
125-
126-
No extra commands in `menuconfig` seem necessary.
127-
128-
# Use of ESP32 I2S hardware for 3 wire LEDs
129-
130-
## TL;DR enable it
131-
132-
There's a `#define` at the top of fastled.h which chooses I2S or RMT. Switch to I2S.
133-
134-
Comment out `"platforms/esp/32/clockless_rmt_esp32.cpp"` from `components\FastLED-idf\CMakeLists.txt`
178+
The ESP-IDF driver does support a `translate` mode which would be the same as what
179+
the internal mode does.
135180

136-
You need to remove the RMT file from the compile because you don't want to waste RAM, and there
137-
are colliding symbols. You can't use both because there's no current way to define which strings
138-
use which hardware.
139-
140-
## Which to use?
141-
142-
Not sure yet. Going to play with it on different builds and see what works.
143181

144182
# Four wire LEDs ( APA102 and similar )
145183

@@ -148,8 +186,11 @@ the clock and data lines have to be controled together ( duh ),
148186
and the RMT interface doesn't do that. What does do that is the SPI
149187
interface, and I don't think I've wired that up.
150188

151-
There are two hardware SPI ports in the system, so that should be
152-
able to be enabled. Work to do.
189+
The I2S interface, on the other hand, appears synchronized. I think you could
190+
write an APA102 driver using I2S and it would be fast and happy.
191+
192+
However, simply doing hardware SPI using the single SPI driver should be good enough.
193+
Work to do.
153194

154195
Since hardware banging is used ( that's the big ugly warning ),
155196
these LEDs are very likely far slower, and probably do not respond to parallelism
@@ -210,15 +251,6 @@ Within menuconfig, I tend to use the following settings. Minimum required silico
210251
are speed workarounds at Rev0 that get compiled in. I change the compiler options to -O2 instead of -Os or -Og.
211252
Default flash size to 4M, because all the devices I have are 4G.
212253

213-
Second of all, there be some dragons in the different versions.
214-
215-
The FastLed RMT code runs in two different modes - it either uses an onboard driver, or it uses the ESP-IDF RMT driver.
216-
I've found that if you use the driver that was originally written for FastLED, it works great with ESP-IDF 4.0,
217-
but crashes horribly in 4.2 and master. These are interesting branches because the new S2 version of the ESP32
218-
chip requires those branches.
219-
220-
It's quite possible that more and more changes will creep in, or that someone will find the flaw that's causing 4.2
221-
to crash.
222254

223255
# A short plug for Microsoft's WSL
224256

@@ -251,17 +283,21 @@ There is an example of LED control, using the RMT interface directly.
251283
If you just want to it like that, without all the cool stuff in FastLED,
252284
be everyone's guest!
253285

286+
Interestingly, the LED library uses RMT, has glitches just like the older versions of RMT
287+
that FastLED had, and don't support I2S which is far more stable.
288+
254289
I did reach out to Espressif. I think they should include or have a FastLED port.
255290
In their forums, they said they don't intend to do anything like that.
256291

257292
## SamGuyer's fork
258293

259-
According to a reddit post, someone named Sam Guyer fixed the issues with FastLED. There are
260-
a number of fundamental problems that Sam has been gnawing on, notably the access to flash
261-
that happens when you 'read files'. His fork was my starting point.
294+
When I started on this journey, I read a series of Reddit posts saying that Sam's
295+
FastLED port was the best for ESP32. It used RMT by default, and it still glitched
296+
a lot, which put me down the path of doing major work on the RMT code
297+
and finding the fundamental issue which he backported.
262298

263-
However, I found that the primarily issue with visual artifacts in RMT had to do with
264-
the amount of ESP-IDF jitter.
299+
The code for the I2S driver, however, just came over peachy, and once I enabled it,
300+
the entire system was far more stable.
265301

266302
Kudos to Sam for getting the code to a better point, where it was amenable to the optimizations
267303
I did.
@@ -275,6 +311,9 @@ is a function which will take pixel bytes to RMT buffers. This is the structure
275311
code already, so the entire ISR can be removed. This functionality is not in the Arduino
276312
implementation of RMT, which is why its not used here yet.
277313

314+
However, now that one has the I2S code, I would think improving the RMT code is
315+
a low priority.
316+
278317
# Updating
279318

280319
This package basically depends on three packages: two that you pull in,
@@ -314,7 +353,7 @@ and still, potentially, have the ability to do some extra work, because you've g
314353
I have not determined if this is using the RMT interface, which would mean we could
315354
use an async internal interface. The timing, however, is very solid.
316355

317-
# Use notes
356+
# Use(age) notes
318357

319358
What I like about using FreeRTOS and a more interesting development environment is
320359
you should be able to use more of the CPU for other things. Essentially, you should
@@ -339,7 +378,9 @@ that would be under MIT license.
339378

340379
I am honestly not sure what happens to LGPL in this case. It's a component in an
341380
embedded system, which is morally a library, but it is clearly very statically
342-
linked.
381+
linked and in the "application", which I think would generate a copy-left. OTOH,
382+
that would also mean that ESP-IDF is all GPL and copy-left, and Espressif
383+
doesn't seem to think so ... whatever.
343384

344385
I don't intend to make any money off this, don't charge people, and do not intend
345386
the use for commercial art projects, so the use is safe for me. But don't say
@@ -482,10 +523,6 @@ Note: what's up with registering the driver? I should, right? Make sure that's d
482523
menuconfig? Doen't seem to be. There are no settings anywhere in the menuconfig regarding
483524
gpio. Should probably look at the examples to see if I have to enable the ISR or something.
484525

485-
## using RMT vs I2S
486-
487-
Note to self: There is a define in the platforms area that lets a person choose.
488-
489526
## GCC 8 memcpy and memmove into complex structures
490527

491528
```
@@ -559,9 +596,8 @@ gpio.c out of the hal compile.
559596

560597
The code in ESP-IDF seems to really like using the pattern of having a macro for a
561598
default constructor. In the case of initializing the RMT structure, if I did it "by hand"
562-
and used the -O2 compile option, I got instability. When I switched to using their
563-
constructure, which seems the same to me generally, I get a stable build. I
564-
now wonder if this was some of the issue around not using the IRQ....
599+
and used the -O2 compile option, I got instability. The code is now written to
600+
do different things in different versions.
565601

566602
## issues regarding ESP-IDF 4.1 and private interrupt handler
567603

components/FastLED-idf/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ set(srcs
1414
"hal/esp32-hal-misc.c"
1515
"hal/esp32-hal-gpio.c"
1616
# remove the following if you want I2S instead of RMT hardware, just put a pound in front
17-
"platforms/esp/32/clockless_rmt_esp32.cpp"
17+
# "platforms/esp/32/clockless_rmt_esp32.cpp"
1818
)
1919

2020
# everything needs the ESP32 flag, not sure why this won't work

components/FastLED-idf/FastLED.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
// prefer I2S? Comment this in.
1212
// Not the default because haven't tried it as much, does work
13-
// #define FASTLED_ESP32_I2S
13+
#define FASTLED_ESP32_I2S
1414

1515
#include "esp32-hal.h"
1616

components/FastLED-idf/platforms/esp/32/clockless_i2s_esp32.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,9 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER>
519519
// -- Allocate i2s interrupt
520520
SET_PERI_REG_BITS(I2S_INT_ENA_REG(I2S_DEVICE), I2S_OUT_EOF_INT_ENA_V, 1, I2S_OUT_EOF_INT_ENA_S);
521521
ESP_ERROR_CHECK(
522-
esp_intr_alloc(interruptSource, 0 /* ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL3*/,
522+
// this seems to work great with the default 0 flag, but everything is in IRAM
523+
// so why not raise it a little? Because you'll get a panic, and I'm not sure why.
524+
esp_intr_alloc(interruptSource, 0 /* ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL2 */,
523525
&interruptHandler, 0, &gI2S_intr_handle)
524526
);
525527

0 commit comments

Comments
 (0)