You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@nuttx.apache.org by Michal Lenc <mi...@seznam.cz> on 2023/03/20 22:20:38 UTC

RTC synchronization with system time

Hello all,



NuttX offers a function clock_synchronize() that synchronizes system clock 
with clock from RTC (internal or external). The synchronization is done 
during board initialization and I suppose this can also be called from an 
application level if required. However I was not able to find any 
implementation that would automatically synchronize system time with 
(correct) values from RTC if system clock drifts from real time. It seems 
the only possible option is to "force" the synchronization by calling the 
mentioned clock_synchronize() function periodically from application level.




What is your view on adding some sort of automatic synchronization that 
would ensure system clock stays in sync with RTC (or at least error is less 
than some value) even when i drifts away from "real time"? Quite simple 
solution is to let clock_gettime() to update base time after N reads however
this would add some computation complexity to gettime (I2C communication 
delay for external RTC etc.) and I am not sure if we really want this inside
 clock_gettime().




Best regards,
Michal Lenc

Re: RTC synchronization with system time

Posted by Gregory Nutt <sp...@gmail.com>.
>>> NuttX offers a function clock_synchronize() that synchronizes system clock with clock from RTC (internal or external). The synchronization is done
>>> during board initialization and I suppose this can also be called from an
>>> application level if required.
>> I think clock_synchronize() is okay for startup initialization, but
>> would be inappropriate at run time.  That is because it could cause the
>> current time to apparently jump backward.  That could be fatal under
>> certain circumstances as described for adjtime() in
>> https://github.com/apache/nuttx/issues/8858
>>
> I remember once reading about how FreeBSD handles this (I think it was
> FreeBSD; this was a long time ago):
>
> If there is a difference between the system clock and the reference clock,
> the system clock is _not_ assigned the reference clock's time, exactly
> because of the "clock running backwards" problem. Rather, when the clock is
> advanced, the advancement is adjusted by a small amount, so that the system
> clock always runs forwards, never backwards, and over time the system clock
> gradually comes into synchronization with the reference clock.
>
> We probably need something like that to avoid the same problem.

We have adjtime() in sched/clock/clock_timekeeping, but it has quite a 
few problems.  See https://github.com/apache/nuttx/issues/8858

This is the same API used by both Linux and FreeBSD:

  * Linux: https://man7.org/linux/man-pages/man3/adjtime.3.html
  * FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=adjtime&sektion=2&n=1

adjtime(), as specified, fixes the problem of time going backward to 
modify the rate of the clock, not the time value of the clock. Both 
Linux and FreeBSD specify that adjtime() controls the rate of the clock 
source.  since only the rate is adjusted, the time will not go backward, 
only slow down until it is correct.

Greg

Re: RTC synchronization with system time

Posted by Tomek CEDRO <to...@cedro.info>.
On Tue, Mar 21, 2023 at 4:02 AM Nathan Hartman wrote:
> On Mon, Mar 20, 2023 at 10:36 PM Gregory Nutt wrote:
> > > NuttX offers a function clock_synchronize() that synchronizes system
> > clock
> > > with clock from RTC (internal or external). The synchronization is done
> > > during board initialization and I suppose this can also be called from an
> > > application level if required.
> > I think clock_synchronize() is okay for startup initialization, but
> > would be inappropriate at run time.  That is because it could cause the
> > current time to apparently jump backward.  That could be fatal under
> > certain circumstances as described for adjtime() in
> > https://github.com/apache/nuttx/issues/8858
> >
>
> I remember once reading about how FreeBSD handles this (I think it was
> FreeBSD; this was a long time ago):
>
> If there is a difference between the system clock and the reference clock,
> the system clock is _not_ assigned the reference clock's time, exactly
> because of the "clock running backwards" problem. Rather, when the clock is
> advanced, the advancement is adjusted by a small amount, so that the system
> clock always runs forwards, never backwards, and over time the system clock
> gradually comes into synchronization with the reference clock.
>
> We probably need something like that to avoid the same problem.

Here are some references :-)

https://github.com/freebsd/freebsd-src/blob/master/contrib/ntp/libntp/adjtime.c

https://github.com/freebsd/freebsd-src/blob/master/contrib/ntp/include/ntp_syscall.h

https://github.com/freebsd/freebsd-src/blob/main/sys/kern/kern_time.c

