Teensy 3 RTC incorrect time question

Status
Not open for further replies.

e30Andrew

Member
Hello all! hope this is the right section to post this...

Today i finally soldered on my crystal and battery, and they both appear to be working and keeping time, which is fantastic.

The problem that I'm running into is that the RTC is about 3.5 months behind...

right now: 1/22/2013 @ 8:37pm

Teensy RTC: 10/1/2012 @ 1:03am

this is using the TimeTeensyRTC default example sketch in the latest Beta12 release.

I am currently using Windows 8, so i dont know if it reads the system time differently, but I may try it tomorrow on my Windows 7 machine if that might be the case.

Any help would be great, thanks.
 
Hello all! hope this is the right section to post this...

Today i finally soldered on my crystal and battery, and they both appear to be working and keeping time, which is fantastic.

The problem that I'm running into is that the RTC is about 3.5 months behind...

right now: 1/22/2013 @ 8:37pm

Teensy RTC: 10/1/2012 @ 1:03am

this is using the TimeTeensyRTC default example sketch in the latest Beta12 release.

I am currently using Windows 8, so i dont know if it reads the system time differently, but I may try it tomorrow on my Windows 7 machine if that might be the case.

Any help would be great, thanks.

That date (Oct 1, 2012) is the default start time (when Teensy 3 was born ?) -- defined in pins_teensy.c
 
That date (Oct 1, 2012) is the default start time (when Teensy 3 was born ?) -- defined in pins_teensy.c

On my TO-DO list is a patch for Arduino to automatically define TIME_T to the time the program was compiled, and use that instead of a fixed date. The idea is the RTC would be automatically initialized to within a second or two of your computer's time, if the crystal is present and it's not previously been initialized. Of course, if you ever remove the Vbat power and reboot without reprogramming, the new default init time would be the moment when you compiled the program.... but at least it would give a nice "out of the box" initialization for working on projects.
 
On my TO-DO list is a patch for Arduino to automatically define TIME_T to the time the program was compiled, and use that instead of a fixed date. The idea is the RTC would be automatically initialized to within a second or two of your computer's time, if the crystal is present and it's not previously been initialized. Of course, if you ever remove the Vbat power and reboot without reprogramming, the new default init time would be the moment when you compiled the program.... but at least it would give a nice "out of the box" initialization for working on projects.

May I can help a little bit, I did some progging around the TimeTeensyRTC Sample, and get this to work to use the Compiler Time from the Arduino IDE after soldered the crystal to the Teensy
Code:
/*
 * TimeRTC.pde
 * example code illustrating Time library with Real Time Clock.
 * 
 */

#include <Time.h>

// Unixtimeseconds from 1. Januar 1970  00:00:00
// to 1. Januar 2000   00:00:00 UTC-0
#define SECONDS_FROM_1970_TO_2000 946684800

int daysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};

