NeoPixelBus icon indicating copy to clipboard operation
NeoPixelBus copied to clipboard

Big flickering when driving LEDs in realtime using USB Serial...

Open sblantipodi opened this issue 2 years ago • 12 comments

Describe the bug Driving LEDs via USB Serial creates big flickering when WiFi is active even at 460800 baudrate. There is big flickering even when there is no WiFi at 1 million baudrate.

To Reproduce Try to run LEDs in real time at 60FPS or even 30FPS when WiFi is active. Big flickering happens. Flickering is reduced when WiFi is off, but there still there if driving LEDs at 1 million baudrate.

This does not happen on ESP8266.

Expected behavior No flickering excpected

Development environment (please complete the following information):

  • OS: Win10
  • Build Environment PlatformIO 5.2.1
  • Board target ESP32
  • Library version [e.g. v2.3.4] - latest 2.6.9

Additional context I have tried using different RTOS tasks as described here:
https://github.com/Makuna/NeoPixelBus/wiki/ESP32-and-RTOS-Tasks
but it does not help.
Using NeoEsp32I2s1800KbpsMethod

sblantipodi avatar Oct 18 '21 10:10 sblantipodi

Please be more specific when you state big flickering. Capture some video, high speed if possible. Please provide a minimal sketch that can demonstrate the problem. I can't diagnose anything that I can't reproduce.
How many pixels on the strip? Did you try changing the count and does it matter?

And BTW, I specifically only support Arduino IDE, and usually only the latest builds.

Makuna avatar Oct 18 '21 17:10 Makuna

@Makuna Here a video of the flicker: https://youtu.be/9CAu7XzbdV4

I'll try to give you some context.

NeoPixelBus is one of the core libs of Luciferin, a small project for ambient lighting also known as bias lighting. Luciferin consists of two piece of software, a PC software that runs on Windows or Linux and a firmware that runs on ESP devices.

The PC software capture the screen at a locked refresh rate that varies from 30 to 200+FPS as per user settings, once a frame is recorded, the PC software gather the color information from that frame and sends them to the ESP using these methods:

  1. via USB serial at variable baudrate that can be set from 115200 to 2 million, defaults to 500K. (this is the problematic method, both serial and wifi is functioning, serial receives the color informations, wifi sends back framerate and some other infos to PC software)
  2. via WiFi using UDP and a "custom protocol" similar to the adaligth ones (no problem when using WiFi only no Serial)
  3. via MQTT (no problem when using WiFi only with MQTT no Serial)

This video shows better what is the purpose of Luciferin: https://youtu.be/Hd6BtPp40I0

As you can see, the environment is a bit rich and it's difficult to create a small sketch that can demonstrate the problem but if it can help, same code, works well on ESP8266 while it gived the flicker on ESP32.

Firmware code is not that big and it's public on GitHub here: https://github.com/sblantipodi/glow_worm_luciferin/blob/full_firmware_wifi_only/src/GlowWormLuciferin.cpp

Serial.read() code is done inside the mainLoop() function while UDP.read() code is done inside getUDPStream() function.

As you can see, once gathered the color information is gathered via Serial.read() or UDP.read(), colors infos are sent to the strip with a setPixelColor() function and then "committed" with a ledShow() function.

Code is pretty easy and as I said works well on ESP8266 but flickers on ESP32.

Numbers of LEDs are dynamic and can be changed inside the PC software, I have tried with 100LEDs, 200, 500 and the flicker happens in the same way.

PlatformIO and Arduino IDE are the same dog, just a different way to use the same things :) If you support Arduino IDE, you support PlatformIO as long as you continue to update your library.json file for the PlatformIO library manager.

I don't know if you want to spend 10 minutes trying to configure Luciferin on your setup.

if yes then

there is a firmware web installer here: https://sblantipodi.github.io/glow_worm_luciferin/beta.html just click the INSTALL FULL BETA button to flash your firmware on your ESP32 from a Chrome browser. (I'm pointing out to the beta since it have reduced features at the moment and the code is easyer to read)

