ws2811/2812 Programs very slow

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
ARTaylor
Posts: 29
Joined: Fri Mar 23, 2018 4:04 pm
Contact:

ws2811/2812 Programs very slow

Post by ARTaylor » Tue Sep 25, 2018 2:43 pm

Hi there - I feel like I am missing some vital bit of knowledge here. I have been playing with some math heavy algorithms in Micropython on the ESP32 controlling ws2811 and ws2812 leds - I have been doing things like blending between two random choices from a set palette (from a list(s)) and trying to have lots of pixels doing different things at once, I know I have been pushing my luck to some extent :lol:

I had lovely results with a small ring of 12 LEDs, but then of course the program fell apart when I scaled up to lots of pixels - it still works but progression is very very slow - I think I have some ideas on mitigating the issues - but today I have been playing with a new strip of ws2811 and having really poor results doing very simple stuff. I am running this program:

Code: Select all

from machine import Pin
from neopixel import NeoPixel
from time import sleep

pixelcount = 50
np = NeoPixel(Pin(19), pixelcount)

while True:
    # Green chaser
    for i in range(pixelcount):
        for n in range(pixelcount):
            np[n] = (0,0,0)
        np[i] = (255,0,0)
        np.write()
        sleep(0.01)
The first time the program loops, the speed is as expected with a fast chase down the strip, but after that the program get progressively slower - right now I am watching it after 10mins or so and I only see an update every 500ms or so - have I made a mistake here or am I missing some vital Micropython knowledge?? It would be good to get a bit closer to the speed I can get with an Arduino sketch.

If anyone is interested I can share my palette sketch - it is controlled by MQTT, can covert hex colours, does exponential scaling for smooth changes and almost works really well :)
Grow something!

ARTaylor
Posts: 29
Joined: Fri Mar 23, 2018 4:04 pm
Contact:

Re: ws2811/2812 Programs very slow

Post by ARTaylor » Tue Sep 25, 2018 2:49 pm

Ok I think I found the solution - needs garbage collection, though I only just came across this!

This quick fix following the manual works a lot better:

Code: Select all

from machine import Pin
from neopixel import NeoPixel
from time import sleep
import gc

pixelcount = 50
np = NeoPixel(Pin(19), pixelcount)

while True:
    # Green
    for i in range(pixelcount):
        for n in range(pixelcount):
            np[n] = (0,0,0)
        np[i] = (255,0,0)
        np.write()
        sleep(0.01)
    gc.collect()
    gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
Grow something!

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: ws2811/2812 Programs very slow

Post by jickster » Tue Sep 25, 2018 3:44 pm

ARTaylor wrote:
Tue Sep 25, 2018 2:49 pm
Ok I think I found the solution - needs garbage collection, though I only just came across this!

This quick fix following the manual works a lot better:

Code: Select all

from machine import Pin
from neopixel import NeoPixel
from time import sleep
import gc

pixelcount = 50
np = NeoPixel(Pin(19), pixelcount)

while True:
    # Green
    for i in range(pixelcount):
        for n in range(pixelcount):
            np[n] = (0,0,0)
        np[i] = (255,0,0)
        np.write()
        sleep(0.01)
    gc.collect()
    gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
I've dealt with the C-side a lot and especially the GC but I'm not sure why gc.collect() would help with the speed.

One big thing that's bugging me is that you reset ALL the LEDs every time you update ONE.
If you reset all the LEDs initially, wouldn't you only need to reset the previous one you changed?

Code: Select all

while True:
    # Green
    # Reset all LEDs
    for n in range(pixelcount):
            np[n] = (0,0,0)
    for i in range(pixelcount):        
        np[i] = (255,0,0)
        np.write()
        np[i] = (0, 0, 0)
        sleep(0.01)
    gc.collect()
    gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
That WILL improve the update speed proportional to the number of pixels you have.

