Go Down

Topic: millis (crystal) accuracy & thoughts (Read 4315 times) previous topic - next topic

JimEli

Dec 27, 2009, 10:08 pm Last Edit: Dec 27, 2009, 10:36 pm by JimEli Reason: 1
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: [Select]
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: [Select]
//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.

pluggy

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.    
http://pluggy.is-a-geek.com/index.html

rhythmtech

#2
Mar 08, 2010, 10:24 pm Last Edit: Mar 08, 2010, 10:27 pm by rhythmtech Reason: 1
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?

ArduinoM

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

Ran Talbott

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.

digimike

#5
Mar 08, 2010, 11:42 pm Last Edit: Mar 08, 2010, 11:42 pm by digimike Reason: 1
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

ArduinoM

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

ArduinoM

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

ArduinoM

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)

JimEli

#9
Dec 19, 2010, 06:33 pm Last Edit: Dec 19, 2010, 06:34 pm by JimEli Reason: 1
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.

rocketgeek

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.

mem

#11
Dec 19, 2010, 08:04 pm Last Edit: Dec 19, 2010, 08:05 pm by mem Reason: 1
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.

JimEli

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.  ;)

Thanks for the RTC recommendations.

I'll try hooking up an lcd via parallel.

JimEli


JimEli

Being from the future, I assumed you wouldn't need me to explain all this.  ;)

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.

Go Up