-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ESP32: timing error every 1ms corrupts LED pixel data #139
Comments
Thanks to @Abraxas3d for working with me to find this issue. |
If the strip is of type NEO_GRBW, the maximum length is even shorter, and matching your math perfectly: 24 LEDs work, but (with the delay(1) workaround in place) LED#25 (n=24 starting from 0) of a 30-pixel strip shows a red offset when the brightness is low. It seems like one bit is forced to 1 due to the timing issue. |
Thanks @MustBeArt for the documentation, I had the same problem in my code but I already manage to solve it |
When researching NeoPixels for the ESP32 I came across a library for FreeRTOS that uses the IR engine to generate the pulses and uses interrupts to keep the pipe full. I think for the ESP32 this would be a better solution than the normal method for driving the LEDs since the pulses and timing are handled by the hardware and it also would be fine for interrupts. See https://github.com/marcmerlin/Neopixel-IR/blob/master/esp32_ws2812.cpp |
Using the RMT is addressed here. Waiting on driver support from upstream. |
No idea if this is the same issue, but my NeoPixel code that works perfectly using AdafruitIO on a Feather Huzzah does not work properly on the FeatherESP32. I can flash the exact same code to both and the ESP32 board always sets the first pixel green and flickers no matter what color I set it to after that. It's been incredibly frustrating trying to figure out why... |
Hi @scott-linenberger I have exactly the same issue with Artnet on Feather HUZZAH ESP32, actually looking to fix It without any luck so far |
@Heljick --> I couldn't fix the issue either. The NeoPixels seem to work fine so long as I don't make an AdafruitIO connection. So, it would seem that when I'm using WiFi and the NeoPixels, the first pixel flicker is there. I tried different level shifters, tried a ton of code to reset and clear things...Wound up having to return my ESP32s and just use the updated Huzzah Feather (which is working absolutely fine). |
Thanks @scott-linenberger for the feedback, can you give me the link to your Feather ? I am in France adn it's very annoying for me, not sure I can't return mine :/ I saw people had issue and solved It using an other library than Adafruit one but can't remember where and if It was exactly for that issue. Will post a review if I can found it but for what I remember this was a delay issue and just having delay(2) solved there problem (maybe was for ESP8266) |
Found the thread Makuna/NeoPixelBus#152 |
@Heljick This is the other Feather I used that works fine with AdafruitIO and NeoPixels Huzzah Feather I also tried a different library: FastLED and had the exact same issue, as soon as I introduced a WiFi connection...flickering lights.. |
OK thanks I assume It's better to stay on ESP8266 indeed even if it's three times slower :/ Shame was very happy so far. |
heya @me-no-dev do you have any recommendations? |
@ladyada issue comes from the fact that we are running on top of freertos so the scheduler switches task every tick (1ms). In the beginning Arduino was the only task running on Core1, but that was later changed in IDF so some tasks run without core affinity, thus interrupting the loop task on Core1. |
@ladyada I can help with a custom driver based on one of the above protocols. Let me know :) |
@me-no-dev we've got no indepth experience with the RMT/DMA framework on ESP32 so a pull req from y'all would be super appreciated by everyone it seems :) |
Will do :) I have a feather-wing with neopixels here. Just one question... AFAIK there are two different signal standards and colour orders right? Like RGB and BGR and two different timing schemes. Could you point me to the proper info on those? Or I can get all that info from the lib and your website? |
the color order is swapped in software, the timing scheme is identical. |
Unfortunately I based my WS2812B hardware application on ESP32 before doing thorough checking (in my prototype I used a strip of 30 LEDs while the final project, for which I already printed PCBs, uses 120 LEDs). As you can imagine, there are glitches all over the place after LED #32. As expected, using delay() doesn't help in my case of 120 LEDs. What I find odd though, is that even if I use the portDISABLE_INTERRUPTS() "workaround" the problem does not disappear completely. In theory, even though disabling interrupts introduces so many other problems, it should totally fix the glitches in the LEDs. In practice, in my case, the glitches are reduced 90% but not completely disappear. Anyway, that's my 2 cents on the issue. Since I have a custom PCBA with ESP32 and 120 WS2812B sitting there, I can help with any debugging you guys may need. |
I have success with using I2S, but the IDF I2S driver will not do. The way that DMA is implemented causes issues. So... I use my own I2S driver and all is fine. At least for 340 pixels (DMA accepts up to 4096 bytes at once). Now I need to write the I2S driver so it can go into Arduino's HAL and will PR the changes here. Maybe 8266 can go the same direction and use I2S as well? |
sure, weve used SPI to DMA befroe, on the samd21. as long as you have pin flexibility i don’t think people care too much how it happens. :) |
Same issue, ESP32 feather + NeoPixel FeatherWing == glitches even on strandtest unless you use EDIT: I just tried https://github.com/Makuna/NeoPixelBus with total success, even with WiFi and Serial. Had to install from git, though, due to Makuna/NeoPixelBus#212 on Linux. I can confirm that's a good workaround until the Adafruit library gets hardware support on ESP32. |
@cscott added a note to the product page. |
@ladyada sorry I have been quite busy with a whole lot of things. I have a form of the driver running through I2S and one of my colleagues wrote a driver and example with RMT (in PR already), so you will have all the options quite soon. I have tested with up to 48 leds (that is all I have) and everything seems good. |
@cscott Makuna uses an early version of my I2S driver, but will also switch to the main one once finished. Afterall using a half-ass driver is not an option for Adafruit :) |
Hi All, |
I have written a WS2812B driver loosely based upon https://github.com/MartyMacGyver/ESP32-Digital-RGB-LED-Drivers Instead of ending transmission, I keep the RMT in constant transmit (i.e. I never fill RMT entries with 0). I have tested my code on these https://www.aliexpress.com/item/DC5V-WS2812B-1m-4m-5m-30-60-74-96-144-pixels-leds-m-Smart-led-pixel/32832420003.html?spm=a2g0s.9042311.0.0.319e4c4dX1ZIpO To get it to work though, I had to increase the stretch of duration1 on the last pixel to 3 * TRS (i.e. 150us vs the datasheet's 50us). Using TRS values lower than 3*TRS resulted in the strand not being reset and therefore cascading forever. I don't have a scope to measure what is actually happening on the data line, but as I still get high refresh rates, my hypothesis is that the actual time of duration1 is lower than described by the datasheet when duration0 is much smaller than duration1. |
The ESP32 library has what looks to be some official RMT tools built-in. They even provide an example. They work just fine for driving WS2812B pixels. I have it working with a flexible 8x32 display with no problems (which is amazing after fighting all sorts of weird flashing and flickering when driving the pin, even with interrupts disabled). With the RMT code, all artifacts have been completely silenced (though, I found I could somewhat reduce them by strapping a couple 220pf capacitors across data and ground). Anyway, to get this working, I monkey-patched That code is horrible, but only because I'm rushing by monkey-patching rather than making a careful fix. It ignores standard defines and hardcodes things in a way I would never do for a library I'm actually distributing. I hate to share my code in it's current state, but by sharing it I'm hoping to remind myself to come back next week and fix it. I based my code off of the example that is on the official espressif repo. That code can be found here: I hope to make a PR next week AFTER I finish giving a talk at The Perl Conference which features the device I need this for. I will have time after that, but definitely not before because I don't even have slides yet. |
I think I'm experiencing this same bug on an ESP32 board I made. I'm using the Neo7Segment library which relies on the Adafruit_NeoPixel library. Here is what I am seeing: Video of Neo7Segment demo -> https://imgur.com/5zKBg4n |
Hi, any news about this issue? experiencing the same problem with esp32 |
Fixed year ago
https://github.com/Yurik72/ESPHomeController/wiki/WS2812-driver-to-remove-flickering
…On Sun, Mar 8, 2020 at 2:49 PM ramarro123 ***@***.***> wrote:
Hi, any news about this issue? experiencing the same problem with esp32
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#139?email_source=notifications&email_token=AKDREXOG5FBJPDDTYYCAMI3RGOH55A5CNFSM4DLP5P7KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEOEVFUI#issuecomment-596202193>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AKDREXIS4YNUXSYFBFBJBBDRGOH55ANCNFSM4DLP5P7A>
.
|
did you submit a patch for this project? i don't see how linking a different library can help :) i am aware that fastled, neopixelbus, and now this other library probably, support rmt on esp32 ... but i am asking about adafruit_neoload not about other_library |
Apologies for digging up an old post, but I had a similar issue with NeoPixels and ESP32. I made my own NeoPattern library but am not skilled enough to convert it to the likes of NeoPixelBus so when I came across your post and RMT version I thought I'd give it a try, however, it doesn't seem to work. When using your .h and .cpp the neopixels do absolutely nothing.
There's no error, the neopixel strip just does nothing. If I upload basic NeoPixel test, everything works albeit glitchy with the odd artifact, so it's definitely something related to swapping the libs and NOT a hardware/wiring/power issue MTIA |
Yeah what ever happened with this? I do not think a PR was ever made for RMT on esp32, are people just using other libraries now? |
Does this issue sound like the same problem ? |
Some people say that if you move your pixel rendering to second core it helps. |
NeoPixelBus supports Matrix, here the reply of Michael in the gitter channel: So the killer solution would be to fork Neomatrix from Adafruit and make it work with Neopixel Bus. This library is simply not for ESP32. You cannot avoid this 1ms ticks and is really annoying to use like it is right now. |
Thanks @BatsIhor for the hint that moving to the second core helps! This is my code:
|
plesae try #253 |
released as 1.7.0 |
@ladyada should the note be removed from the NeoPixel Featherwing description now? https://www.adafruit.com/product/2945 |
removed! |
On the ESP32, an extra delay of about 5 microseconds is inserted into the signal output every millisecond. This is far outside the Neopixel timing tolerance of 150 ns, so it leads to incorrect values in some of the pixels.
The data for up to 33 RGB pixels can be transmitted in less than one millisecond (1.25 uS per bit X 24 bits per pixel X 33 pixels = 990 uS). In the common case where the show() method call immediately follows a delay() function call, the problem is not encountered unless the strand has at least 34 RGB pixels. However, if the code keeps time some other way (such as by calling millis() repeatedly) the extra delay may occur with random alignment to the signal. In that case, the signal may be corrupted with even a single pixel strand.
The extra delay may also be avoided by disabling interrupts during the call to the show() method. In the ESP32 Arduino environment, this cannot be done in the usual way, by calling noInterrupts() -- that function is defined to be nothing in Arduino.h. It can, however, be accomplished by invoking the macro portDISABLE_INTERRUPTS() defined by FreeRTOS in the file portmacro.h, since the Arduino code in the ESP32 is actually running on top of FreeRTOS. The macro portENABLE_INTERRUPTS() re-enables interrupts. Of course, if this method is used, any other time-critical operations will suffer interference, probably including millisecond timekeeping.
Method to Reproduce
The best way is to observe the output signal on a logic analyzer. Use any sketch that talks to pixels, and set the number of pixels to at least 34. In each burst of activity on the signal line representing a single strand update, you should see at least one pulse (high or low) of between 5 and 6 uS, and those pulses should occur every millisecond thereafter (when the millisecond coincides with signal activity).
If no logic analyzer is available, you can see the problem with just a strand of pixels. If a strand of more than 33 pixels is available, simply hook it up and try to run any of the example sketches. Flaky pixels will be visible.
If no long strand of pixels is available, the following sketch will illustrate the problem with whatever length strand you do have. Because the strand is short, the extra pulse will only occur some fraction of the time, so you may have to watch for a while to see flaky pixels. (This is how I originally discovered the problem. I use this method of timekeeping when I need to process more than one time-critical device.)
Workarounds
If your sketch is written so that every call to the show() method always follows immediately after a call to delay(), you can use up to 33 pixels in a strand without a problem. (Note: delay(0) doesn't work, it has to be at least delay(1).) The provided example sketches work this way.
If your sketch keeps time some other way, you can add a delay(1) call immediately before each call to the show() method, and use up to 33 pixels in a strand without a problem.
If you must have strands of 34 or more pixels, your only choice is to disable interrupts as described above and suffer the consequences.
Suggested Solution
The problem is pretty fundamental. The only way to prevent the extra delay appears to be to disable interrupts, and disabling interrupts for more than a millisecond (much more for long strands) is hardly a good answer.
See http://www.insentricity.com/a.cl/268/controlling-ws2812-rgb-leds-from-the-esp32 for an alternative driver design that should avoid this difficulty, if it can be ported to the Arduino environment.
The text was updated successfully, but these errors were encountered: