Makuna / NeoPixelBus

An Arduino NeoPixel support library supporting a large variety of individually addressable LEDs. Please refer to the Wiki for more details. Please use the GitHub Discussions to ask questions as the GitHub Issues feature is used for bug tracking.
GNU Lesser General Public License v3.0
1.18k stars 264 forks source link

Update WS2812X ESP32 RMT timing for WS2815 compat #795

Open rmounce opened 7 months ago

rmounce commented 7 months ago

Context

I'm using WLED and have been trying to troubleshoot flickering issues for a while now with my WS2815 LED strips from BTF-Lighting. I have about 6 metres of cable between my controller and each strip, and have taken the following measures so far:

IMG_0180 Large

These efforts cleaned up the data signal and reduced flickering considerably, but it never went away until I upgraded to WLED 0.15 beta. This finally fixed the flickering for one of my two LED strips! A bit more investigation showed that WLED changed to I2S by default for the first output, which has different timing to RMT. And reading the WS2815 datasheet showed that the RMT timing for WS2812B is out of the specs for WS2812.

Commit Summary

The existing values are out of spec for WS2815 which results in flickering, especially on longer cable runs.

These new RMT values are still closer to ideal WS2812B specs than the current I2S WS2812X timing (about 310us / 940us).

Datasheet specs: T0H T1H T0L T1L
WS2812B 250-550 650-950 700-1000 300-600
WS2815 220-380 580-1600 580-1600 220-420

Note for ESP32 WLED users interested in this PR

To resolve flickering issues in the meantime, upgrade to WLED 0.15 beta. For more than 1 output, this also adds APA106 support which uses compatible timings with WS2815 on the second output.

WLED 0.15 with WS2815 LED Mode WS281X Mode APA106
Output 1 (I2S) Good Bad
Output 2+ (RMT) Bad Good
Makuna commented 7 months ago

Further checks, While the WS2805/WS2814 might function, the WS2815 might have the same issue as previous WS2812 chips, in that the overall kbps must be no faster than 800kbps. Looking at the very latest update on the spec sheet, they added an addition that was not present before in the spec sheets I have. TDATA Data cycling time ≥1.25µs.
Normally this is defined by a line stating min/max data rate; but here they instead defined it by stating the total bit time must equal or exceed 1.25us.
With the WS2812, being even slightly faster than 800kbps caused issues only after approximately 60 leds in the strip, so after that 60 flickering would happen. If this holds for the WS2815, then a new speed will be needed unique to current sets. Esp32 I2s is already timed to 25% of the pulse, so 312us, but it is not accurate enough to be consistently below 400us.

Makuna commented 7 months ago

The Tm1914 which is already present is close, also try it. Increasing its reset to 300us and aliasing it to WS2815 would make it fully compatible.

rmounce commented 7 months ago

Hmm you're right with the newer WS2815 datasheet, they seem to be very inconsistent. I'll do some more research to summarise these and do some more scientific testing to determine the limits of my WS2815.

I haven't tried Tm1914 yet but I did try NeoEsp32RmtSpeedWs2811 which appeared to be even closer to the specs than Tm1914, but there was still flickering.

So my testing so far:

Stable

Unstable, occasional flickering

rmounce commented 7 months ago

Datasheet summary

T0H T1H T0L T1L Tdata
WS2812B 250-550 650-950 700-1000 300-600
WS2811/WS2815 220-380 580-1600 580-1600 220-420
WS2815B-V1 2.0 220-380 580-1000 580-1000 580-1000 <=1250us

I noticed that WS2811 has exactly the same timing spec as the earlier WS2815 variants. I'm ignoring the T1L value for WS2815B-V1 2.0 and assuming that this is actually 220-420 like WS2811.

Additional testing

Constant 1250us Tdata, T1L = T0H+50

T0H T1H T0L T1L Tdata Result
190 1010 1060 240 1250 Occasional corruption (every ~30 seconds)
230 970 1020 280 1250 Occasional corruption (every ~60 seconds)
270 930 980 320 1250 Stable (short test)
410 900 800 460 1250 Regular corruption (every few seconds)
430 770 820 480 1250 Constant corruption

I only realised after this testing that there is a 25us quantum with ESP32 RMT, so I think all of these values were actually rounded down to the nearest 25us resulting in a Tdata of 1225us for each test. Regardless, I think this confirmed the WS2812 RMT timing is extremely marginal with WS2815 LEDs and going slightly further out of spec by increasing T0H & T1L resulted in much more corruption.

Constant 350us T0H, 400us T1L

T0H T1H T0L T1L Tdata Result
350 750 800 400 1150 Occasional corruption (every ~30 seconds)
350 800 850 400 1200 Stable (short test)
350 850 900 400 1250 Stable
350 900 950 400 1300 Stable

Constant 300us T0H, 350us T1L

T0H T1H T0L T1L Tdata Result
300 750 800 350 1100 Stable
300 800 850 350 1150 Stable
300 850 900 350 1200 Stable
300 900 950 350 1250 Stable (default WS2811 RMT timing)

