Staacks / there.oughta.be

Projects featured on my blog at https://there.oughta.be
https://there.oughta.be
GNU General Public License v3.0
101 stars 33 forks source link

--led-limit-refresh option is missing #13

Closed eurosting closed 3 years ago

eurosting commented 3 years ago

Hello guys, to reduce the load and heating of PI 3 in LED cube I would like to limit the refresh rate by use --led-limit-refresh option. But this option seems to be not implemented or missing. Please advise how can the refresh-rate be reduced. Thanks.

Staacks commented 3 years ago

I have to admit that I am not entirely sure why --led-limit-refresh is not available, but I think that this is not the option you are looking for. --led-limit-refresh will limit the refresh time, but not necessarily the render cycle of the main thread (unless the vsync then limits the frame rate).

So, what is happening is that the cpp program runs an infinite loop which renders the image all the time. At the same time, there is a process on a single core that is part of the rpi-rgb-led-matrix library that takes the latest image from "my" cycles and sends it to the cube repeatedly. If "my" loop is not fast enough, the rpi-rgb-led-matrix process will send the same image several times to "refresh" the image and reduce flickering (hence refresh time).

Now, reducing the refresh time so drastically might help with overheating, because my loop waits for a so-called v-sync, which means that it waits for the refresh from the library. So, if you reduce the refresh time, you will probably also slow down the render loop as it waits for the refresh (have not tested this). However, you probably only want to slowdown the render loop while the refresh rate stays high. In fact, I think that a render framerate of 30 Hz or less will not be noticable to the human eye as it is a slow animation. This way, my process on your rPi will sleep "a bit" (not sure how much) while the library process continues to refresh without any increased flickering.

Now, my code neither has a method to measure the framerate of the main loop nor does it have a method to limit it. But, at least the latter can easily be added in a rather crude way. Simply add usleep(25000) ; after the line that does the v-sync swap: https://github.com/Staacks/there.oughta.be/blob/466fac4e2706e82038eec4026529b4f7c8d2b8a4/led-cube/led-cube/cpu-stats-gl.cpp#L577

This should put the process to sleep for 25000µs, which should allow for no more than 40 Hz (probably significantly less for the time it takes to render the image). Does this reduce the temperature and CPU load for you?

eurosting commented 3 years ago

I add the usleep(25000) after the line 577 in your script and compiled it again. Unfortunately the refresh rate rized. I changed the value to usleep(500000) and the rized more and the animation was about 2 frames per second. Well, it can be easy explained -> slowdown your animation -> more cpu time for other processes.

It looks like I need to slow-down rpi-rgb-led-matrix library. For this purpose exists --led-limit-refresh parameter. Unfortunately LED doesn't recognize this parameter.

TERMINAL pi@pi-rgb:~/led $ sudo ./cpu --led-show-refresh --led-limit-refresh=60 Initialized EGL version: 1.4 GL Viewport size: 192x64

Option --led-limit-refresh=60 starts with --led- but it is unknown. Typo? 152.6Hz pi@pi-rgb:~/led $

Staacks commented 3 years ago

That makes sense to a certain extend. I expected the library thread to be running at 100% anyways. Did you reserve a core for it? Maybe there is just more capacity on the rPi3 than on my rPi2.

In any case, I see why you would want to limit the refresh rate as well. Not convinced that 60 Hz looks good, but you will have to try it. Does --led-limit-refresh work in the demos? I have to say that I am not entirely sure why my code should work differently here. I just compared and I hand over the command line parameters to the library the same way the demos do.

However, when I just looked at the library code, it seems that the actual parameter is not --led-limit-refresh, but just --limit-refresh. Does this help? Is it as simple as a mistake in the documentation?

eurosting commented 3 years ago

According to information this page the properly parameter is --led-limit-refresh. But you are right the script accepts --limit-refresh. https://github.com/hzeller/rpi-rgb-led-matrix

I tested different values for --limit-refresh, but is seems to have NOT any impact - the refresh rate stays nearly constant.

Why I'm trying to reduce the load? - At the moment I don't have any cooling on Pi3. There is no space between CPU and RGB-Matrix-Head. After start of animation on PI it takes 2-5 seconds until the CPU reach more than 60°C, then the CPU (I thing) throttling. The consequence ist the flickering animation.

Does --led-limit-refresh work in the demos? No, is unknown parameter

Staacks commented 3 years ago

