The DS3234 is an "Extremely Accurate SPI Bus RTC with Integrated Crystal and SRAM". There are several programming notes on the forum; search using key "DS3234".
The data sheet specifies Accuracy +- 2ppm from 0 degrees C to 40 degrees C. That works out to just about one minute per year. One can improve on this by using the Aging Offset Register.
From the data sheet: "The aging offset register takes a user-provided value to add to or subtract from the oscillator capacitor array". That allows you to "pull" the oscillator frequency one way or the other.
I programmed the DS3234 for a 1 Hz output on SQW; file full-scale.pdf shows the measured output as a function of aging offset. A value of zero yields just about 1 ppm slow. With this particular device, I was able to pull the output from about 7 ppm slow to about 6 ppm fast. Pull down on the scroll bar to see a graph. Note this is a sample of one
DS3234. I would expect the sign of the slope to be the same for any 3234, but the zero crossing will depend on the crystal. The data sheet says at 25 degrees C, one LSB typically provides about 0.1 ppm. I measured about 0.05 ppm at about 22 degrees.
Now look at file zoom.pdf. I have begun adjusting the aging value in steps of 1 in an attempt to get the 1 Hz output to exactly 1 Hz. Since my frequency country is known to count 0.1 ppm fast, I aimed for an indicated output of 1.0000001 Hz. Two values produced the ideal number, -20 and -21. I think it reasonable to suppose that one is too fast and the other too slow. But not much, and as nearly dead on as possible.
Here is a code fragment (BS-2) that I used to program the aging register. Read34 and Write34 read or write a single 8-bit register from or to the DS3234. So I read and display the current aging value. Then I request a new value, display it in binary because I am superstitious, and write it to the aging register. Then I force a temperature conversion to allow the new value to take effect and wait for conversion complete.
RegAd = Age34 'read current ageing value
AgeingLo = RegData
AgeingHi = 0 'set up to extend sign
IF AgeingLo.BIT7 = 1 THEN AgeingHi = $FF 'extend sign if needful
DEBUG CR, "current Ageing Value: ", SDEC Ageing, " Input New Value "
DEBUGIN SDEC Ageing 'read new value
DEBUG " ", BIN8 AgeingLo 'just to be certain
RegAd = Age34 'set new value
RegData = AgeingLo
RegAd = Con34 'make new value take effect
RegData = %00100000
GOSUB Write34 'convert temperature
DO UNTIL RegData.BIT5 = 0 'wait for conversion complete
RegAd = Con34
If you don't have a frequency counter, how do you decide what aging value to choose? Cut and try. Set the clock as closely as you can and observe how much time it gains or loses over, say, a week. Now there are about 600,000 seconds per week; 1 ppm will yield an error of about 0.6 seconds per week. Suppose you are off 2 seconds after a week; that is about 3 ppm, or an offset of 30 at 1 ppm per LSB. Small changes are good; perhaps 10 or 15 in this case. Changes to values that are more negative will speed up the clock; changes to values that are more positive will slow down the clock.
Re-inventing the wheel is not a waste of time if, when you are done, you understand why it is round.