CamelCaseName / HUB75nano

This Arduino library adds the basic functionality needed to drive a HUB 75 protocol LED Panel up to 64x32 Pixels RGB.
GNU General Public License v3.0
37 stars 6 forks source link

Line 16 blinking when refresh #18

Closed impressgroupsc closed 10 months ago

impressgroupsc commented 10 months ago

Hi again,

Here I bring you a new incident. I am making a countdown timer and when changing something on the screen every second line 16 of the panel (counted from 1 to 32) turns on at maximum intensity and returns to normal intensity in a fraction of a second making a flicker effect.

https://github.com/CamelCaseName/HUB75nano/assets/142884178/38c3588c-6a85-4b9a-97d0-8789d7bf190a

This only happens with line 16 since the rest work fine. And it does it whatever the color and whatever it is drawn. I attach the code with which I have tested.

I have tried to record a video so that the effect can be seen.

Do you know what could be happening?

Thanks

This is the code I've used.

#define PANEL_BIG 1
#define MAX_BRIGHTNESS_SLEEP_MUSEC 100
#define BRIGHTNESS_SLEEP_MUSEC 100

#define RA 14 // row selector a
#define RB 15 // row selector b
#define RC 16 // row selector c
#define RD 17 // row selector d 12
#define RE 18 // row selector e 19
#define RF 2 // red first byte
#define GF 3 // green first byte
#define BF 4 // blue first byte
#define RS 5 // red second byte
#define GS 6 // green second byte
#define BS 7 // blue second byte
#define CLK 9 // clock signal 8
#define LAT 10 // data latch 17
#define OE 11 // output enable 9

#include "HUB75nano.h"

int color_r       =  0;
int color_g       =  0;
int color_b       =  0;

unsigned long startMillis;  // Guardará el momento en que el temporizador comenzó
unsigned long currentMillis;
const unsigned long period = 1000;  // El periodo de tiempo para cada segundo (1000 ms)
unsigned int seconds = 40;  // Duración del temporizador en segundos

// create an instance of the panel
Panel panel = {};

void setup() {
    // Iniciamos el monitor serie para monitorear la comunicación
    Serial.begin(9600);

    panel.fillBuffer(panel.BLACK); // background red

    startMillis = millis();  // Inicializa el temporizador

    color_r       =  0;
    color_g       =  3;
    color_b       =  0;
  }

void loop() {
    panel.displayBuffer(); // makes the buffer visible and the leds all blinky blinky

    currentMillis = millis();
    if (currentMillis - startMillis >= period && seconds >= 0) {
        // Ha pasado un segundo
        seconds--;  // Reduce los segundos restantes
        Serial.println(seconds);  // Muestra los segundos restantes
        startMillis = currentMillis;  // Reinicia la referencia de tiempo para el próximo segundo

        if (seconds > 30) {
          panel.drawRect(8, 8, 48, 24, panel.GREEN, true);
        }
        else if (seconds > 0 && seconds <= 30) {
          panel.drawRect(8, 8, 48, 24, panel.ORANGE, true);
        }
        else {
          panel.drawRect(8, 8, 48, 24, panel.RED, true);
        }

        if (seconds == 30) {
            color_r       =  3;
            color_g       =  2;
            color_b       =  0;
        }
        if (seconds == 0) {
            // El temporizador ha llegado a cero
            color_r       =  3;
            color_g       =  0;
            color_b       =  0;
        }
    }
  }
CamelCaseName commented 10 months ago

alright, i tried it out and fixed the single line blinking, however now the whole panel blinks once a second. this happens when you draw the big rectangle as it takes enough milliseconds to notice the LEDs going dark. the leds cannot stay on during that time as only one row is on at a time.

i remedied the issue in your code by only drawing once, when the color has to change, then there is no more flicker

the next bigger update is going to try and improve drawing speeds, but for you i publish a hotfix which at least fixes the single line being brighter

The code i used to get rid of blinking:

 #define PANEL_BIG 1
#define MAX_BRIGHTNESS_SLEEP_MUSEC 100
#define BRIGHTNESS_SLEEP_MUSEC 100

#define RA 14  // row selector a
#define RB 15  // row selector b
#define RC 16  // row selector c
#define RD 17  // row selector d 12
#define RE 18  // row selector e 19
#define RF 2   // red first byte
#define GF 3   // green first byte
#define BF 4   // blue first byte
#define RS 5   // red second byte
#define GS 6   // green second byte
#define BS 7   // blue second byte
#define CLK 9  // clock signal 8
#define LAT 10 // data latch 17
#define OE 11  // output enable 9

#include "HUB75nano.h"

int color_r = 0;
int color_g = 0;
int color_b = 0;

