Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

RTC slows down after a few minutes and doesn't keep the correct time pace

dvalero484

Newbie level 6
Newbie level 6
Joined
Oct 20, 2024
Messages
14
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
119
Hello everyone.

I'm working on an automatic irrigation system using Arduino Mega 2560, TFT screen ILI9488, RTC module DS3231 and a KY-023 joystick module in a physical assembly (schematics are shown below).

1738284344773.png



Everything works fine. The problem is that the RTC doesn't keep the correct time. When the system is switched on, after a few minutes it starts to get delayed by seconds. The more time it is on, the more delay it gets. I'll leave the code I used here. It's a long code, mainly because of the screen part (it's also in Spanish, as it's my first language, you could ask some AI to translate the comments for you, sorry for that).

I would be very grateful for your help. Thanks in advance.
 

Attachments

  • Programador_de_Riego_ATmega328p.txt
    50.6 KB · Views: 31
after a few minutes it starts to get delayed by seconds. The more time it is on, the more delay it gets.
There are several calls to the rtc.adjust() function in the above code, depending on the value of the digital input 'pulsador'. Did you try to comment them separately in order to determine where exactly the RTC clock is being updated?
 
Hi,

i personally vote for an timer interrupt.
* I´d run a software clock from it (maybe only at startup and once every day synchronize to the external RTC)
* and I´d make the control loop state machine run from it.
It will consume
Currently you spend (I guess) 99.5% of the time in a delay() loop .. just wasting processing power. Resulting in slow reaction on key_press - maybe even miss a key_press or other events.

**
Schematic wise it seems you are afraid of capacitors.
* no power supply decoupling
* no ADC low pass (noise filtering)
* no relay snubber
Thus external noise (and noise generated by switching the relay) will influence the stability of the system

***
are you sure 10k pullup for the I2C lines is according specification?

***
Did you read the RTC datasheet? Especially about I2C access and timing, and PCB and assembling recommendations.
.. also: wiring of N.C. pins, OSF bit handling, power supply decoupling...

Klaus
 
Hi,

i personally vote for an timer interrupt.
* I´d run a software clock from it (maybe only at startup and once every day synchronize to the external RTC)
* and I´d make the control loop state machine run from it.
It will consume
Currently you spend (I guess) 99.5% of the time in a delay() loop .. just wasting processing power. Resulting in slow reaction on key_press - maybe even miss a key_press or other events.

**
Schematic wise it seems you are afraid of capacitors.
* no power supply decoupling
* no ADC low pass (noise filtering)
* no relay snubber
Thus external noise (and noise generated by switching the relay) will influence the stability of the system

***
are you sure 10k pullup for the I2C lines is according specification?

***
Did you read the RTC datasheet? Especially about I2C access and timing, and PCB and assembling recommendations.
.. also: wiring of N.C. pins, OSF bit handling, power supply decoupling...

Klaus
Hi Klaus, thanks for replying.

I don't really want to use interruptions yet, I don't know much about it, I'm only starting to study how it works, and I need to submit this project soon. Delays work just fine. Interruptions may be better, but that'll be for later.


About the schematics, you're right, I'll implement all you're saying, that may fix something or make it work better.
 
I give a thumbs up to Klaus about interrupts. If you keep accessing the RTC you will eventually miss hardware updates. The method I use with DS3231 is to configure it to give 1Hz interrupts, read the time into variables and update the variables at each interrupt. In other words, apart from storing the time for use at start up, all the time counting is done in software. Interrupts are intimidating if you don't understand them but they are actually very easy to use and well worth learning.

Brian.
 
Hi

I personally treat the external RTCs rather critically.
The more often I read from them ... the higher the chance for an "accidental" corruption.
And every write to them will cause the timing to be incorrect - unless I have a more reliable master clock I can rely on.
The (write) access to the external RTC needs to follow some rules (noise, bit timing, byte timing, ACK ...) to be sure not to corrupt accuracy.

You always have to expect noise, power fail - even in the middle of an I2C access.
So I imagine to be on an island. But I have one clock I can refer to. I rather build a house for it (for more constant temperature) I rather put it in a box with a glass window, so I can see the time .. but no humidity, dust, bug, animal .. can manipulate it´s operation.
I surely don´t fiddle around with it every minute. I keep it is still as possible.

I simply reduce the risk of failure.

Brian´s approch to use the 1Hz output to synchronize the software clock with the RTC is perfect. You can be sure there is no runaway.
Your clock has a 32768 Hz output .. it can be used the same way.

****
Some software hints:

Hint how to maintain accuracy:
Let´s say you use the 32768 Hz as input to your microcontroller.
It may increment a counter with each pulse. Asynchronously.

Now you can do:
< if (c_counter == 32768) --> sec_counter++, c_counter = 0 >
in this case: there is a risk to miss the exact counter value of 32768 ... then the counter goes up to 65535, rolls over to 0 (1 second passed) then up to 32768 (another second passed)
sou you risk to miss two seconds.

Better do:
< if (c_counter >= 32768) --> sec_counter++, c_counter -= 32768 >
in this case .. even if you are late for 100 ticks ... it will perform the clock rather accurately (but not precise, since there is a delay/jitter of 100 ticks).

Still it is not perfect.
the command <c_counter -= 32768> usually results in a read-modify-write action.
It reads the counter value, it peforms the subtraction, it writes the result back into the counter variable.
But this needs time. Probably less than a microsecond, but still there is a chance that exactly during this time there is an external clock edge .. you may miss to count.
This means a maximal accuracy error of 1/32768s .. which is about 30 microseconds.

Depending on microcontroller you may replace the math with a logic function:
< c_counter &= 0x7FFF >.
On some microcontrollers this does not lead to a read-modify-write.
On AVRs for example this may be replaced by the one clock cycle command CBI or CBR instruction.
In case an AVR compiler does it otherwise ... you may use the inline assembler option.

.. still bad things may happen, thus for sure you should synchronize both clocks once in a while. Maybe once a day.

If such things are very critical, then I usually read the time from the external RTC ... compare it with the software_RTC .. and only in case of mismatch I correct the sw_RTC values .. and additionally I increment a variable in EEPROM.
So I can have a bunch of applications running ... and have access to whether there was an out-of-sync problem ... and how often.


Klaus
 


Write your reply...

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top