If you call gc.collect(), it's not necessary to call gc.threshold() because gc.collect() WILL do a collect regardless of the threshold.
The threshold is only if you do NOT call gc.collect() manually.

ARTaylor
Posts: 29
Joined: Fri Mar 23, 2018 4:04 pm
Contact:

Re: ws2811/2812 Programs very slow

Post by ARTaylor » Tue Sep 25, 2018 3:54 pm

TBH I don't understand GC right now, I will read over the docs properly this eve

And yes you are absolutely correct, but I just threw this program together to test some things, the problem I found is the rate of the program drops increasingly over time - the GC functions prevent this from happening, but there is a pause when

Code: Select all

gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
is executed. The programs I want to run are a lot more complicated, they can be improved for sure but they are definitely more processor intensive regardless.
Grow something!

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: ws2811/2812 Programs very slow

Post by jickster » Tue Sep 25, 2018 3:55 pm

ARTaylor wrote:
Tue Sep 25, 2018 3:54 pm
TBH I don't understand GC right now, I will read over the docs properly this eve

And yes you are absolutely correct, but I just threw this program together to test some things, the problem I found is the rate of the program drops increasingly over time - the GC functions prevent this from happening, but there is a pause when

Code: Select all

gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
is executed. The programs I want to run are a lot more complicated, they can be improved for sure but they are definitely more processor intensive regardless.
If you're going to call gc.collect() manually AND you set GC auto-collect to OFF, calling gc.threshold() is 100% unnecessary.

ARTaylor
Posts: 29
Joined: Fri Mar 23, 2018 4:04 pm
Contact:

Re: ws2811/2812 Programs very slow

Post by ARTaylor » Tue Sep 25, 2018 3:56 pm

Thanks, I missed the end of your earlier comment
Grow something!

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: ws2811/2812 Programs very slow

Post by jickster » Tue Sep 25, 2018 3:58 pm

After np.write(), print gc.mem_free()
Also time the call np.write()

That's the only thing that could be slowing down.

ARTaylor
Posts: 29
Joined: Fri Mar 23, 2018 4:04 pm
Contact:

Re: ws2811/2812 Programs very slow

Post by ARTaylor » Tue Sep 25, 2018 4:27 pm

jickster wrote:
Tue Sep 25, 2018 3:58 pm
After np.write(), print gc.mem_free()
Also time the call np.write()

That's the only thing that could be slowing down.
Thanks, I can see the gc.mem_free() is showing bytes decreasing rapidly - this is happening even if np.write() is commented out. gc.collect() restores bytes as you said.

Setting the np object tuple seems to be the problem not np.write(), commenting this out while still calling np.write() shows no decrease in bytes.

What did you mean by time the call? Print a time stamp before/after?
Grow something!

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: ws2811/2812 Programs very slow

Post by jickster » Tue Sep 25, 2018 4:29 pm

ARTaylor wrote:
jickster wrote:
Tue Sep 25, 2018 3:58 pm
After np.write(), print gc.mem_free()
Also time the call np.write()

That's the only thing that could be slowing down.
Thanks, I can see the gc.mem_free() is showing bytes decreasing rapidly - this is happening even if np.write() is commented out. gc.collect() restores bytes as you said.

Setting the np object tuple seems to be the problem not np.write(), commenting this out while still calling np.write() shows no decrease in bytes.

What did you mean by time the call? Print a time stamp before/after?
Time the np.write() call BUT if commenting out np.write() causes memory to decrease rapidly … there’s another issue.


Sent from my iPhone using Tapatalk Pro

ARTaylor
Posts: 29
Joined: Fri Mar 23, 2018 4:04 pm
Contact:

Re: ws2811/2812 Programs very slow

Post by ARTaylor » Tue Sep 25, 2018 4:41 pm

Writing the tuple is the problem:

Code: Select all

np = (n,n,n)
for example, commenting that out fixes the issue. I guess the value for every LED is being stored, and 50+ is excessive
Grow something!

Post Reply