And the man page :-)

https://man.freebsd.org/cgi/man.cgi?query=adjtime&sektion=2&apropos=0&manpath=FreeBSD+13.1-RELEASE+and+Ports

The adjtime() system call makes small adjustments to the system time, as
     returned by gettimeofday(2), advancing or retarding it by the
time    speci-
     fied by the timeval delta.     If delta is negative, the clock is slowed
     down by incrementing it more slowly than normal until the correction is
     complete.    If delta is positive, a    larger increment than
normal is    used.
     The skew used to perform the correction is    generally a
fraction of    one
     percent.  Thus, the time is always    a monotonically
increasing function.
     A time correction from an earlier call to adjtime() may not be finished
     when adjtime() is called again.  If olddelta is not a null    pointer, the
     structure pointed to will contain,    upon return, the number
of microsec-
     onds still    to be corrected    from the earlier call.

     This call may be used by time servers that    synchronize the
clocks of com-
     puters in a local area network.  Such time    servers    would
slow down    the
     clocks of some machines and speed up the clocks of    others to
bring    them
     to    the average network time.

     The adjtime() system call is restricted to    the super-user.


Hope that helps :-)

-- 
CeDeROM, SQ7MHZ, http://www.tomek.cedro.info

Re: RTC synchronization with system time

Posted by Nathan Hartman <ha...@gmail.com>.
On Mon, Mar 20, 2023 at 10:36 PM Gregory Nutt <sp...@gmail.com> wrote:

>
> > NuttX offers a function clock_synchronize() that synchronizes system
> clock
> > with clock from RTC (internal or external). The synchronization is done
> > during board initialization and I suppose this can also be called from an
> > application level if required.
> I think clock_synchronize() is okay for startup initialization, but
> would be inappropriate at run time.  That is because it could cause the
> current time to apparently jump backward.  That could be fatal under
> certain circumstances as described for adjtime() in
> https://github.com/apache/nuttx/issues/8858
>

I remember once reading about how FreeBSD handles this (I think it was
FreeBSD; this was a long time ago):

If there is a difference between the system clock and the reference clock,
the system clock is _not_ assigned the reference clock's time, exactly
because of the "clock running backwards" problem. Rather, when the clock is
advanced, the advancement is adjusted by a small amount, so that the system
clock always runs forwards, never backwards, and over time the system clock
gradually comes into synchronization with the reference clock.

We probably need something like that to avoid the same problem.

Cheers
Nathan

Re: RTC synchronization with system time

Posted by Gregory Nutt <sp...@gmail.com>.
> NuttX offers a function clock_synchronize() that synchronizes system clock
> with clock from RTC (internal or external). The synchronization is done
> during board initialization and I suppose this can also be called from an
> application level if required.
I think clock_synchronize() is okay for startup initialization, but 
would be inappropriate at run time.  That is because it could cause the 
current time to apparently jump backward.  That could be fatal under 
certain circumstances as described for adjtime() in 
https://github.com/apache/nuttx/issues/8858

Re: RTC synchronization with system time

Posted by "David S. Alessio" <da...@gmail.com>.
Hello, Michal,


You might want to take a look at PTP (Precision Time Protocol)
	https://en.wikipedia.org/wiki/PTPd <https://en.wikipedia.org/wiki/PTPd>

and PTPd, a BSD-licensed implementation:
	https://github.com/ptpd/ptpd <https://github.com/ptpd/ptpd>

PTP is designed to sync the system clock to IEEE 1588 time.  This is overkill for what you’ve requested, but you could strip out the 1588 code, and use the shell to interface with the RTC.

Best regards,
-david



> On Mar 20, 2023, at 3:20 PM, Michal Lenc <mi...@seznam.cz> wrote:
> 
> Hello all,
> 
> 
> 
> NuttX offers a function clock_synchronize() that synchronizes system clock
> with clock from RTC (internal or external). The synchronization is done 
> during board initialization and I suppose this can also be called from an 
> application level if required. However I was not able to find any
> implementation that would automatically synchronize system time with
> (correct) values from RTC if system clock drifts from real time. It seems 
> the only possible option is to "force" the synchronization by calling the 
> mentioned clock_synchronize() function periodically from application level.
> 
> 
> 
> 
> What is your view on adding some sort of automatic synchronization that 
> would ensure system clock stays in sync with RTC (or at least error is less
> than some value) even when i drifts away from "real time"? Quite simple 
> solution is to let clock_gettime() to update base time after N reads however
> this would add some computation complexity to gettime (I2C communication 
> delay for external RTC etc.) and I am not sure if we really want this inside
>  clock_gettime().
> 
> 
> 
> 
> Best regards,
> Michal Lenc


