Pages: [1] 2 3   Go Down
Author Topic: millis (crystal) accuracy & thoughts  (Read 3607 times)
0 Members and 1 Guest are viewing this topic.
USA
Offline Offline
Jr. Member
**
Karma: 4
Posts: 89
If you can't fix it with a hammer, it must be an electrical problem.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm trying to make a sports timer with an Arduino and I'm finding the crystals appear to be wildly inaccurate. Comparing photos of the (3 different) Arduino vs. (several) handheld stopwatches, I get results like this over a period of 10 minutes:

Code:
Delta-s      delta-ms
-1.11       -1110
-1.22       -1220
-1.36       -1360
-1.21       -1210
-1.03       -1030
-0.48       -480
-0.31       -310
-0.72       -720
-0.06       -60
0.09        90
0.27        270


The timer code on the Arduino is simply reading millis() and displaying via SPI interface to a Sparkfun 4-digit 7-segment display. Relevant code below:

Code:
//declare globals
volatile unsigned long current_time, *display_time;

void SpiTransfer(volatile char data) {
  SPDR = data;                    // start the transmission
  while (!(SPSR & (1<<SPIF)));    // wait for the end
}

void DisplayTime(void) {
  PORTB &= ~(1<<PORTB2);                   //set SPI_SS low
  SpiTransfer( (*display_time/600)%10 );   // thousands digit
  SpiTransfer( (*display_time/100)%6 );    // hundreds digit
  SpiTransfer( (*display_time/10)%10 );    // tens digit
  SpiTransfer( *display_time%10 );         // ones digit
  PORTB |= (1<<PORTB2);                    //set SPI_SS high
}

void setup(void) {
  uint8_t junk;

  //setup spi in order to talk to 4-digit 7-segment display_time
  pinMode(SPI_MISO, INPUT);
  pinMode(SPI_MOSI, OUTPUT);
  pinMode(SPI_CLOCK, OUTPUT);
  pinMode(SPI_SS, OUTPUT);
  digitalWrite(SPI_SS, HIGH);
  //spi enabled, msb 1st, master, clk low when idle,
  //sample on leading edge of clk, system clock/64
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1);
  junk = SPSR;
  junk = SPDR;

  //display ticking timer.
  display_time = &current_time;
  current_time = 0;

  //offset between now and system time
  millis_offset = millis();
}