void setup() {
  timefromcompiler(__DATE__,__TIME__);
  // set the Time library to use Teensy 3.0's RTC to keep time
  setSyncProvider(Teensy3Clock.get);

  Serial.begin(115200);
  while (!Serial);  // Wait for Arduino Serial Monitor to open
  delay(100);
  if(timeStatus()!= timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");      
}

void loop() {
   digitalClockDisplay();  
   delay(1000);
}

void digitalClockDisplay() {
  // digital clock display of the time
  printDigits(hour());
  Serial.print(":");
  printDigits(minute());
  Serial.print(":");
  printDigits(second());
  Serial.print(" ");
  printDigits(day());
  Serial.print(".");
  printDigits(month());
  Serial.print(".");
  Serial.println(year());
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

int conv2d(char* p){
  int v = 0;
  if ('0' <= *p && *p <= '9')
  	v = *p - '0';
  return 10 * v + *++p - '0';
}

void timefromcompiler(char* date, char* time){
  int _days, _month, _year, _hour, _minute, _second;
  uint32_t _ticks;
  
  //Day
  _days = conv2d(date + 4);
	
  //Month
  switch (date[0]) {
    case 'J': _month = date[1] == 'a' ? 1 : _month = date[2] == 'n' ? 6 : 7; break;
    case 'F': _month = 2; break;
    case 'A': _month = date[2] == 'r' ? 4 : 8; break;
    case 'M': _month = date[2] == 'r' ? 3 : 5; break;
    case 'S': _month = 9; break;
    case 'O': _month = 10; break;
    case 'N': _month = 11; break;
    case 'D': _month = 12; break;
  }
  
  //Year
  _year = conv2d(date + 9);
  
  //Time
  _hour = conv2d(time);
  _minute = conv2d(time + 3);
  _second = conv2d(time + 6);
  
  //Date & Time to Unixtime
  for (int i = 1; i < _month; ++i)
    _days += daysInMonth[i - 1];
  if (_month > 2 && _year % 4 == 0)
    ++_days;
  _days += 365 * _year + (_year + 3) / 4 - 1;

  _ticks = ((_days * 24 + _hour) * 60 + _minute) * 60 + _second;
  _ticks += SECONDS_FROM_1970_TO_2000;
  
  Teensy3Clock.set(_ticks);
}

This Sketch convert the Compilertime to Unixtime (the format the Freescale Chip saved the time) and set it in the Teensy.
 

Attachments

  • TimeTeensyRTC_with_Compilertime.ino
    2.4 KB · Views: 339
The Time library was recently updated. Teensyduino 1.13 still has the old copy. The latest code is here:

http://www.pjrc.com/teensy/td_libs_Time.html

The 1.14 installer will have this new version. I highly recommend using this newer Time library. Many small bugs were fixed.


Teensyduino tries to automatically initialize the RTC, if it has a 32 kHz crystal connected but the time has never been set. This is the line in mk20ds128.c which sets the time:

Code:
        if (RTC_SR & RTC_SR_TIF) rtc_set(TIME_T);

If the RTC was previously set and it's been running since (either normal or battery power), then rtc_set() is not called.

TIME_T is passed from the Arduino IDE when the code is compiled. The idea is for the clock to automatically set the first time you program a board with a freshly installed crystal and battery. Of course, if you ever remove the battery, the time will default to when you compiled the program.

However, there's 2 bugs. I'm working on them. #1: the TIME_T is in UTC. I'm planning to change the number Arduino passes to the compiler to localtime. #2: mk20dx128.c isn't recompiled every time you use upload or verify, so the time defaults to the last time that particular file was compiled.

Of course, you can call rtc_set() or Teensy3Clock.set() to set the time correctly. Someday I'm going to fix those 2 bugs, so in the common case where you add the crystal and battery and just try the examples, the clock will automatically to your correct local time.
 
There's also a Teensy3Clock.compensate(num) function. It takes a signed integer, so you can slightly increase or decrease the RTC speed to compensate for inaccuracy in the crystal. The compensation is units of 0.1192 ppm. Using -100 slows the RTC by 11.92 ppm.
 
The Time library was recently updated. Teensyduino 1.13 still has the old copy. The latest code is here:

However, there's 2 bugs. I'm working on them. #1: the TIME_T is in UTC. I'm planning to change the number Arduino passes to the compiler to localtime. #2: mk20dx128.c isn't recompiled every time you use upload or verify, so the time defaults to the last time that particular file was compiled.

Of course, you can call rtc_set() or Teensy3Clock.set() to set the time correctly. Someday I'm going to fix those 2 bugs, so in the common case where you add the crystal and battery and just try the examples, the clock will automatically to your correct local time.

Paul,
I don't consider #1 a bug.
Time should always be kept and tracked in UTC.
Using anything else breaks time keeping particularly when using
the time or comparing the time to an external device or to a time in some other locality.
(Think alarms sync'd to google calendar, or events synchronized to a cell phone)
The unix guys figured this out 40+ years ago. Always track time in a common epoch, then convert
it to the users local time zone when necessary as the human wants to see it.
i.e. timezones are a human creation and are only for the convenience of the human viewer.

The CPM/DOS/Windows guys never understood this and only tracked a local date/time
in human readable form.
Tracking date/time as a broken down local time is a bad idea, not only because it makes tracking and comparing
times much more difficult but because it makes an assumption of locality. If you are not in
the assumed locality the time is wrong. Or if you are trying to compare times from two
different localities, things don't work. This does not happen when using a single epoch.

Using a epoch timer tick to track time, solves the complexity in tracking time
and comparing times, but once you start attempting to offset that epoch by some sort of local time offset,
all kinds of bad things will start to creep into the code and things become a mess.

The problem is if the epoch is shifted, then you have no idea what time it really is from looking at the epoch tick counter,
since the counter is no longer an epoch and there is nothing in the epoch counter value to indicate that it is offset
from the real epoch.

If you were going to do anything, then my preference would be keep the time tracking in UTC using
a single common epoch as it should be,
and then set the users timezone offset automatically for them.
That way you don't break the true timekeeping and all the existing time functions like:
mktime() localtime() asctime(), gmtime(), etc.. will still continue to work properly.

I've been through many date/time tracking issues in quite some detail, as I was involved
with some Scuba Diving s/w that logged dive information in a database.

Tracking the date/times of dives sounds so simple at first but
it can actually get quite messy because of the way different dive computers track time
and the way most people tend to think of "time".
Typically when diving, you are traveling to some other location which is a different timezone from you own.
Having to deal with epoch times vs local time tracking is a real mess for s/w trying to figure
when the dive was actually done.
Also, when storing the logging information in a data base you want it to be consistent no matter where
you are physically standing or where the dive was done, when you later review the log.

Then you have the issue of trying to figure out the amount of time between dives.
If all you have is a local time, you can't figure this out with 100% reliability because the local time
does not have any locality information to indicate the timezone offset and the two dives
might not have been done in the same timezone.

I know that Michaels Time library only used GMT and didn't deal with timezones.
But consider where he lives: :D
We had conversation about it one time, and joked and laughed about how timezone was not an issue that
he had to worry about.

In the end, the only thing that really works for all situations,
is using a single epoch and then converting to timezone offsets
as needed. The unix guys really did get it right way back then.

Maybe I can help you get the time stuff in Teensy working "properly"?


--- bill
 
Paul -- any ETA for this TIME_T ? it would be very convenient to keep track of things.
On my TO-DO list is a patch for Arduino to automatically define TIME_T to the time the program was compiled, and use that instead of a fixed date. The idea is the RTC would be automatically initialized to within a second or two of your computer's time, if the crystal is present and it's not previously been initialized. Of course, if you ever remove the Vbat power and reboot without reprogramming, the new default init time would be the moment when you compiled the program.... but at least it would give a nice "out of the box" initialization for working on projects.
 
I struggled to figure it out but I do the following which seems to work:


Code:
// This sets the system time (NOT the Teensy RTC Clock)
// set your seperated date/time variables out as normal and update system time FIRST
setTime(TimeHour,TMinute,TSecond,DateDay,DateMonth,DateYear);

// now we can use the system time to update the Teensy's RTC bits
// This sets the RTC Clock from system time - epoch stylee, just like it wants :)
Teensy3Clock.set(now());

I trust that helps someone out coz i've been looking all weekend trying to figure it out and only just sussed it ;)

Great little board, only had it a few days, totally luvin' it! :) (cheers Paul!)

Andy
 
Paul -- any ETA for this TIME_T ? it would be very convenient to keep track of things.

This was done quite some time ago. It's in Teensyduino 1.18. Near the end of mk20dx128.c is this code:

Code:
        if (RTC_SR & RTC_SR_TIF) rtc_set(TIME_T);

If you turn on verbose info from File > Preferences, you'll see the -DTIME_T=xxxx info is being given to the compiler.

There's a patch in Arduino so it always recompiles mk20dx128.c, even if the file hasn't changed, so that code always gets a fresh TIME_T.

If you have the crystal added to your board, try removing the battery. Upload a sketch, and then quickly power cycle the board right after the upload. When it powers up, the RTC will be in the uninitialized state (because you took off the battery) and it'll get configured automatically with the TIME_T from your recent compile.
 
Paul,
I just looked at the value of TIME_T and it is wrong.
The time_t value in a time library should be the epoch time as the number of seconds
since 00:00:00 Coordinated Universal Time
The value I see in the TIME_T is a value that represents the current time but is offset
by the current timezone including the current local DST condition.

If this value is used, then the actual time being set is wrong unless you happen to be
in the GMT timezone.

I know a while back that you said you wanted to change it from UTC to local time but that is wrong
and will break other libraries that know that unix time is an epoch that is based on UTC and
does not ever include any DST offsets.
It will also break compatibility with other external systems which also know how to track unix epoch time.

For users that want to abuse the time API and track time in localtime vs UTC,
then I think a better solution would be to create different defines and let the user pick
the one he wants vs forcing all the users to have their clocks set incorrectly to local time.
i.e. have the user call a function to set the clock, vs blindly just doing it and assuming
the user want to abuse the time API by using a time_t value that is offset by the localtime
and DST offset.

So for example, have users call a function and pass in the time_t value.
You could have two defines say
TIME_T and LOCALTIME_T
Or even better maybe the names:
UTC_TIME_T
LOCAL_TIME_T
So there is no confusion which you are getting and to avoid any confusion
over any association with the time_t typedef.

Then the user could pass in whichever he wanted.
For those what want to use the API properly, they would use TIME_T or UTC_TIME_T
for those that want to abuse the API, they would use LOCALTIME_T or LOCAL_TIME_T


That way nobody is forced into having their clock set in a way
that won't work for them.



--- bill
 
Let's talk of time zone stuff in a month, after Maker Faire, when I'm working on Teensyduino 1.20 (version 1.19 will likely be a maintenance release with only small fixes).

Until 1.20, this won't (nor will anything else) be changing.
 
I saw that there and it's defined on the command line when mk20dx128.c gets compiled so the current time gets defined, but was hoping to (ab)use it as a simple version indicator -- i.e. Serial.println(TIME_T);
but I get:
error: 'TIME_T' was not declared in this scope

I'm not using a crystal or the RTC on this Teensy.

Could you also define it for the Arduino sketch ?
 
Status
Not open for further replies.
Back
Top