once you installed the firmware on your ESP32, an AP is started, connect to the GLOW_WORM_LUCIFERIN AP with your PC or your mobile, surf to 192.168.1.4 from your browser and you'll see something like this:

just enter your wifi credentials, and the GPIO you want to use on your ESP (2, 3, 5, 16 is supported currently), you can skip the mqtt infos if you want, click, store config and your set. Your ESP will reboot and you are set.

Now you can download the PC software here: https://github.com/sblantipodi/firefly_luciferin/actions/runs/1354959116 There is a Windows installer or a linux rpm/deb.

Once the software is installed, launch it, click the tray icon (if you are on windows and have the tray icon enabled) click settings,

  • then go to WiFi/MQTT tab, tick enable wifi checkbox
  • then go to Mode tab, in the output device section, select the right com port for your ESP.
  • click save and close button.

Software will restart and the ambient light effect will start.

You'll see the flickering I'm talking about.

If you don't have time for this, I can close the issue no problem, I'm your fan in any case :)

PS: Flickering is similar to the one noticed in this issue #520 but it happens at a larger interval, let's say every four seconds... more or less but it's obviously random.

sblantipodi avatar Oct 19 '21 20:10 sblantipodi

Since you are updating constantly, that flicker is caused an errant communications issue and not something systemic. Usually the timing is off (you have different chips than WS2812). You are using ESP32 and not ESP32C2 or ESP32S3?

Try NeoEsp32I2s1Ws2812xMethod instead of NeoEsp32I2s1800KbpsMethod. Neo800KbpsMethod maps to this but you are not using it for the ESP32, the original WS2812 had a short reset time, the latest have a much longer reset time; and you maybe hitting this since you are sending so quickly one after another. The method naming convention is that if you use the i2s name specifically, then then chip name must be specific (2812x, not 2812). But the non specific name (Neo800KbpsMethod) uses the most "compatible".

Makuna avatar Oct 19 '21 22:10 Makuna

@Makuna I'm using WS2812B LEDs on ESP32 "standard", not C2 or S3.

I have tried NeoEsp32I2s1Ws2812xMethod but the flickering is there, there is no improvement from NeoEsp32I2s1800KbpsMethod to NeoEsp32I2s1Ws2812xMethod unfortunantly.

What do you mean with this?

Since you are updating constantly, that flicker is caused an errant communications issue and not something systemic.

there is no communication error from the PC software to the firmware, I am logging the received messages and the message is received correctly but then displayed badly on the strip.

PS: I am trying to update the strip at only 5FPS, flickering is still there.

sblantipodi avatar Oct 20 '21 12:10 sblantipodi

Errant communication to the WS2812b.
Try the RMT method next. see ESP32 methods Wiki entry

Makuna avatar Oct 20 '21 17:10 Makuna

NeoEsp32Rmt0Ws2812xMethod produces worse flickering than NeoEsp32I2s1800KbpsMethod.

sblantipodi avatar Oct 20 '21 19:10 sblantipodi

Are you using level shifters at all? RMT is more sensitive to interrupt saturation than I2s. But I2s can be effected by it. I suspect this is what you are running into. There is little I can do. This requires the sketch writer to reduce ISR usage (less ISRs).

With I2s, the ISR is called once per Show() and the actual data sending is done by i2s DMA hardware.

Something you can try, but I have no idea if it will help.

Switch back to I2s method. On this line of NeoPixelBus https://github.com/Makuna/NeoPixelBus/blob/a561a8294eb1ba1eaeeafc91467b9ab828dfcfa8/src/internal/Esp32_i2s.c#L387

Try increasing the priority by using ESP_INTR_FLAG_LEVEL2 and see if it helps. Keep increasing upto ESP_INTR_FLAG_LEVEL6, but in general this isn't the best approach.

Makuna avatar Oct 20 '21 20:10 Makuna

I have the exact same behaviour on various ESP32 based microcontrollers, ESP32 dev kit, Lolin D32, TinyPICO, Quindor's custom ESP32...

Some of those microcontrollers uses CH341 serial chip, some other uses CP2124 serial chip.

In every setup I use a 74AHCT125N logic level converter, image

some older setup uses a simple logic level converter from sparkfun like this: image

as I said, I have various setups in my house, with different components, all ESP32 based, and all have the same problem. I have quality PSUs and quality strips from BFT-Lighting.

I have designed various PCBs to get sturdy "connections".

I buy components from mouser and digikey so they are 100% genuine and good quality ones.

I have tested ESP_INTR_FLAG_LEVEL1, ESP_INTR_FLAG_LEVEL2, ESP_INTR_FLAG_LEVEL3, ESP_INTR_FLAG_LEVEL4, and the flickering is there. With ESP_INTR_FLAG_LEVEL5 and ESP_INTR_FLAG_LEVEL6, it seems that it doesn't work well at all..

the strange thing is that if I use WiFi using UDP stream without using Serial, I can push 200+FPS with 100LEDs and 60+FPS with 500LEDs without any stuttering/flickering.

the problem happen when I mix WiFi with Serial.

sblantipodi avatar Oct 21 '21 20:10 sblantipodi

In general, its never a good idea to increase the priority, but I thought it would be worth trying. There has been issues with some of the level shifters not being fast enough causing glitches. But unlikely here, but you might try without one.

I am thinking the Serial ISR is the culprit here; in that it either takes too long in its ISR or its ISR is triggering far too often.

Also, which cores are you running your work on? The ESP32 has two cores, leave NeoPixelBus work on the first core, try to move WiFi and Serial onto the second core (see ESP32 tasks and core affinity APIs).

Makuna avatar Oct 21 '21 20:10 Makuna

Ok, I tried everything,

  • moving Serial and WiFi on core 0 and NeoBixelBus work on core 1
  • moving Serial and WiFi on core 1 and NeoBixelBus work on core 0
  • splitting WiFi and Serial work between cores
  • not using a level shifter is worse than when using it

the 74AHCT125N should be much faster than needed... but I don't think that it's a level shifter problem because if I disable the Serial.read() part the problem vanish.

flickering is still there.

sblantipodi avatar Oct 24 '21 15:10 sblantipodi

Try the latest Github version with RMT again and make sure to get the updated board support. There is a fix for latest IDF with interrupt level.

Makuna avatar Nov 29 '21 17:11 Makuna

@Makuna thanks for the continued help and for the great work here, I love your lib. unfortunantly the flicker is still there as before.

Using the latest master branch from github and the latest Arduino framework for ESP32 with NeoEsp32Rmt1Ws2812xMethod and NeoEsp32Rmt0Ws2812xMethod

sblantipodi avatar Nov 30 '21 09:11 sblantipodi

@sblantipodi Some changes have been made to the i2s method lately. Have you tried the latest?

Makuna avatar Feb 10 '23 21:02 Makuna

@Makuna I'm always glad to upgrade to the latest version of your great lib. I'll test it and report back soon. thanks!

sblantipodi avatar Feb 10 '23 23:02 sblantipodi

@Makuna I'm driving 100 LEDs at 120FPS at 1.5 million baudrate on an ESP32 that uses CP2104 UART chip via USB, during the "color stream via USB" there is a process that uses MQTT to send framerate data to the broker along with other informations. I have done another test with "UDP stream (no USB)" with 500 LEDs at 60FPS and there is no regression.

No flickering at all in every conditions, I'm closing the issue since the problem is completely fixed.

Thank you for your awesome work here Makuna, this lib is simply amazing.

Best wishes Davide

sblantipodi avatar Feb 12 '23 11:02 sblantipodi