Pages: [1]   Go Down
Author Topic: Experimenting with better time keeping (non-RTC)  (Read 2273 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 1
Posts: 29
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello all, this is not really a problem, but a true experiment with the Arduino time keeping.

It is pretty well known that the Arduino time keeping code, related to the millis() function, does not align exactly with the 16Mhz clock.  millis() uses the 8bit Timer0, and 16,000,000 is not perfectly divisible by 256.

I decided to run a test against the millis() timekeeping vs using a timekeeping method that perfectly aligns with the 16Mhz clock using Timer1.

I am testing with an Arduino Micro clone (ATMega32u4) with 16Mhz crystal oscillator.

My results were very surprising.  After running for 3 days, the times remained almost perfectly aligned.  Never deviating more than 1ms.  Perhaps my test code is wrong or I am not accounting for something.

Code:
volatile uint32_t timer1_millis;
uint32_t millis_tmp;
uint32_t timer1_millis_tmp;
uint32_t next_millis_update;


void setup(void) {
  TCCR1A = 0;
  TCCR1B = _BV(WGM12) | _BV(CS11) | _BV(CS10); // /64 prescale
  TIMSK1 = _BV(OCIE1A); //Overflow counter interupt enable
  OCR1A = 249; // 1ms with /64 prescale @ 16Mhz
 
  Serial.begin(115200);
 
  // synchronize times
  timer1_millis = millis();
 
  // report every 10 seconds
  next_millis_update = timer1_millis + 10000;
}

void loop(void) {
  if(millis() >= next_millis_update) {
   
    // set snapshot values for calculation
    millis_tmp = millis();
    timer1_millis_tmp = timer1_millis;
   
    Serial.print("Timer1: ");
    Serial.println(timer1_millis_tmp,DEC);
   
    Serial.print("Millis: ");
    Serial.println(millis_tmp,DEC);
   
    Serial.print("Diff:   ");
    Serial.println((timer1_millis_tmp - millis_tmp),DEC);
   
    next_millis_update += 10000;
  }
}

ISR(TIMER1_COMPA_vect) {
    timer1_millis++;
}
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 207
Posts: 12924
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
It is pretty well known that the Arduino time keeping code, related to the millis() function, does not align exactly with the 16Mhz clock.

It is even better known that millis tracks the 16 MHz processor clock perfectly.

Quote
millis() uses the 8bit Timer0, and 16,000,000 is not perfectly divisible by 256.

Correct.  But the millis code accounts for that fact.
Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2073
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
It is even better known that millis tracks the 16 MHz processor clock perfectly.
Even in subsecond ranges??
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 207
Posts: 12924
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Even in subsecond ranges??

I don't understand the question.  Are you asking if millis accurately tracks a wall clock?
Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 29
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I finally took a second (okay, 100th) look at the Arduino code.  millis() does lose time like I was expecting, but keeps track of the missing "fractional" time and then adds it to millis() once the fractional time adds up to a whole millisecond.

This does explain the behavior I was seeing with my sketch.  millis() and my timer would be synchronized, and after a few seconds millis() would lose a millisecond, but would eventually gain the lost millisecond back.  Wash, rinse, repeat ad infinitum.

So, millis() does lose time in the short term, but is ultimately "correct" over the long term.

In reality, millis() is never completely correct.... it is always off by less than 1000 nanoseconds [edit] microseconds... but that does not really matter in terms of time keeping.
« Last Edit: September 29, 2013, 01:19:01 pm by decep » Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 538
Posts: 27099
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I use micros() for time tracking, seems to be very accurate with crystal driven processors.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

0
Offline Offline
Newbie
*
Karma: 1
Posts: 29
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Please do not think that I am saying that there is something wrong with the Arduino code.  This is purely an academic experiment.

millis() and micros() is more than adequate for timing purposes, but it can never align perfectly with the 16MHz clock source using an 8bit timer in [Fast-]PWM mode.

I knew millis() could not align perfectly and I wanted to see how quickly it would drift, but I did not expect millis() to keep up over the long term.
Logged

Pages: [1]   Go Up
Jump to: