How to deal with millis() drift - millisecond timekeeping

I'm working on a project which involves multiple arduinos that need to be time synced at a distance. I've built a very successful syncing routine which runs over a ZigBee network, and results in syncing to within 1ms.

Now I've run into the limitations with the timekeeping of the Arduino. I've done some reading and understand that this ultimately results from the ceramic oscillator. So I'm seeing a drift between my synced Arduinos, and it's too large for this project (about 27ms per minute between the two in my test rig). Anyway, my requirements are basically that I can keep the clocks running at the same rate, to keep them in sync for at least several hours (between syncing operations).

I'm happy to use an RTC chip, but while this will give me good timekeeping, it will only return seconds, but I need millisecond resolution. So, I have millis() giving me high-resolution timekeeping, but it drifts, and can have an RTC for low-drift, but low resolution time-keeping...

One thought is using an Arduino with a crystal oscillator - I believe some models do have them, but which models?

Any suggestions are welcome - I'm open to strange and wonderful ideas.

Crystals are generally more accurate than ceramic resonators, (the more accurate the crystal, the more you pay for it), but all clock sources are temperature sensitive and the frequency will drift.

RTCs are just crystal controlled clocks and also drift. The more expensive ones, like the DS3231, are temperature compensated.

For concrete suggestions, you need to define the accuracy required of the time sync operation.

Thanks for the reply - and apologies for not making it clear enough.

Really my outside tolerance is for the system to be within 10ms for an hour, which isn't asking much. Optimally I'd like to be within 5ms for 24 hours.

I'm aware that all crystals etc (and therefore RTCs etc) will have drift, but the drift I'm seeing between these Unos (which have ceramic oscillators) is high. I was actually quite surprised how high. Between the two Unos the drift was 450ppm.

My easiest solution would be to use Arduinos that have a crystal rather than a ceramic - but I can't seem to find out which ones do.

My easiest solution would be to use Arduinos that have a crystal rather than a ceramic - but I can't seem to find out which ones do.

I'm not aware of any that do but it can't be hard to replace the ceramic with quality crystal, the pin spacing is probably the same.

You can also home-brew your own Arduino, using a quality crystal.

Since you have already sorted the synchronisation, I guess you only need to do this once.

You can add a crystal to your Arduino but it will still drift if the temperature isn't well controlled.

RTCs can be programmed to output a 1Hz pulse. A good RTC with temperature compensation (like the DS3231) will provide an accuracy of 10ms per hour (2-3ppm).

But 5ms per 24 hours would be 58 parts per billion. You're not going to get that out of an RTC chip. For that you're best bet would be to use a GPS, provided you can obtain satellite fix at the various locations. A GPS will output a once per second pulse that is very accurate and won't drift. But they do need to be able to see the sky reliably.

Thanks for the info. So here's what I'm thinking:

I can either replace the crystal on the uno, or build a board from scratch with an ATMega, and use one of these:

That should give me 2.5ppm with temperature compensation. Then, if I increase my syncing frequency to once every hour, it should be okay.

Older Duemilanove's have crystals.
You can still get them

I can either replace the crystal on the uno, or build a board from scratch with an ATMega, and use one of these:

Good idea.

But isn't that part designed for 3.3V operation whereas your Uno runs at 5V?

5V oscillators are available also.

darm forum & IE11 - keeps sticking extra %22http// into the links. You may need to edit the start of the link.

This link works:

Yes, you're right it was a 3.3 V unit, I had a few tabs open and grabbed the wrong link, just lucky I didn't order the wrong parts!

Thanks for all your help!

Why can't you synchronize the clocks ever 5 minutes?

He said his upper limit is a drift of 10ms in an hour. He tested two units and they drifted apart 27ms in one minute. So five minutes is too long.

And the resonator in an Uno can be a lot worse than that. The datasheet only promises ±0.5%.

The reason I can't sync more often is because when the time sync is running I can't record sensor data, so to run the sync I have to tolerate some sensor downtime. Because I'm syncing over a wireless mesh network with varying latency, the sync becomes relatively involved and takes several seconds.

Actually, while I can find many 5v crystals, I can't find any 5v TCXOs (the sensor units will be exposed to ranging temperatures, which is why TC seems like a good idea). Can I clock an atmega328p from a 3.3v TCXO (so long as I'm providing 3.3v Vcc for the TCXO of course)?

Can I clock an atmega328p from a 3.3v TCXO (so long as I’m providing 3.3v Vcc for the TCXO of course)?

According to the 328p datasheet the minimum input logic high level for the XTAL1 pin is VIH1 = 0.7*VCC, when VCC is 2.4-5.5V. For VCC=5.0V that works out to VIH1 = 3.5V. So I think the answer is no.

If you give us the details of the system, we can stop asking dumb questions.
like, how many units do you expect to have in this network? What is the longest hop from master to remote unit?

But, yes, your first instinct to use crystals rather than resonators would help.

I would still lean toward syncing more often. I think you can sync without it taking “several seconds”. Can you think of a way to speed that up?

Interesting problem. It might be possible to use phase locked loop techniques to phase lock the arduinos. I have designed PLLs where the oscillator frequency was digitally regulated by changing the capacitance of an LC oscillator depending on the phase error. I have not looked at the arduino oscillator but I am guessing that the frequency depends on some capacitance. Suppose you attach an NFET gate to one side of the capacitor. You can then connect the source and drain of the NFET to an arduino digital output. Depending on the state of the arduino output the gate to source/drain capacitance will change. When the digital output is low, the NFET channel will invert and the capacitance will increase. When the output is high the channel will not invert and the capacitance will decrease. In this way you can incrementally bump the frequency up and down and keep the arduinos in sync.

@charlie, That system does or does not compensate for temperature variations that affect the frequency ?

I have worked with equipment that had a crystal in a temp. oven, and tried to keep the crystal at an almost constant temp. (but I think that is overkill for this project).