unsigned long startMillis; // Guardará el momento en que el temporizador comenzó
unsigned long currentMillis;
const unsigned long period = 1000; // El periodo de tiempo para cada segundo (1000 ms)
uint8_t seconds = 40;              // Duración del temporizador en segundos
uint8_t draw_state = 0;

// create an instance of the panel
Panel panel = {};

void setup()
{
    // Iniciamos el monitor serie para monitorear la comunicación
    Serial.begin(9600);

    panel.fillBuffer(panel.BLACK); // background red

    startMillis = millis(); // Inicializa el temporizador

    color_r = 0;
    color_g = 3;
    color_b = 0;
}

void loop()
{
    panel.displayBuffer(); // makes the buffer visible and the leds all blinky blinky

    currentMillis = millis();
    if (currentMillis - startMillis >= period && seconds >= 0)
    {
        // Ha pasado un segundo
        seconds--;                   // Reduce los segundos restantes
        Serial.println(seconds);     // Muestra los segundos restantes
        startMillis = currentMillis; // Reinicia la referencia de tiempo para el próximo segundo

        if (seconds > 30 && draw_state == 0)
        {
            panel.drawRect(8, 8, 48, 24, panel.GREEN, true);
            draw_state = 1;
        }
        else if (seconds > 0 && seconds <= 30 && draw_state == 1)
        {
            panel.drawRect(8, 8, 48, 24, panel.ORANGE, true);
            draw_state = 2;
        }
        else if (seconds > 40 && draw_state == 2)
        {
            panel.drawRect(8, 8, 48, 24, panel.RED, true);
            draw_state = 3;
        }

        if (seconds == 30)
        {
            color_r = 3;
            color_g = 2;
            color_b = 0;
        }
        if (seconds == 0)
        {
            // El temporizador ha llegado a cero
            color_r = 3;
            color_g = 0;
            color_b = 0;
        }
    }
}

the addition of the drawing state tracker leads to no more flickering

new hotfix version should be out soon,

impressgroupsc commented 10 months ago

Ok, thanks for your prompt response. The solution you present to me is correct, however the problem is not solved since if I make a countdown timer I have to draw the corresponding number every second (40 - 39 - 38 - 37 - 36 ..... - 3 - 2 - 1 - 0) and although I have optimized it so that it only draws the digit that changes, it still produces the blinking on line 16 in its entirety.

I have verified that the same effect occurs on line 32 in addition to line 16.

I thought that the problem could be due to some redrawing of that line and that is why I commented on it.

The example that I had given you had been simplified as much as possible so that you could see the effect.

In any case, I'll be on the lookout for the new version.

Thank you.

CamelCaseName commented 10 months ago

https://github.com/CamelCaseName/HUB75nano/releases/tag/2.2.1 fixes your issues, with the faster drawing you can now update the screen while running with ease

see the attached video which redraws the time every second, the flicker is not noticeable in real life, only for the camera

https://github.com/CamelCaseName/HUB75nano/assets/48067449/07b0cb1d-69d9-437d-bff8-187ab257cde2

the numbers were drawn with this snippet after the if/else blocks drawing the rectangle

        panel.drawBigChar(12, 9, ((seconds / 10) % 10) + 48, Colors::WHITE, 3);
        panel.drawBigChar(26, 9, (seconds % 10) + 48, Colors::WHITE, 3);

(excuse the wrong pixels on my panel, some are just broken by now after 4 years)

impressgroupsc commented 10 months ago

Great news. I have already done the test and it works very well. Just one more question (sorry for the inconvenience), I have a function that draws on the screen from an array and I use the panel.setbuffer function; It used to work fine for me but now it gives me an error when passing the color. How should I do it?

This is the function:

void drawBitmap(int x, int y, uint8_t colorR, uint8_t colorG, uint8_t colorB, const uint16_t* bitmap, size_t width, size_t height) {

    for (size_t i = 0; i < height; i++) {
        uint16_t value = pgm_read_word_near(&bitmap[i]);

        for (int j = 15; j >= 0; j--) {
            if (value & (1 << j)) {
                panel.setBuffer(x+15-j, y+i, Colors::RED); // HERE MARKS ERROR
            } else {
                panel.setBuffer(x+15-j, y+i, Colors::BLACK); // HERE MARKS ERROR
            }
        }
    }
}
CamelCaseName commented 10 months ago

Oh sorry, i accidentally made it private in the last release when shuffling methods around

https://github.com/CamelCaseName/HUB75nano/releases/tag/2.2.2

has it public again

Also regarding bitmaps, the panel is capable of displaying bitmaps on the whole screen with higher color definition, but a method like yours is missing so far. like flash and sram mixed mode, but that is in planning.

Anyways wish you good fun and luck with your panel and if you have any more issues, just open an issue :D