One thought: I have not checked the history of the repository, but you could try a more recent version of the repository. I recommended a specific commit to replace the even older commit in the Adafruit installation script for the library. So, maybe a newer version introduces a fix for this parameter, but I still do not see that the current version parses this parameter as --led-limit-refresh anywhere, so there is at least an inconsistency between the documentation and the actual code.

You might also try to set the parameter directly in the code. Try adding the line defaults.limit_refresh_rate_hz = 60 after the other default parameters: https://github.com/Staacks/there.oughta.be/blob/466fac4e2706e82038eec4026529b4f7c8d2b8a4/led-cube/led-cube/cpu-stats-gl.cpp#L519 (Sorry, haven't tried it, but this seems to be the code equivalent with yet another name.)

If this also does not limit the refresh rate, and considering that it doesn't work in the demos either, you might want to bring this up on the issue tracker of the rgb-led-matrix library.

On the other hand, I am not entirely sure if your flickering is due to overheating. 60°C is high, but not extremely high and there are so many sources for flickering... Definitely try isolating a core (if you haven't already), disable the audio chip and make sure that your power supply delivers stable 5V as the undervoltage protection also throttles the CPU (so, if the voltage drops because the LEDs turn on, this might also explain your symptoms).

You might also try to contact the other users here who are using an rPi3 to learn whether they have a heatsink and/or similar problems.

eurosting commented 3 years ago

Merry Christmas to All.

I reinstall all RGB scripts and libraries and from GibHub, done all updates and done some tests again. The cooling seems to be not a problem - I run the animation for 2-3 mins and temperature rized to values about 67°C, but no trottling were showed by the command vcgencmd get_throttled. Anyway every 1-30 seconds I noticed small animation glitches - some rows (differet every time, but the rows next to each other) flicker (stay black) for a very short time (some milliseconds). May be the PI writes some data to SD all the time? Or something interrupts the animation.

Then I checked the --led-limit-refresh parameter, it works fine for RGB-LED Demo examples, but not for the LED cube - see terminal:

DEMO Example with 60Hz limit:

pi@pi-rgb:~ $ cd rpi-rgb-led-matrix/examples-api-use/
pi@pi-rgb:~/rpi-rgb-led-matrix/examples-api-use $
pi@pi-rgb:~/rpi-rgb-led-matrix/examples-api-use $ sudo ./demo -D0 --led-gpio-mapping=adafruit-hat-pwm --led-slowdown-gpio 2 --led-cols=192  --led-rows=64 --led-brightness=30 --led-show-refresh --led-limit-refresh 60
Size: 192x64. Hardware gpio mapping: adafruit-hat-pwm
Press <CTRL-C> to exit and reset LEDs                                                                   60.0Hz

LED cube with same settings and also 60Hz limit:

pi@pi-rgb:~/led $ sudo ./cpu --led-gpio-mapping=adafruit-hat-pwm --led-slowdown-gpio 2 --led-cols=192  --led-rows=64 --led-brightness=30 --led-show-refresh --led-limit-refresh 60
Initialized EGL version: 1.4
GL Viewport size: 192x64
Option --led-limit-refresh starts with --led- but it is unknown. Typo?                                     1 166.6Hz
pi@pi-rgb:~/led $

I aslo tried to use the dedicated core for LED cube prozess. For this purpose I reserved the core 3 (isolcpus=3). I checked by using htop - there is no load on core 3. If I start my LED cube script by this way, then animation works (with flickering):

pi@pi-rgb:~/led $ sudo ./cpu --led-show-refresh
Initialized EGL version: 1.4
GL Viewport size: 192x64
113.9Hz

If I start this prozess on dedicated core, then led cube flickers one time very shortly, and then it stayes black - no animation, but script styes working:

pi@pi-rgb:~/led $ sudo taskset 0x00000004  sudo ./cpu --led-show-refresh
Initialized EGL version: 1.4
GL Viewport size: 192x64                                                                                   161.5Hz
pi@pi-rgb:~/led $ sudo taskset -c 3  sudo ./cpu --led-show-refresh
Initialized EGL version: 1.4
GL Viewport size: 192x64                                                                                   161Hz

I don't tested different COMMIT - no idea how to do this. It's first time I'm using PI and linux.
eurosting commented 3 years ago

And I also noticed that max (evaluation time) value, which provides --led-show-refresh option rizes higher and higher for led cube animation - the longer the animation runs. That means for me the PI loads the core, which evaluates LED cube animation, with something else. So dedicated core should definitely help to solve the glitching of animtion.

Staacks commented 3 years ago

And I also noticed that max (evaluation time) value, which provides --led-show-refresh option rizes higher and higher for led cube animation - the longer the animation runs. That means for me the PI loads the core, which evaluates LED cube animation, with something else. So dedicated core should definitely help to solve the glitching of animtion.

Sorry, I can't follow... The "max" that is reported by --led-show-refresh is the longest time for a refresh that ever happened since the program was started. It can only increase.

However, this explains why you cannot use --led-limit-refresh. This option has been been introduced in March 2020 and at the same time this "max" was replaced with "lowest", showing the rate instead of the time: https://github.com/hzeller/rpi-rgb-led-matrix/commit/1ba867b0cb0ad5901b7d57e708b6fa027b698ea2 If I am not mistaken, you are probably using the same commit I used or the commit that is set as a default in the Adafruit script. Both are older than the command line option and both output "max". The current release only gives "lowest": https://github.com/hzeller/rpi-rgb-led-matrix/blob/9f5ffd8a93614dbf3b6262103aefea2e3ba268bd/lib/led-matrix.cc#L214

It seems like you compiled the code against an installation from the Adafruit script (maybe replacing the COMMIT= line as I suggest on my blog) and are running demos from the newest release which you downloaded separately but which was not used to compile my code..?

So, to use this option, you probably want to make sure to compile against the latest commit. Not sure if this works, though. I picked my commit around early 2020 when I started working on the code, but I still picked an older commit from 2019: https://github.com/hzeller/rpi-rgb-led-matrix/commit/21410d2b0bac006b4a1661594926af347b3ce334 I have to admit that I am not sure why. Might just be a broken head version at that time, some laziness on my side once it was working or a more basic incompatibility, in which case you will have a problem here.

If I start this prozess on dedicated core, then led cube flickers one time very shortly, and then it stayes black - no animation, but script styes working:

Don't do that :) Or at least use a different one than core 3. The refresh process of the library detaches itself automatically and always goes to the third core. isolcpus=3 makes sure that OS (the kernel CPU scheduler) does not send any other process there. If you use taskset you also send the OpenGL worker process there, which is exactly what you do not want.

Also, even if you isolate the core, you do not want to run anything else on the cube unless it is extremely lightweight and never spikes in usage. Just because the kernel scheduler does not send anything to this CPU core does not mean that it can just output its result at any time or deal with other resources whenever it likes (RAM? GPIO pins? Interrupts? Not sure what the limiting aspect is here). Other processes still interfere with the timing and for example I can still see a faint flicker on my cube whenever I start an SSH session to it. You want to strip down the processes as much as you can (which is another reason for a read-only system).

eurosting commented 3 years ago

Hello Sebastian, as I now understand the COMMIT seems to be a "version" of the "code". As I'm new, I just followed your description (https://there.oughta.be/an/led-cube)

For the library installation I used this script https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/master/rgb-matrix.sh which uses COMMIT=21410d2b0bac006b4a1661594926af347b3ce334

And then I used your c++ code, which you provide: https://github.com/Staacks/there.oughta.be/blob/master/led-cube/led-cube/cpu-stats-gl.cpp

The easieast way for me to install the right (or newest) version of the library would be just to change the COMMIT number in the installation script and just reinstall the libraries again. And then just to recompile your code. Which COMMIT number shoud I use? - this one 1ba867b0cb0ad5901b7d57e708b6fa027b698ea2 ???

eurosting commented 3 years ago

To be honest the cube is now working nearly perfect after I add the core isolation. It would be great to limit the refresh rate - by using 50Hz, 100Hz or 150Hz we could avoid flicker on the video or just reduce the 100% load of 3rd core. But, I don't really need this. For me the issue can be closed. Thank for your time and your support. LED cube is a grea idea !!!

Staacks commented 3 years ago

A commit is a point in the history of code. You could call it a version, but depending on how granular commits are used, it could be any small change in code or maybe even something that is not working at the moment it has been committed. So, in contrast to a version, you should not be surprised if a random commit is not working properly.

Commit 1ba867b0cb0ad5901b7d57e708b6fa027b698ea2 would be the oldest that has the command line parameter. Any newer should work and it might be worth trying the latest commit. It just might have some other incompatibility I don't remember right now.