tinue / apa102-pi

Pure Python library to drive APA102 LED stripes; Use with Raspberry Pi.
GNU General Public License v2.0
201 stars 71 forks source link

Not Fast enough #49

Closed oussamajegham closed 2 years ago

oussamajegham commented 3 years ago

Thank you for your library , it makes things easy for us , but i have a problem i would be grateful if you could help me to solve it , I am building a POV Display project , My motor is turning 25 spin per second (1500 RPM) , there is 64 LEDs of HD107S (same to APA102 but have much higher addressing frequency "30 Mhz" ) , the problem is the speed of scaning is not fast enough, therefore I see lines and not dots , even I tried to turn the frequency up To 24 MHz ,It seems that the best result i can reach is at 8 Mhz , after that all frequency give same results , What wrong ?!! it seems that the library stuck at ~ 8 Mhz !!

Untitled - Copy 24_frqs_From_video4

Testing the Dotstar library give better result , but i didn't find how to change frequency yet , it will be easy for me working with your library because the frequency is easy to change , i hope you find solution to the problem .

Dotstar VS Apa102-pi lib

Apa102-pi loop :

while 1: if GPIO.input(15) == GPIO.HIGH: strip.set_pixel_rgb(30, 0x00000F) strip.show() strip.set_pixel_rgb(30, 0x000000) strip.show()

Dotstar loop :

while 1: if GPIO.input(15) == GPIO.HIGH: pixels[30] = (10, 0, 0) pixels[30] = (0, 0, 0)

tinue commented 3 years ago

According to documentation the SPI bus speed should go up to about 50MHz. I could think of two reasons why it's not going anywhere near this limit:

My library is written in Python, which is an interpreted language. You could try to get some timings for Python itself: Run your sample with and without the "strip.show()" part, and add some time gathering logic. You should be able to find how fast the set_pixel_rgb() is in comparison to show(). My suspicion is that the Python overhead itself is limiting the code to about 8MHz.

Regards, Martin

oussamajegham commented 3 years ago

Thank you for your replay and I am very sorry for my late , The problem is that python very slow , if the library was written in C ,it would work , So i will be glad if you can change it to C , because your library it has many features the others don't have .

RubenMomoa commented 3 years ago

maybe its because show() uses spi.write 5 (or more) times clock_start_frame makes 1 call show it self makes 1 call and clock_end_frame does 1 + some based on num_led calls (up to 64 calls for 1024 led's)

maybe it would be faster to do this in 1 call this works (in my limited testing) write([0] * 4 + led_data + [0] * 4 + [0] * ((num_led + 15) // 16)) it combines the start, data, end frames all in 1 call the downside is that the num_led limit isn't 1024 anymore it would be 956

tinue commented 2 years ago

Hello, I wrote the library initially to learn Python, and to understand the APA102 protocol. I wanted to pass on this knowledge in the form of documented code, so I published it on Github.

So the code is inefficient, and at the same time easier to understand compared to a "tuned" version. Your change is a good example: I also think that this would work fine, and it would probably be faster. On the other hand: If one wants to understand the protocol, then "start frame" etc. are important elements, and having separate calls makes this easier to comprehend.

This is why I don't plan to optimise the code at the cost of readability. However, feel free to fork the repository and try to provide a "high speed" version of the library. People who simply want to use the library, and not understand the protocol behind it would certainly prefer this version.

For a really speedy version, one would have to provide an implementation in C or C++, but I don't plan to do this.

dasl- commented 2 years ago

For anyone interested, @jordanlewis had some success increasing the performance of this library by implementing some of the internal logic using numpy: https://github.com/dasl-/pifi/blob/96d11bbb0bbdc6cd69a662e12b5f28c66ded62d8/pifi/led/drivers/driverapa102.py#L26-L62

The TLDR is that we set the APA102.leds array manually, thus bypassing some slow logic in the APA102.set_pixel method. By reimplementing that logic in numpy vectorized operations, we were able to speed things up a lot, and avoid the overhead of so many function calls in python.

We are running our code on a raspberry pi, and the speed up was significant there.