I think my initial test with NeoEsp32RmtSpeedWs2811 was flawed and that the corruption I saw was probably due to WiFi interrupt shortly after WLED startup, or I just made a typo. The datasheets & further testing show that the existing WS2811 timing seems to be good for my WS2815, and also within the published specs for WS2815B-V1 2.0 (ignoring an obviously wrong value in the datasheet).

So maybe there is not much to do here except add an alias from WS2815 to WS2811?

Instead I will turn my attention to WLED and try authoring a PR to split their "WS281X" mode into:

Makuna commented 7 months ago

Yeah, I will be adding a WS2815 aliases into NeoPixelBus, see newly created issue to track this.

But in general, WLED will be minimizing the number of specific methods they use to a set that are considered "compatible" to reduce the option matrix, so in the future they may expose WS2815 but may only map to the WS2811 anyhow.

blazoncek commented 7 months ago

Just to chime in regarding WLED. We are constantly battling image size vs. feature set availability. Recent additions to WLED have pushed image size to nearly 100% available application partitions on ESP32 while we are still with ancient PlatformIO platform Espressif32 3.5.0. Updating to a newer platform increases image size by nearly 100kB which no longer fits on existing partitions.

@rmounce I've talked to @Makuna about the reduction of methods used to save some additional RAM and flash. Introducing new methods - or better - adding variation of existing methods will be very low on TODO list for WLED. PR or not. Exception being benign code size increase.

@Makuna would there be a simpler way to call some base class virtual functions instead of what we do now? I.e.:

case I_32_RN_NEO_3: (static_cast<NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>*>(busPtr))->Show(consistent); break;
Makuna commented 7 months ago

@Makuna would there be a simpler way to call some base class virtual functions instead of what we do now? I.e.:

case I_32_RN_NEO_3: (static_cast<NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>*>(busPtr))->Show(consistent); break;

Virtual functions add code and heap usage. The model I went with reduces it, so the library works on small AVRs (ATTINY with between 64-512 bytes of total RAM for stack and heap) the original target I built the library for. WLED and a few others are unique in that they require dynamic reconfiguration across all features. Most users don't need this.

I am investigating into "virtual" Features and Methods for those platforms that can dismiss the loss of 30 to 300 bytes of RAM and code space (because they would already spend it working around the lack of dynamic configuration). But some "reconfiguration" will still require memory churn, going from RGB to RGBW or even WS2812x to SM168xx requires back buffers to be released and reallocated. Not to mention one wire (NeoPixel) vs two wires (Dotstars).

troyhacks commented 7 months ago

Just to toss in on the "overall kbps must be no faster than 800kbps" timing, my I don't know what I'm doing experiments with NeoPixelBus show I can push RMT at 1.333MHz and it's stable... enough? These are allegedly WS2812b pixels, according to the AliExpress listing.

I also shortened the break, which I found entirely too long and that helps loop around faster too. 208 FPS on 256 pixels, 52 here on 1024 pixels in a chain. Probing the end of the chain show the "clock" was propagated all along the panels.

https://github.com/Makuna/NeoPixelBus/assets/5659019/c7dfddb6-fc56-4e28-a83d-303d03195ffd

image-3

Makuna commented 7 months ago

Just to toss in on the "overall kbps must be no faster than 800kbps" timing, my I don't know what I'm doing experiments with NeoPixelBus show I can push RMT at 1.333MHz and it's stable... enough? These are allegedly WS2812b pixels, according to the AliExpress listing.

Individual experience on the reset timing will vary, as true/real WS2812x (b,c,etc) officially need at least 280us. Clones/fakes can be all over the place, from 50us to 300us. This is why it was set to 300us.

The issue with overall speed comes from longer strips. If you have 300 pixels, with official/real WS2812x you will see glitches after about 60 pixels. And this was running at 833Kbps.

Exioncore commented 1 week ago

Hmm you're right with the newer WS2815 datasheet, they seem to be very inconsistent. I'll do some more research to summarise these and do some more scientific testing to determine the limits of my WS2815.

I haven't tried Tm1914 yet but I did try NeoEsp32RmtSpeedWs2811 which appeared to be even closer to the specs than Tm1914, but there was still flickering.

So my testing so far:

Stable

  • NeoEsp32I2sSpeedWs2812x 312/938us, 938/312us
  • NeoEsp32RmtSpeedApa106 350/1350us, 1350/350us

Unstable, occasional flickering

  • NeoEsp32RmtSpeedWs2811 300/950us, 900/350us
  • NeoEsp32RmtSpeedWs2812 400/850us, 800/450us

Thank you!

I am also running 2 WS2813 LED strips (79 and 78 leds respectively) on a d1 mini ESP32 running WLED (0.15.0-b7), and I kept having the 1st led on the 2nd strip flicker occasionally triggering the whole strip to flicker (inverting the strips order changed which strip flickered telling me it wasn't a wiring/hardware issue). Setting the second strip to Apa106 indeed fixes the problem.

One small note, manually updating NeoPixelBus from the default 2.8.0 to 2.8.3 seemed to make the issue worse.