I'm wondering did anybody test Arduino quartz crystals for accuracy. I cannot find anything there. Except for suggestions to use RTC, but see bellow.
What I can find is that 16Mhz quartz is usually 50ppm, can be better, can be worse. But that seems to be over whole 0-100C temp range, which would be actually better than typical 10ppm 32khz watch crystal.
I can't find any temp dependency curves for 16mhz crystal unfortunately. I guess I will have to try.
Has anybody done any tests?
Now for all crying use RTC, please don't . yes I know I can do that. But I fail to see your point. I want to test using Arduino crystal. Besides if you cry use RTC, you make all this forum redundant, because 99.999% stuff discussed here can be done way better by buying off the shelf stuff. Arduino is not supposed to be about that.
It is possible to replace the crystal with a more accurate one.
Another approach is to measure the actual clock frequency in Hz of the Arduino using the 1PPS output of a GPS unit. Even as a function of temperature, if you like.
This excellent tutorial, specifically the section on how to use the input capture unit of Timer1 on the Arduino Uno R3 (or Pro Mini, Classic Nano, etc.) gives the basic idea.
This code actually measures the crystal clock frequency in Hz, after connecting the ICP input D8 to the 1PPS output of a handy GPS module, that has a satellite fix.
// Frequency timer using input capture unit
// Author: Nick Gammon
// Date: 31 August 2013
// added averaging JR 2015
// Input: GPS 1PPS capture signal on Pin D8
volatile boolean first;
volatile boolean triggered;
volatile unsigned int overflowCount;
volatile unsigned long startTime;
volatile unsigned long finishTime;
// timer overflows (every 65536 counts)
ISR (TIMER1_OVF_vect)
{
overflowCount++;
} // end of TIMER1_OVF_vect
ISR (TIMER1_CAPT_vect)
{
// grab counter value before it changes any more
unsigned int timer1CounterValue;
timer1CounterValue = ICR1; // see datasheet, page 117 (accessing 16-bit registers)
unsigned long overflowCopy = overflowCount;
// if just missed an overflow
if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF)
overflowCopy++;
// wait until we noticed last one
if (triggered)
return;
if (first)
{
startTime = (overflowCopy << 16) + timer1CounterValue;
first = false;
return;
}
finishTime = (overflowCopy << 16) + timer1CounterValue;
triggered = true;
TIMSK1 = 0; // no more interrupts for now
} // end of TIMER1_CAPT_vect
void prepareForInterrupts ()
{
noInterrupts (); // protected code
first = true;
triggered = false; // re-arm for next time
// reset Timer 1
TCCR1A = 0;
TCCR1B = 0;
TIFR1 = bit (ICF1) | bit (TOV1); // clear flags so we don't get a bogus interrupt
TCNT1 = 0; // Counter to zero
overflowCount = 0; // Therefore no overflows yet
// Timer 1 - counts clock pulses
TIMSK1 = bit (TOIE1) | bit (ICIE1); // interrupt on Timer 1 overflow and input capture
// start Timer 1, no prescaler
TCCR1B = bit (CS10) | bit (ICES1); // plus Input Capture Edge Select (rising on D8)
interrupts ();
} // end of prepareForInterrupts
void setup ()
{
Serial.begin(115200);
Serial.println("Frequency Counter");
pinMode(8, INPUT_PULLUP);
pinMode(7, OUTPUT);
digitalWrite(7, LOW);
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
// set up for interrupts
prepareForInterrupts ();
} // end of setup
void loop ()
{
static unsigned long average = 0;
static int n = 0;
// wait till we have a reading
if (!triggered)
return;
PINB |= (1 << 5); //blink LED
// period is clock cycles in one second
unsigned long elapsedTime = finishTime - startTime;
Serial.println (elapsedTime);
average += elapsedTime;
n++;
if (n == 10) {
Serial.print("System clock count, average of ten: ");
Serial.println(average / 10);
n = 0;
average = 0;
}
// so we can read it
delay (500);
prepareForInterrupts ();
} // end of loop
Yet another option: buy an Arduino Uno clone with a more accurate crystal. Many of the $4 Pro Mini clones on eBay have a 16 MHz crystal, not a resonator.
Yes, sorry, I forgot to mention, I will use some Chinese pro mini thing. It already has quartz crystal of unknown quality.
I think you can measure the frequency by just making a clock by using regular millis function and then checking the drift after 24 hours.
Then I could software calibrate it. This should make quite accurate clock subject to temperature coefficient of the quartz (can't find any data on this).
Yes, I need to care for overflow and not use timer0. Ut it's easy to do. For example like this
int timeMillis =0;
int timeSeconds=0;
int timeMinutes=0;
int timeHours =0;
while (true){
currentTime =millis();
timediff = currentTime - previousTime;
previousTime = currentTime;
timeMillis+= timediff;
if (timeMillis >=1000){
timeSeconds += timeMillis/1000;
timeMillis %= 1000;
}
/// Same for minutes and so on...
}
All the data sheets for 16Mhz crystals I can find has only initial tolerance and frequency stability as ppm over all temperature range. Fancy ones even has one number at all like here https://ecsxtal.com/store/pdf/ecs-2325-2333.pdf
I can't find any temperature graphs similar to those for 32Khz crystals
Cause 32768 happens to be a power of 2. So with a series of counters you can derive a 1 sec pulse...
Very handy for watches...
So these crystals need to be very accurate and reasonably cheap as they are mass produced.
There are almost 100000 seconds in a day, so even with an accuracy of 0.001% you are still off by a second per day... after 2 months it will be a full minute... after a year 12 minutes...
Timer2 is designed to be able to have a 32 kHz watch crystal hoked up to it. The ATmega328P even has a special low power mode (I think it's called Power Save) that turns off the main oscillator but leaves Timer2 running. If you need RTC accuracy you can use that in place of a full RTC module.
They are 32khz for easy division. But also because less frequency means less power.
Accuracy is probably better on higher frequencies, that's why I think bulova made watch with 216khz crystal.
Ant tempco is bad see for example this datasheet https://www.mouser.com/datasheet/2/137/FC3215AN_en-2952664.pdf
It's more than 100ppm over 0-75C which is worse than typical 16Mhz crystal
Did you read my first post?. You show the datasheet with 50ppm tempco over temperature, which I wrote I can find. And I do not see any temperature graphs as for example for this 32khz crystal. https://www.mouser.com/datasheet/2/137/FC3215AN_en-2952664.pdf