LED Matrix Loop blocked by a Time-consuming Function

Hi.

I am building a digital clock using ATmega328P with DS1307 and bunch of shift registers for the segments display.

I store the data of the LED matrix in a 32bit x 16 array, then shift out one row per loop. The whole display requires 16 loops to refresh.

My code structure looks like this:

#include <Wire.h>
#include <SPI.h>
#inlclude <EEPROM.h>
#include "RTClib.h"

#define UPDATE_INTERVAL 1000000

//Global variables
RTC_DS1307 rtc;
static uint32_t update_ref_time;
static DateTime time_utc;
static uint32_t matrix_data[16];

void setup() {
 //Set pin, SPI, RTC etc.
}

void loop() {
 static row = 0;
 uint32_t microsec = micros();
 
 if (microsec - update_ref_time > UPDATE_INTERVAL) {
 update_ref_time = microsec;
 time_utc = rtc.now(); //Update time from RTC every UPDATE_INTERVAL
 }
 
 update_display_data(); //Update display data

 some_other_functions(); //Scan buttons, check_alarm etc. 

 refresh_row(row); //Shift out the row
 
 row = (row < 15) ? row + 1 : 0;

 //Print loop exec time
 Serial.println(micros() - microsec, DEC);
}

The code works, but the display is flickering.

The loop executed without "time_utc = rtc.now();" takes around 430 us, but the loop with it takes about 1480 us. The RTC update blocks the scanning of display which causes noticeable brightness bump on some random segments.

I tried setting the UPDATE_INTERVAL to 0, so all the loops would take approximately 1480 us, the flikering did disappear but the display was flashing because the refresh rate was too low.

I also tried scanning all row in one loop like

void loop() {
    time_utc = rtc.now();
    update_display_data();
    some_other_functions();

    scan_all_16_rows();
}

But the LEDs in the last row was much brighter than the others since the loop was always blocked after last row scan.

How can I solve the problem?

Thank you!

Update: I attached the WIP code. I am a beginner in programming so my code is very nasty. :cold_sweat:

And here's a photo of the staff I've been workin on

DigitalClock.zip (11.4 KB)

How can I solve the problem?

Take your snippets to the fine folks at http://snippets-r-us.com. I'm sure that they'll be able to help you.

The RTC info you want updated once a second? Then only read it once a second:

unsigned long last_time = 0L;

void loop()
{
    if (millis() - last_time) >= 1000)
    {
        last_time += 1000 ;  // schedule action every 1000ms
        time_utc = rtc.now();
        update_display_data();
    }
    some_other_functions();

    scan_all_16_rows();
}

The there will only be that 430µs hiccup once a second.

if hope you are not delaying the bit-shifting at all ! there should be no need.
32 times : -set the data bit, toggle the clock bit twice, it should not take very long.
Please show us that snippet. (how time efficient is it ?)
But regardless, on my 7 segments (which admittedly are only 4x8 which is quite a lot less) i simply have the common cathode (i think..) connected via a BC547 transistor to the ground driven by a PWN pin. I use it to dim the display as well as that i just momentarily turn it off and set it back to the desired brightness afterwards. The afterglow of the LED's should be enough to not show anything noticeable.

MarkT:
The RTC info you want updated once a second? Then only read it once a second:

Only write to the matrix if the data has changed ! Read as often as you like..

MarkT:
The RTC info you want updated once a second? Then only read it once a second:

You don’t need to read the RTC anywhere near this often. Use the Time.h library (install from Arduino Library Manager). It keeps track of time with internal millis() and will efficiently provide you with the current time whenever you want. Then, you just need the RTC to “true-up” the internal time periodically. Every couple hours is probably more than often enough. The library includes examples showing how to do this.

Thanks everyone. I solved this problem by using TimeLib [Github Link] mentioned by gfvalvo.

I retrive the time from RTC on arduino startup then sync every 30 minutes. Now I can refresh time data as often as I want since no more I2C communication is involved.

VVe1rd0:
I retrive the time from RTC on arduino startup then sync every 30 minutes.

As I mentioned, you could make that every couple hours and it would be fine.