Re: RTC synchronization with system time

Posted by Gregory Nutt <sp...@gmail.com>.
> No, I don't want to do this from application level hence why I am looking
> for an alternative. NuttX also has function clock_resynchronize() that
> should solve the problem with time going backwards but not sure if it has
> ever been tested and used.

There is an RTC timer driver in drivers/timers that you can use to read 
to the RTC and receive alarms.  That with adjtime() would support a 
application level solution.

A problem with clock_synchronization() is that it depends on the 
properties of the RTC so you probably could not make a general solution 
with it.  For example, different RTCs have different time 
representations, different resolutions, and different behaviors. Many 
have resolution only to 1 second.  Some have sub-second resolution.  
Different RTCs support different interrupts when events occur like the 1 
second increment.  Some RTCs support alarms.



Re: RTC synchronization with system time

Posted by Michal Lenc <mi...@seznam.cz>.
> You wouldn't really do this from application level, right?



No, I don't want to do this from application level hence why I am looking 
for an alternative. NuttX also has function clock_resynchronize() that 
should solve the problem with time going backwards but not sure if it has 
ever been tested and used.




Thank you for the link and issue about adjtime(), that seems like a good 
alternative and way to go.




Best regards,
Michal Lenc

---------- Původní e-mail ----------
Od: Gregory Nutt <sp...@gmail.com>
Komu: dev@nuttx.apache.org
Datum: 21. 3. 2023 0:20:43
Předmět: Re: RTC synchronization with system time
"You wouldn't really do this from application level, right? There is 
currently no POSIX-compatible application interface to do that.  But you 
could implement a kernel thread that is started in your board 
initialization logic that can call clock_synchronize() according to 
whatever criteria you need. 

I suppose a standard kernel thread could also be implemented in 
sched/clock if such a one-size-fits-all solution can be imagined. You 
might check out logic in sched/clock for CONFIG_CLOCK_TIMEKEEPING.  That 
is used primarily for adjusting the time to properly track time from 
NTP.  Seems to me that that is essentially the same issue:  Keeping two 
clocks in agreement. 

On 3/20/2023 4:20 PM, Michal Lenc wrote: 
> Hello all, 
> 
> 
> 
> NuttX offers a function clock_synchronize() that synchronizes system clock

> with clock from RTC (internal or external). The synchronization is done 
> during board initialization and I suppose this can also be called from an 
> application level if required. However I was not able to find any 
> implementation that would automatically synchronize system time with 
> (correct) values from RTC if system clock drifts from real time. It seems 
> the only possible option is to "force" the synchronization by calling the 
> mentioned clock_synchronize() function periodically from application 
level. 
> 
> 
> 
> 
> What is your view on adding some sort of automatic synchronization that 
> would ensure system clock stays in sync with RTC (or at least error is 
less 
> than some value) even when i drifts away from "real time"? Quite simple 
> solution is to let clock_gettime() to update base time after N reads 
however 
> this would add some computation complexity to gettime (I2C communication 
> delay for external RTC etc.) and I am not sure if we really want this 
inside 
>  clock_gettime(). 
> 
> 
> 
> 
> Best regards, 
> Michal Lenc 
> 
"

Re: RTC synchronization with system time

Posted by Gregory Nutt <sp...@gmail.com>.
> ....  adjtime() is not properly configured as an OS interface; it 
> would need system call hooks in syscall/ and include/sys in order to 
> be usable in all build configurations.
>
I see a few other issues with adjtime() that I documented here: 
https://github.com/apache/nuttx/issues/8858



Re: RTC synchronization with system time

Posted by Gregory Nutt <sp...@gmail.com>.
On 3/20/2023 5:15 PM, Gregory Nutt wrote:
> You wouldn't really do this from application level, right? There is 
> currently no POSIX-compatible application interface to do that.

There is no /POSIX /interface to do this, but the Linux interface 
adjtime() -- see https://man7.org/linux/man-pages/man3/adjtime.3.html -- 
is implemented in sched/clock/clock_timekeeping.c