void loop(void) {
  //main loop
  while(1) {
    //update display
    current_time = (millis() - millis_offset)/100;
    DisplayTime();
}

I've tried using nonblocking delays to slow the calls to millis(), thinking that was the culprit, but I get similar results. Does the SPI call block the millis() timer interrupt?

I'm thinking of using a DS3231 (like a chronodot) to create an accurate 1Hz interrupt on the Arduino. Any thoughts? I'm open to ideas.

thx.
« Last Edit: December 27, 2009, 04:36:51 pm by JimEli » Logged


Lancashire, UK
Offline Offline
Edison Member
*
Karma: 9
Posts: 1991
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have found the Arduino timekeeping to be within a couple of seconds a day.  This is just getting the millis() output out to a seperate NTP controlled computer, once a minute, logging it over several months and doing the maths by hand.
Present results show the Arduino has made out the last 4days to be 345,593.346 seconds long (it should be 345,600 seconds)(it was restarted after a software change just over 4 days back) this is fairly typical for my 3 Arduinos.    
Logged


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

I am, seeing very similar drift. ~5 seconds at 20 min, when compared to a stop watch for start stop events. I am timing a motor powering on and off and need to be accurate to a tenth of a second.  Has anyone found a fix for this?
« Last Edit: March 08, 2010, 04:27:39 pm by rhythmtech » Logged

Norway
Offline Offline
Sr. Member
****
Karma: 0
Posts: 344
Just dip it in mercury and power it up
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It is hard to manufacture crystals with a beat that is 16.0000000 Mhz and usually the crystals used in the arduino have +- rating of 50 ppm.
So if you need more accurate timing, you need to software adjust the millis() with your drift. Heat can throw the beat off, so temperature swing will affect the mhz rate. Crystals change the frequency due to aging also.

A voltage-controlled crystal oscillator (VCXO) is used when the frequency of operation needs to be adjusted only finely. The frequency of a voltage-controlled crystal oscillator can be varied only by typically a few tens of parts per million (ppm), because the high Q factor of the crystals allows "pulling" over only a small range of frequencies.

To the more intressed read wikipedia
http://en.wikipedia.org/wiki/Crystal_oscillator

David
Logged

Rural Arizona
Offline Offline
Edison Member
*
Karma: 7
Posts: 1711
Incorrigible tinkerer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Are those Arduinos using actual crystals?  Or are any of them controlled with the 3-terminal ceramic resonators?  Resonators have a much larger frequency tolerance than crystals.
Logged

MD, USA
Offline Offline
God Member
*****
Karma: 2
Posts: 663
A jack of all trades and a master of none!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I am timing a motor powering on and off and need to be accurate to a tenth of a second.  Has anyone found a fix for this?

You may want to use a Digital timer rather then trying to get the arduino to handle it. You should be able to integrate a digital timer with the arduino if you need to keep a log of the times.
http://www.automationdirect.com/adc/Overview/Catalog/Relays_-z-_Timers
« Last Edit: March 08, 2010, 05:42:39 pm by digimike » Logged

Norway
Offline Offline
Sr. Member
****
Karma: 0
Posts: 344
Just dip it in mercury and power it up
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Duemillenova and Mega have crystals at least (I have a mega, there is spk16.000y crystall there)

those small arduinos, and some copies have resonators

David
Logged

Norway
Offline Offline
Sr. Member
****
Karma: 0
Posts: 344
Just dip it in mercury and power it up
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

assuming that the temperature is constant!
find out the drift of your crystal by running a timer loop against some accurate timing device (preferably one that you can start and stop with the arduino) and let it run for a few hours or days.
when you have that data (the drift is a constant value) you make a formula that states how many millisec it drifts pr. millisec
you add or deduct that value from every millisec counted

Voila! you have an accurate counter!

David
Logged

Norway
Offline Offline
Sr. Member
****
Karma: 0
Posts: 344
Just dip it in mercury and power it up
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

And try to use hand stopwatches over a few seconds is just crazy

1. human reaction time on stopwatch (try starting and stopping two stop clocks at the same time in each hand)
2. delay from pressing stop on arduino till it writes it to serial to display
3. same for pressing start (the arduino must process some code)
Logged

USA
Offline Offline
Jr. Member
**
Karma: 4
Posts: 89
If you can't fix it with a hammer, it must be an electrical problem.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
And try to use hand stopwatches over a few seconds is just crazy

1. human reaction time on stopwatch (try starting and stopping two stop clocks at the same time in each hand)
2. delay from pressing stop on arduino till it writes it to serial to display
3. same for pressing start (the arduino must process some code)

The above timer comparison was accomplished with no human input. I simply started both an arduino (with code posted above) and a stopwatch, placed them side-by-side, and took photos of them at approximately 1-minute intervals over a period of 10-minutes. I repeated this with several different types/models of stopwatches, all with similar results.

The results posted above are the differential between both timers.

Wildly inaccurate.

No pressing of buttons.
« Last Edit: December 19, 2010, 12:34:34 pm by JimEli » Logged


Seattle WA
Offline Offline
Full Member
***
Karma: 1
Posts: 208
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think the problem is your code -- you should try using a timer interrupt rather than millis() if you care about the accuracy of your timing. That will give you a timing accuracy about on par with the crystal itself, which on the order of 100 ppm. You can get a 10 ppm crystal for a couple of bucks and swap it out if that's not good enough.

If you want better then that, be prepared to spend some coin.
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6252
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think the problem is more likely to be latency on the SPI display rather than inaccuracy in the crystal or millis routine.

Try the test with an LCD with parallel connection using the LiquidCrystal library.

or for a simple test, write a sketch that blinks an LED every ten minutes (longer would be better) and compare the blink intervalto the time on your stopwatch.
« Last Edit: December 19, 2010, 02:05:11 pm by mem » Logged

USA
Offline Offline
Jr. Member
**
Karma: 4
Posts: 89
If you can't fix it with a hammer, it must be an electrical problem.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Lets be realistic here.
As has already been observed, if we are talking about an application like casual timing for track and field (i.e. not official competition like Olympics, etc.) the crystal in your typical microcontroller (like Arduino) is probably sufficient. Your human error in hitting start/stop is greater than the error from a typical microprocessor crystal over 10 minutes.

I think you ignored looking at my data, because I'm seeing unacceptable timing errors for anything more accurate than an egg timer.  smiley-wink

Thanks for the RTC recommendations.

I'll try hooking up an lcd via parallel.
Logged


USA
Offline Offline
Jr. Member
**
Karma: 4
Posts: 89
If you can't fix it with a hammer, it must be an electrical problem.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

see reply #9.
Logged


USA
Offline Offline
Jr. Member
**
Karma: 4
Posts: 89
If you can't fix it with a hammer, it must be an electrical problem.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Being from the future, I assumed you wouldn't need me to explain all this.  smiley-wink

A photo was taken of the arduino & stopwatch at approximately 1-minute intervals for 10 minutes. The columns represent the time difference between the 2 clocks. The difference between the clocks at the start had the arduino 1.11 seconds behind the stopwatch.  After approx. 10-minutes, the arduino was 0.27 seconds ahead. I hope that explains the data.

I repeated the experiment using 3 different arduinos and several stopwatches with similar results.

It doesn't seem to make any sence to me either.
Logged


Pages: [1] 2 3   Go Up
Jump to: