What is the fastest way to send RGB frames to a HUB75 panel?

Hi, I’ve the SM shield V5 (Teensy 4) up and the example sketches are working.

Is there any documentation available beside the comments in the code?

I’m specifically looking for the most performant way to write and push out RGB data to the LEDs.

I want to maximize the fps, all layer handling I prefer to do myself (for now). Basically I need a place to write the data into and somehow a possibility to check if the last frame is on display already. No need to render new frames if they get droped anyway. Is there a way for dynamic fps or is the timing fix?

Thanks for any hint!

For traditional panels with external scanning, the maximum fps is not determined by the controller, but by the limitations of the panel. Most panels do not support clock speeds over 15-20 MHz, while Teensy4 or RP2040 could provide up to 30-50 MHz.
Thus, there is a natural limit to the speed of updating a panel, depending on the number of pixels and color depth.

Great progress in increasing the refresh rate should be expected from new types of drivers that use internal scanning. In such panels, there is no need to constantly update parts of the image at a high frequency - the panel drivers contain a built-in memory buffers where the entire image is loaded. After uploading the data, the panel performs scanning itself, relieving the controller from routine work.

I’m currently getting 241 fps and no matter how simple the animation is - I’m stuck with that. I would the fps expect to change depending on animation complexity, but they don’t.

Currently I’m using the FastLED example. 32x32, 24 bit.

This are the settings:

#include <MatrixHardware_Teensy4_ShieldV5.h>        // SmartLED Shield for Teensy 4 (V5)
//#include <MatrixHardware_Teensy3_ShieldV1toV3.h>    // SmartMatrix Shield for Teensy 3 V1-V3
//#include <MatrixHardware_Teensy4_ShieldV4Adapter.h> // Teensy 4 Adapter attached to SmartLED Shield for Teensy 3 (V4)
//#include <MatrixHardware_ESP32_V0.h>                // This file contains multiple ESP32 hardware configurations, edit the file to define GPIOPINOUT (or add #define GPIOPINOUT with a hardcoded number before this #include)
//#include "MatrixHardware_Custom.h"                  // Copy an existing MatrixHardware file to your Sketch directory, rename, customize, and you can include it like this
#include <SmartMatrix.h>
#include <FastLED.h>

#define COLOR_DEPTH 24                  // Choose the color depth used for storing pixels in the layers: 24 or 48 (24 is good for most sketches - If the sketch uses type `rgb24` directly, COLOR_DEPTH must be 24)
const uint16_t kMatrixWidth = 32;       // Set to the width of your display, must be a multiple of 8
const uint16_t kMatrixHeight = 32;      // Set to the height of your display
const uint8_t kRefreshDepth = 36;       // Tradeoff of color quality vs refresh rate, max brightness, and RAM usage.  36 is typically good, drop down to 24 if you need to.  On Teensy, multiples of 3, up to 48: 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48.  On ESP32: 24, 36, 48
const uint8_t kDmaBufferRows = 4;       // known working: 2-4, use 2 to save RAM, more to keep from dropping frames and automatically lowering refresh rate.  (This isn't used on ESP32, leave as default)
const uint8_t kPanelType = SM_PANELTYPE_HUB75_32ROW_MOD16SCAN;   // Choose the configuration that matches your panels.  See more details in MatrixCommonHub75.h and the docs: https://github.com/pixelmatix/SmartMatrix/wiki
const uint32_t kMatrixOptions = (SM_HUB75_OPTIONS_NONE);        // see docs for options: https://github.com/pixelmatix/SmartMatrix/wiki
const uint8_t kBackgroundLayerOptions = (SM_BACKGROUND_OPTIONS_NONE);
const uint8_t kScrollingLayerOptions = (SM_SCROLLING_OPTIONS_NONE);

SMARTMATRIX_ALLOCATE_BUFFERS(matrix, kMatrixWidth, kMatrixHeight, kRefreshDepth, kDmaBufferRows, kPanelType, kMatrixOptions);
SMARTMATRIX_ALLOCATE_BACKGROUND_LAYER(backgroundLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kBackgroundLayerOptions);
//SMARTMATRIX_ALLOCATE_SCROLLING_LAYER(scrollingLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kScrollingLayerOptions);

How did you measure that?

241 fps for 32x32 24 bpp matrix theoretically required more than 31 MHz clock frequency

Not physically, but with matrix.countFPS();

What irritates me is that this number does not change, no matter what the animation complexity is. I’m doing something wrong.

Sorry, I don’t know how SmartMatrix exactly works.
It is question to @Louis how FPS calculated…

Animation complexity has nothing to do with FPS rate for such panels, the only pixel depth and screen size matters.

This value is not a fps of your animation, it is a update rate of the panel itself. By their nature, these panels require constant refresh - with FPS at least 50-100 Hz, even if they show a still image.

There’s software documentation in the README, the GitHub wiki, and in the code, particularly in FeatureDemo which uses most of the libraries features.

You can set the refresh rate manually, and if it’s too high it will back off to something reasonable.

To update the matrix with new pixels you need to draw the pixels, call swapBuffers, and only on the next time the matrix is refreshed will the new pixels be displayed.

That is already well above what the human eye can observe, so I’m no sure why you are unhappy.

Are you seeing flickering or lack of brightness or are you just trying to match update rates on different platforms?

Thank you @Louis, I will check this.
edit: I tryed different values for kRefreshDepth, but the resulting 241 fps update speed doesn’t change?! What am I missing?

@netmindz Hi, as you know I currently run demanding multi layer 32 bit noise animations, meaning with 1k LEDs even a Teensy 4 starts to sweat and I have to consider to deploy the available computing time wisely.

Also I see a difference between “what the human eye can observe” and “how it feels while looking at is”. In my perception high framerate monitors / displays (even if they are just interpolating between the frames) create super smooth and fluent transitions between different pixel values. It just looks good. And still even if I my move my hand in front of it I see nearly no strobing effect at all. So yeah - the more fps, the better.

1 Like

My rendering on SmartMatrix is still not as efficient as it could be - there is still a significant amout of time wasted by waiting for the new buffer. I need to sync this better which is kind of difficult because my rendering time per frame varies. I follow the FastLED_Functions example using only one background layer - assuming that this is the most efficient way to interact with SmartMatrix.

Here some measured times (kpps = kiloPixel per second):

Any idea how to use the time better? Is dynamic refresh rate control possible somehow?

Here a video of the corresponding 12 layer animation: 12 layers + temporal dithering, 240 fps @1024 LEDs - YouTube

I don’t think so.

Is a 4.2 ms period not enough fast for you? Your animation on the video doesn’t looks as demanding a fast update.
Could you please to publish a code which the others can test?

I will publish ALL the code when it’s finished and honed (and contains no dirty hacks anymore).

You are correct that that for this animation it doesn’t matter, but for super-responsive (minimal latency) audio visualisation it does matter and literally “the more fps the better” is true, at least up to 2000 fps, then it becomes stupid. :wink:

As an example have a look here - I run this on a 128*64 OLED with 650 fps. And still the scrolling could be faster… OLED 100 fps vs. 650 fps - YouTube

Back to my question. With a less complex animation I spend more then 50% waiting - so I would really love to double the framerate then in case the LED panels are able to still digest this higher bandwith.

No matter what I tryed, I always get 240 fps. (Which is great, don’t get me wrong!)

I might be wrong but I think I remember that once there was a parameter like kRefreshRate (?!) but I can’t find any documentation about it - not in the GitHub wiki, nor in the README.md, nor in the example files.

Basically I’d like to know if 240 fps is the upper hard limit or not.