https://github.com/apache/nuttx/blob/master/sched/clock/clock_timekeeping.c#L142

Linux application interfaces are acceptiable.  adjtime() is not properly 
configured as an OS interface; it would need system call hooks in 
syscall/ and include/sys in order to be usable in all build configurations.

It is not very sophisticated and could do so much more. Currently it 
calculates a clock adjustment that gets added to the system time.


Re: RTC synchronization with system time

Posted by Gregory Nutt <sp...@gmail.com>.
You wouldn't really do this from application level, right? There is 
currently no POSIX-compatible application interface to do that.  But you 
could implement a kernel thread that is started in your board 
initialization logic that can call clock_synchronize() according to 
whatever criteria you need.

I suppose a standard kernel thread could also be implemented in 
sched/clock if such a one-size-fits-all solution can be imagined. You 
might check out logic in sched/clock for CONFIG_CLOCK_TIMEKEEPING.  That 
is used primarily for adjusting the time to properly track time from 
NTP.  Seems to me that that is essentially the same issue:  Keeping two 
clocks in agreement.

On 3/20/2023 4:20 PM, Michal Lenc wrote:
> Hello all,
>
>
>
> NuttX offers a function clock_synchronize() that synchronizes system clock
> with clock from RTC (internal or external). The synchronization is done
> during board initialization and I suppose this can also be called from an
> application level if required. However I was not able to find any
> implementation that would automatically synchronize system time with
> (correct) values from RTC if system clock drifts from real time. It seems
> the only possible option is to "force" the synchronization by calling the
> mentioned clock_synchronize() function periodically from application level.
>
>
>
>
> What is your view on adding some sort of automatic synchronization that
> would ensure system clock stays in sync with RTC (or at least error is less
> than some value) even when i drifts away from "real time"? Quite simple
> solution is to let clock_gettime() to update base time after N reads however
> this would add some computation complexity to gettime (I2C communication
> delay for external RTC etc.) and I am not sure if we really want this inside
>   clock_gettime().
>
>
>
>
> Best regards,
> Michal Lenc
>

Re: RTC synchronization with system time

Posted by Gregory Nutt <sp...@gmail.com>.
> What is your view on adding some sort of automatic synchronization that
> would ensure system clock stays in sync with RTC (or at least error is less
> than some value) even when i drifts away from "real time"? Quite simple
> solution is to let clock_gettime() to update base time after N reads however
> this would add some computation complexity to gettime (I2C communication
> delay for external RTC etc.) and I am not sure if we really want this inside
>   clock_gettime().
>
I didn't respond to this.

I don't know if a system solution makes sense.  This is a user function 
that is supported by all common OS via adjtime().  We should implement 
the solution in the same way that other systems do.

I suspect that the properties of RTCs are too variable and that any 
solution has to be hardware specific, at least in some aspects.

clock_synchronize() or clock_resynchronize() are totally inappropriate 
for this and would clearly break system timing.  But adjtime() as 
specified (but not as currently implemented ) would be a very good 
solution to do this and is already exposed to applications.  See 
https://github.com/apache/nuttx/issues/8858

Waiting for N reads is arbitrary.  It would be better to get an event 
from the RTC, like when the second timer rolls over or an alarm 
expires.  An application should be able to get that from 
drivers/timer/rtc.c.  Sampling an RTC asynchronous does not give you 
good times due to the limited resolution of most RTC time. But sampling 
the RTC at well known points in time (like incrementing the second) 
would be synchronous and accurate.

I'm sure the solution does not belong in clock_gettime().  That would be 
mixing functionality and not in the spirit of good modular design.  And 
would not support the most common use case for adjtime():

The most common way of adjusting time via adjtime() is as part of the 
use of NTP (I see PTP also uses adjtime).  Certainly any system solution 
cannot prohibit that most common use of adjtime().  Certainly 
clock_gettime() cannot get involved with NTP which is an application 
space protocol.

There are lots of examples of adjtime implementations.  And examples of 
NTP clients on the internet using adjtime(). 
https://github.com/openntpd-portable/openntpd-portable, 
https://github.com/ntp-project/ntp.

Here is an NTP adjtime() call: 
https://github.com/ntp-project/ntp/blob/master-no-authorname/ntpdate/ntpdate.c#L2039