I've not yet used a RTC so I'm not completely sure of the "normal" way to read a real time clock. There's a few different approaches I've thought of but was hoping for some advice on it.

Here are the ways I've thought of reading and using the time so far:

  1. Get the date and time at power up and save to RAM, and then through the use of the timer interrupt increment the RAM values every second etc. The code would then use the values in RAM whenever it needed to know the date/time.
  2. Through the use of a timer interrupt, query the RTC every second and copy the received date and time to RAM. Again, the code would then use the values in RAM whenever it needed to know the date/time.
  3. Every time I need to find out the time, query the RTC and use it's response directly.

Which would be the best approach?

  • 15
    \$\begingroup\$ The best approach is the one that meets your specifications while using a minimum amount of resources. Since we don't really know your needs, "best" has very little meaning to us. \$\endgroup\$ Mar 11 '15 at 18:59
  • \$\begingroup\$ All very good answers I can't pick an answer! \$\endgroup\$
    – user9993
    Mar 12 '15 at 1:08

I would use a fourth option.

Most RTC chips have the option of outputting a 1 second pulse. You should connect that pulse to an interrupt enabled input on your MCU.

  • You get the time from the chip once at the start of your program, and maybe occasionally from then on - maybe once an hour.
  • The interrupt signal then triggers an interrupt routine in your MCU in which you increment the time by one second.

That arrangement gives you the accuracy to the second of the RTC without the overhead of actively reading the RTC.

  • 5
    \$\begingroup\$ When using this approach, it's important to know which clock edge represents an increment and also to ensure that any reading which is in progress during that clock edge should be abandoned. \$\endgroup\$
    – supercat
    Mar 11 '15 at 21:38
  • \$\begingroup\$ Or ensure that the reading is only triggered by the ISR - you get a one second gap to do the reading before the next ISR is triggered. \$\endgroup\$
    – Majenko
    Mar 12 '15 at 10:29
  • \$\begingroup\$ Whenever possible, I prefer to set real-time clocks to run faster than one tick per second and use them for general-purpose event timing, if the RTC resolution can be set fine enough to match event-timing needs; there may thus not always be an interrupt occurring on every RTC tick. Further, when setting alarms, it's often important to know exactly what the RTC time is at the moment the alarm is being set, and poll the RTC to see if it moved while the alarm was being set. I don't know why 32-bit chip vendors don't simply offer a 47-bit counter with the ability to read either... \$\endgroup\$
    – supercat
    Mar 12 '15 at 13:33
  • \$\begingroup\$ ...the upper 32 bits or the lower 31 plus the clock-input state, have an alarm that may be turned on and off at any time without synchronization delay, and an alarm register that may be written at any time when the alarm is off, with semantics that the alarm occurs if an increment occurs while the alarm is enabled. If a chip can accept asynchronous wakeups and software does double-check polling when appropriate, no other hardware synchronization would be required, and software wouldn't have to work around issues caused by other forms of hardware synchronization. \$\endgroup\$
    – supercat
    Mar 12 '15 at 13:37

3rd and 2nd are more viable.

3rd approach is what I use in most cases. It's benefit is that I don't need to worry about mirroring the RTC in the RAM. It's potential shortcoming is that interrogating the RTC through serial bus introduces a delay. If you are writing data once a second, this delay will probably not matter.

2nd approach is good too. Maintaining a mirror clock may introduce a timekeeping error, if the device is running for a long time. Mirror clock can drift apart from, the RTC. If you read the RTC regularly, then the drift will not accumulate.
However, I would advise against doing serial communication in the interrupt service routine (ISR) itself. Set a flag in the ISR and do the serial communication in the main().

p.s. In all cases, I was using DS1307.


Some RTCs (e.g. MC68HC68T1 [which admittedly almost no one should be using anymore]) will pause their internal counting when being read from so as to give a consistent response. They must be read from as rarely as possible so as to minimize disruption. Read from them once and then use timer interrupts to update the time value stored in RAM of the MCU.

  • \$\begingroup\$ Such designs boggle the mind. Having reads that occur during an increment yield random data would be an easy problem to work around. Having reads cause counts to be missed is a problem that can't be worked around except by accepting lost counts. \$\endgroup\$
    – supercat
    Mar 11 '15 at 21:37
  • 2
    \$\begingroup\$ Apparently double buffering is something some people don't think of when they design their chips. \$\endgroup\$ Mar 11 '15 at 21:42
  • \$\begingroup\$ If code checks when polling to ensure a value hasn't changed, there's no need for double buffering. For an on-chip real-time clock, such repeat-until-no-change polling will work even if an interrupt tries to read the RTC at the same time as main-line code is doing so. Some double-buffered designs make it difficult to write main-line and interrupt code that can safely co-exist, and I've never seen one which I'd really consider "helpful". \$\endgroup\$
    – supercat
    Mar 11 '15 at 21:51

I'm going to assume the RTC is either a separate chip with its own crystal, or a module integrated with your microcontroller that again has a separate time source (such as as a 32 kHz crystal) than the main clock. And the time source for the RTC is more accurate than the one for the microcontroller.

To determine how often you need to read the RTC, you need to figure out what the maximum error your main clock can have. For example, if the main crystal is spec'ed at 20 ppm, that is the same as 0.002%. So a clock just based on the main clock source could drift 0.00002 * 3600 * 24 = 1.728 seconds a day.

So if you read the RTC only twice a day, and in between incremented the time once a second using a timer interrupt, you would never be off more than a second -- never be off more than a second compared to the RTC that is.

If, as I assumed earlier, your RTC is either a separate chip with its own crystal, or a module integrated with your microcontroller, that doesn't mean it is correct. An RTC can have an error too. For example, if it is using a 32 kHz crystal with a tolerance of 5 ppm (which are just slightly more expensive than 10 ppm ones), it could be off by 0.43 seconds per day -- or 13 seconds per month.

To get around this, you will need to tune the RTC, where you write a correction factor back to a register. Doing so will allow you to get the error practically to zero. But of course you'll have to have a third external clock source to use as a reference when doing the tuning. An extremely accurate reference in the US is the 60 Hz AC line, which is guaranteed to be exactly 60*60*60*24 (5,184,000) cycles in a 24 hour period between successive midnights. For this to be useful, you must time for the entire 24 hours, as the 60 Hz can drift some between midnights.

Another excellent time reference would be using GPS (10 ns accuracy), if one already had GPS hardware in their project.

If instead your RTC times comes from an external source, like the cellular network time (AT+CCLK? call), or a network time server using NTP, then you can use the RTC value as is since there will be nothing to "tune".


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.