PaulStoffregen / Time

Time library for Arduino
http://playground.arduino.cc/code/time
1.25k stars 666 forks source link

Getting Millisecond Extension #11

Open LabbiqX opened 9 years ago

LabbiqX commented 9 years ago

I need it in some of my projects.

PaulStoffregen commented 9 years ago

I do not believe this is a good implementation. At the very least, some sort of integration with the now() function is needed, so the pair together returns numbers representing the same time. I'm not exactly sure how that should be done, but at least something is needed.

Even if this were implemented well, whether or not to include it would also depend on opinion from @michaelmargolis

Later this year, I do plan to very seriously look at improving this Time library. Discussion is here: https://github.com/PaulStoffregen/Time/issues/3#issuecomment-61147194 Perhaps this millisecond function should be considered? Michael, any thoughts?

At the moment, I'm working on Teensy-LC, so I can't do much with libraries like Time, other than bug fixes, until Teensy-LC is released.

andrewjaykeller commented 8 years ago

+1 - I need Time with a project of mine.... openbci.com time synchronization between an SDK like processing/node.js and an arduino

PaulStoffregen commented 8 years ago

@michaelmargolis - Looks ok to me. Any objections?

blackketter commented 8 years ago

I've built a little C++ library for my own use that, among other things, provides time in milliseconds as a 64-bit signed integer, for both wall-clock now() time and millis() uptime. The larger range prevents the problems with rollover and absolute and relative times can be handled as a single scalar value with simple arithmetic. I suppose it's marginally slower in some cases but I haven't had a case where that was an issue, at least on Teensy. I'd be happy to contribute any of this if there's any interest.

michaelmargolis commented 8 years ago

I avoided millisecond support in the library because the values would not be monotonic when the time was periodically synchronized to an external time provider. I felt that this could cause problems for less experienced users that tried to do ‘more accurate’ time arithmetic using millisecond values.

I am open to hearing how we could address this issue.

PaulStoffregen commented 8 years ago

The same can easily happen for seconds, if the Arduino clock and sync provider disagree too much.

PaulStoffregen commented 8 years ago

@blackketter Can 64 bit integers work on AVR? I suppose I could do some tests to find out.... Even though my own work is now mostly focused on 32 bit ARM, for widely used libraries like Time we really do need to restrict ourselves to stuff that works on 8 bit AVR.

michaelmargolis commented 8 years ago

The same can easily happen for seconds, if the Arduino clock and sync provider disagree too much. The default sync interval was chosen so resync occurs well before the clock drifts more than a second. Assuming that the sync provider remains accessible, the seconds value will remain monotonic (even if using a ceramic resonator).

blackketter commented 8 years ago

int64_t is supported and works fine on my Arduino Uno here with this simple loop incrementing a 32 and 64 bit integer for a millisecond:

 int32_t x32 = 0;
  unsigned long n = millis();
  while (n == millis()){};
  n = millis();
  while (n == millis()) {
    x32++;
  }
  Serial.print("int32_t: ");
  Serial.println(x32);

  int64_t x64 = 0;
  n = millis();
  while (n == millis()){};
  n = millis();
  while (n == millis()) {
    x64++;
  }
  x32 = (int32_t)x64;
  Serial.print("int64_t: ");
  Serial.println(x32);

On the Uno, I get results like:

int32_t: 524
int64_t: 288

And on Teensy3 (96MHz):

int32_t: 15965
int64_t: 13682

I suspect that concerns about performance, even on 8-bit AVR, are premature optimization.

Re: monotonicity shouldn't be a requirement for a wall-clock time function (daylight savings time, which is a worthy goal, breaks that pretty hard).

michaelmargolis commented 8 years ago

monotonicity shouldn't be a requirement for a wall-clock time function Indeed, but what about applications involving measurement of intervals of time?

blackketter commented 8 years ago

Indeed, but what about applications involving measurement of intervals of time?

Not sure what you mean by intervals in this case:

If 64-bit millisecond units are used for both wall-clock and uptime (i.e. now64() and millis64()), relative calculations are trivial.

This presents the problem of the RTC and the millis() clock not being in sync and for some systems (without crystals) may drift considerably. I'm not sure how big a problem that may be, but I suspect that applications that are running on systems that need very accurate millis() should probably get crystals or be calibrated appropriately.

blackketter commented 8 years ago

FWIW, I posted that Clock library I've been using that provides a C++ interface to Time and provides a 64-bit millisecond interface. Seems to work for both Teensy3 and Uno.

https://github.com/blackketter/Clock

michaelmargolis commented 8 years ago

If you want to measure time intervals … you should use millis() or its 64-bit equivalent I disagree with the above for the following reason.

Many people use this library to measure intervals of time, the TimeRTCLog example sketch provided with the library illustrates how the time of day functions can be used with the display of event intervals. I would not want to lose the consistency between time of day functions and time duration functions.

For logging applications that require consistency with a wall clock, a common technique is to add functionality to convert the internal system time (typically synched to UTC) to local time zone and DST for wall clock display.

I would agree that adding this capability to the library would be beneficial and don’t see a problem adding a cosmetic milliseconds value to some new function that renders system time as local time. Would that addresses the requirement for millisecond extension?

However, I don't feel comfortable providing millisecond precision to the internal system time if it cannot be made monotonic. Correct me if I misunderstand, but I think you are saying that because the Arduino crystal can drift, the system time can’t guaranteed to be monotonic, so having the extra precision does not create a new problem.

However the drift in a typical Arduino board with crystal is in the order of a couple of seconds per day, syncing every 5 minutes (the default) ensures that time will be set to the current second well before it could drift non-monotonically. But I don’t see how that would be practical with millisecond precision system time. This may not be an issue in a clock display but could look like a bug in an application that dealing with event intervals that could be within a second or a month.

blackketter commented 8 years ago

All good.

millis() (and micros()) uptime sources are monotonic (i.e. they go up and never go down), but may not be linear or accurate to real-world time (depending on the hardware and environment.) They also likely have higher resolution.

An RTC may be more accurate, but may not be monotonic (i.e. may go down due to changes to DST, user resetting or drift compensation). Current RTCs have second resolution, but an RTC based on NTP would certainly have sub-second resolution.

I think any new API should provide identical units for time (i.e. milliseconds or microseconds) and allow the user to use the timebase appropriate for their application, depending on the need.