millis() and Timer0 interrupt
Arduino uses Timer0 to generate an interrupt every 16384 cpu clock cycles. During this interrupt,
timer0_fract are incremented by amounts derived from F_CPU,
corresponding to the time elapsed between interrupts.
In the normal Arduino build,
timer0_millis is 32 bits. We extend it to 64 bits wide,
so that it will not quickly overflow, and define the
time() function to merely return
timer0_millis / 1000. Likewise, the
set_system_time() function just
multiplies the argument by 1000, and writes that to
To provide clock discipline,
discipline_clock() transforms its argument into an approximate
parts-per-million value suitable for the cpu frequency, F_CPU. Every 1024 Timer0 interrupts, this ppm value
is added to (or subtracted from) the microsecond counter
timer0_fract ... about once per second on a 16 Mhz board.
The original Arduino code defines
timer0_fract as an unsigned char, and scales it by a factor of 8,
losing the 3 lowest bits. For our discipline to work at all,
timer0_fract must be able to go
negative. And the loss of those bits means a loss precision of about 8 PPM. So we change
to be a signed 16 bit int, and do away with the scaling.
This scheme imposes minimal extra load on the millis() ISR, while providing for a fairly accurate
time-keeping system, even on boards which use a ceramic resonator instead of a crystal.
At the same time, it does not affect the
which continue to return the same results as before.