Yours is a classical problem of clock syncrhonization. You have a software clock (your program's idea of the current time) which you want to keep in sync with a reference hardware clock (the RTC). This is typically achieved by using a phase-locked loop, or PLL. It works as follows:
- you measure the difference between your software clock's time and the reference time
- you adjust your software clock based on this measurement.
This is essentially what you are already doing, except that you are fixing your clock by stepping it abruptly, whereas a PLL would usually slew the clock to get it in sync progressively.
Stepping the clock has some undesirable effects: it makes the time discontinuous and, more annoyingly, it can make it non-monotonous. I would thus recommend you try to slew your clock instead.
Here is the approach I would try if I were in your shoes. I am assuming you are using an Arduino Uno, or a similar AVR-based board with a 16-bit Timer 1:
- configure Timer 1 in mode 4: CTC mode with TOP = OCR1A
- set the prescaler to 64 and OCR1A = 12499 in order to get a period of 50 ms; TIMER1_COMPA_vect will be your data gathering interrupt
- configure your RTC to generate a 1 Hz output, and route this signal to the input capture pin ICP1 (pin 8 on the Uno)
- run the PLL logic inside TIMER1_CAPT_vect.
Since the RTC's 1 Hz period is a multiple of the timer period, you would expect the timer's input capture unit to always capture the same value. The difference between two consecutive captured values is thus a direct measure of your clock's drift in units of 4 ppm (4 μs/s). The ISR would be basically along these lines:
ISR(TIMER1_CAPT_vect)
{
static uint16_t last_capture;
uint16_t this_capture = ICR1;
int16_t drift = this_capture - last_capture;
last_capture = this_capture;
// Reduce the drift modulo 12500 into [-6250, +6250).
if (drift >= 6250) drift -= 12500;
if (dirft < -6250) drift += 12500;
tune_clock(drift);
}
where tune_clock()
is your PLL algorithm responsible for slewing the
software clock.
Pay attention to the signedness of the variables. The subtraction of the captured values should be done with unsigned numbers, then the result should be made signed.
- 45.1k
- 4
- 42
- 81