hzeller / rpi-rgb-led-matrix

Controlling up to three chains of 64x64, 32x32, 16x32 or similar RGB LED displays using Raspberry Pi GPIO
GNU General Public License v2.0
3.67k stars 1.17k forks source link

Can the code contribute to flickers ? #883

Closed GeorgeFlorian closed 5 years ago

GeorgeFlorian commented 5 years ago

Board: Raspberry Pi 4 OS: Linux raspberrypi 4.19.58-v7l+ Panels: Chinese 2727 SMD 64x32 5 pitch

Hello ! I am driving 4 panels using 2 chains.

I have the following "display" function in a while loop:

static void Text_HasArrived(RGBMatrix *canvas, const char * line1, const char * line2,
                            int brightness = 50, rgb_matrix::Color color1 = GREEN, rgb_matrix::Color color2 = GREEN) {
  canvas->Clear();
  canvas->SetBrightness(brightness);

  rgb_matrix::DrawText(canvas, font_Arial21, 6, font_Arial21.baseline()-7, color1, &BLACK, line1, -2);
  rgb_matrix::DrawText(canvas, font_Arial20, -2, font_Arial20.baseline()*2-5, color2, &BLACK, line2, -2);
}

so:

int main(int argc, char *argv[]) 
{
  RGBMatrix::Options defaults;
  RuntimeOptions runtime_defaults;
  defaults.hardware_mapping = "regular";  // or e.g. "adafruit-hat"
  defaults.multiplexing = 1;
  defaults.cols = 64;
  defaults.rows = 32;
  defaults.chain_length = 2;
  defaults.parallel = 2;
  //defaults.pixel_mapper_config = "U-mapper";
  defaults.disable_hardware_pulsing = true;
  defaults.show_refresh_rate = true;
  runtime_defaults.gpio_slowdown = 3;
  RGBMatrix *canvas = rgb_matrix::CreateMatrixFromFlags(&argc, &argv, &defaults, &runtime_defaults);
  if (canvas == NULL)
      return 1;
// ...

while (condition) {
  Text_HasArrived (canvas, "The Ferry", "has arrived!");
  usleep(3000 * 1000);
 // 
}

  canvas->Clear();
  delete canvas;

  return 0;
}

I have tried all of the runtime_defaults.gpio_slowdown values. 0 and 1 scramble the out really bad. runtime_defaults.gpio_slowdown = 2 returns around 178 Hz runtime_defaults.gpio_slowdown = 3 returns around 216 Hz runtime_defaults.gpio_slowdown = 4 returns around 191 Hz runtime_defaults.gpio_slowdown = 5 returns around 170 Hz

Also, another thing that I've noticed. Running the process with sudo will give it a bump in Hz. runtime_defaults.gpio_slowdown = 2 returns around 231 Hz runtime_defaults.gpio_slowdown = 3 returns around 300 Hz runtime_defaults.gpio_slowdown = 4 returns around 253 Hz runtime_defaults.gpio_slowdown = 5 returns around 219 Hz

But the flicker appears to be the same with either 2,3,4 and 5 option, sudo or without.

I am not using an Adafruit Hat. I had an active adapter made. I am using Raspbian Buster Lite, I have disabled the sound thingy, and the other services using: sudo apt-get remove bluez bluez-firmware pi-bluetooth triggerhappy pigpio. Also, when trying sudo timedatectl set-ntp false or sudo systemctl stop cron I get this:

System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

What I don't know is how to not run anything else on the PI, because I don't know which process should run and which should not. And I don't understand what to do with top. It returns a bunch of things.

What can cause the flicker ? Is it code related ? But if it was code related, it should've flicker once every 3 seconds. Thank you !

hzeller commented 5 years ago

First off: yes you should always run with sudo, otherwise relevant realtime features can't be used. Also setting the isolcpus setting use is useful.

I am a bit surprised by your systemd message: as far as I know, the Raspbian Buster Lite is a systemd-basd system. When disabling things, also make sure to disable 1-wire protocol; there were some versions of Raspbian Lite that enabled it and messed with connected hardware. (W.r.t. operating system: I have heard people use the dietpi distribution with much success, as-in, apparently it reduces flicker compared to raspbian).

Ok, to answer the question: yes, this code can exhibit flicker. In your loop, you do Clear() on the currently active frame and draw things back to it. This of course will create some flicker on each update.

To avoid that, you can write your text into an offline canvas, then use the SwapOnVSync() to atomically swap it at frame sync:

static void Text_HasArrived(FrameCanvas *canvas, ...) {
    ...
}

int main(...) {
  // ... init
  RGBMatrix *matrix = rgb_matrix::CreateMatrixFromFlags(...);

   // Create a new canvas to be used with led_matrix_swap_on_vsync
  FrameCanvas *offscreen_canvas = matrix->CreateFrameCanvas();

  while (condition) {
     Text_HasArrived(offscreen_canvas, ...);  // Write stuff to offline canvas
     // Now, we pass that canvas to the matrix. It returns the previously active canvas
     offscreen_canvas = matrix->SwapOnVSync(offscreen_canvas);
     usleep(...);
  }
}

See also examples such as scrolling-text-example.c for some SwapOnVSync() example.

GeorgeFlorian commented 5 years ago

Can I not run the program as root ?

Because I have the following error: https://stackoverflow.com/questions/57822336/system-path-to-bash-sh-returns-file-txt-permission-denied-only-when-c-pro?noredirect=1#comment102076685_57822336

hzeller commented 5 years ago

The library drops the permissions from root to daemon after the hardware is initialized to minimize the security issues.

So if you want to read a file, it needs to be readable by that user.. You can make it readable to nobody (chmod a+r <file>).

Alternatively, if you want to keep running as root, set the drop_privileges in your RuntimeOptions to 0.

hzeller commented 5 years ago

I didn't hear anything, sounds like you solved your problem ? Please make sure to close the issue in these cases.

GeorgeFlorian commented 5 years ago

I didn't hear anything, sounds like you solved your problem ? Please make sure to close the issue in these cases.

I ended up using runtime_defaults.drop_privileges = 0; because I needed to open some sensitive files, like dhcpcd.conf.

I have also improved the code to only update the image if some of the output actually changed, not on every cycle of the loop.

Also, Raspbian Buster Lite is indeed a systemd based OS. I don't how or why mine wasn't working properly. I did sudo rm /sbin/init; sudo ln -s /lib/systemd/systemd /sbin/init and then a reboot and all worked out.

I haven't disable 1-wire protocol yet. I will look into it now. EDIT: Adding dtoverlay=w1-gpio to /boot/config.txt made the panel look like shit. I think you meant to remove dtoverlay=w1-gpio if one finds it in /boot/config.txt. That bit in the readme could use some brushing, because it isn't clear at all. For me at least.

Thank you !