DS3231 Drift Results (5 months)

It’s been just under 5 months since I simultaneously synchronized ten DS3231/DS3231M RTCs as part of a long-term experiment to measure their drift. Of the ten, seven are crystal-based DS3231 chips, while three are DS3231M chips. Since they’re all on the same breadboard connected to the same power supply, all of them have been subject to the same physical conditions of temperature, movement, voltage, etc. insofar as I can control for them in my apartment.

In the table below “Number” is the identifying number of each chip I arbitrarially asigned to uniquely identify each one, “Type” refers to its type (all the DS3231 modules are marked as the wide-temperature-range SN type, while the DS3231Ms are listed as M. The official DS3231M chip (#2) I received directly from Maxim is marked with an asterix.), “Offset” is the aging offset in register 0x10 expressed in decimal form, “PPM” is the stability in parts per million, and “Drift” is the number of seconds the clock has drifted since the start. For both the PPM and Drift columns, a positive value indicates that the RTC has run faster than the NTP-synchronized system clock while a negative value indicates the RTC has run slower than the system clock.

All results were collected over a 26 minute period starting 12904549 seconds after the clocks were first synchronized. Each clock was measured three times and the resulting values averaged and rounded to two decimal places. Keep in mind that this dataset consists of just two data points (zero drift at the start, and the measured drift now) for each clock: unlike Dan, who continuously collected data and made many nice graphs, I set the clocks and essentially ignored them for five months.

Anyway, I digress. Here’s the results:

Number	Type	Offset	PPM	Drift
0	SN	-6	0.19	2.46
1	SN	0	-0.69	-8.96
2	M*	0	-1.62	-20.85
3	M	0	-3.06	-39.54
4	M	0	-2.76	-35.65
5	SN	0	0.16	2.07
6	SN	0	0.01	0.10
7	SN	-15	0.33	4.32
8	SN	0	0.08	0.98
9	SN	0	-0.05	-0.60

Some commentary, bullet-pointed for your reading pleasure:

  • All clocks are within their advertised tolerances (2 ppm for the crystal-based clocks and 5 ppm for the MEMS-based clocks).
  • Five of the seven crystal-based DS3231 chips run fast, while two run slow. All three of the MEMS-based DS3231M chips run slow.
  • Clock #6 has essentially no drift whatsoever. There’s nothing particularly noteworthy about it: just luck of the draw.
  • The Raspberry Pi used to set the clocks in September was also used to measure the offset today. It has run continuously since the clocks were set, and has been synchronized continuously to another Raspberry Pi (+/- 0.1 ms), which was in turn synchronized to GPS using a Motorola Oncore UT+ receiver (+/- 150 ns). Time errors on the Pis are negligible.
  • I have two PCA9548A I2C switches that allow me to wire up all the clock chips and switch between them using software commands rather than needing to physically move wires around. This makes life easy.
  • At the start of the measurement, I had observed each of the clocks’ outputs using my oscilloscope and compared them to a GPS-synchronized PPS signal. Clocks #0 and #7 drifted faster than the others but were still within the advertised specs (unfortunately I didn’t write down how fast they were drifting and have since forgotten). I adjusted the aging register until the short-term drift was minimal; the results are acceptable, though I note they drifted the most of any of the crystal-based clocks.
  • All ten clocks are part of a cheap module available on eBay from various Chinese sellers. The module comes with either a DS3231 or DS3231M chip (the sellers don’t sort them so you can get either type at random) of various vintages. The oldest I’ve seen is from 2006. None of the chips seem to be new, with various smudges and wear visible on the face of the chip, so they’re likely pulled from old equipment and reused on these boards. Even so, they work well.
  • Each board also comes with a 24C32A I2C EEPROM, which is nice, but not strictly necessary. I use them for storing the aging offset in case I remove the backup battery and want to tune it again without using the oscilloscope.
  • The boards also come with a holder for a backup coin cell battery. Critically, the boards are also wired with a 2N4148 diode and a 200-ohm series resistor feeding the positive terminal of the battery, presumably for use with a (not included) LIR2032 rechargeable coin cell. If you use a non-rechargeable CR2032 coin cell you must remove either the diode or resistor or else the circuit will try to charge the coin cell battery, which can damage the battery. I’ve removed the battery holder entirely from one or two other test boards and the charging circuit works well to charge a backup supercapacitor, but the charging circuit must be removed or disabled if you use non-rechargeable coin cell batteries.
  • The data here is just a brief summary; I have more detailed data in a spreadsheet that’s available upon request.

7 thoughts on “DS3231 Drift Results (5 months)”

  1. Can you please explain ….. how we can calculate drift, ppm, and how much offset to assign so that clock time gets corrected

    1. Hi Hanish,

      Your question is a good one, and has a lot of subtleties that make it hard to answer without knowing your exact situation.

      That said, I used two methods, one fast and one slow.

      The slow method is to have a system (a Raspberry Pi in my case) that’s connected to a precise reference clock (I had a GPS receiver that’s capable of disciplining my system’s clock to +/- 1 microsecond, but syncing to a nearby, reliable NTP server should get you within a few milliseconds.). It doesn’t need to be on all the time, but it does need to be on, synced, and stable when setting the DS3231 and later when you decide to check the drift. In the intervening time it can be turned off, if you wish. The DS3231 must have continuous power and be uninterrupted at all times through the measurement.

      I synchronized my Pi and used it to set my DS3231 (it’s very important to understand the offset that is applied when setting the clock. See here for details.) and recorded the exact time I set it. For example, running the command “hwclock -w && date +%s” as root will set the clock and give you the time to the second, in unix time, that you set the clock. Write that down. (You can also run “hwclock -c” to get the microsecond-level difference between your system clock [system-time] and the RTC [hw-time]; you can write that down if you wish. You just need to write down one line from that output, the rest is just periodic updates.)

      Next, ensure that your system is not automatically resetting the DS3231 — typically a Linux system will do this automatically every 11 minutes. I just disconnected the DS3231’s I2C lines so it couldn’t communicate with the Pi but left it connected to power (and with a coin cell battery) and let it run for a few months.

      Later, when I wanted to read it, I connected the clock to the Pi again and ran “hwclock -c” again and wrote down the two times.

      I then subtracted the “system-time” of when I first set the clock from the “system-time” of when I read the clock to get the difference in seconds. As an example, let’s say it was exactly 30 days, or 2592000 seconds. Next, I subtract “system-time” of when I set the clock from “hw-time” when I set the clock; this gives me the offset described above (say 0.5 seconds). Then I subtract “system-time” of when I read the clock from “hw-time” of when I read the clock. Let’s say it’s 4 seconds. I then subtract the set offset from the read offset (that is, 4 seconds – 0.5 seconds = 3.5 seconds). This means that over the course of 30 days, the clock drifted by 3.5 seconds. I then divide that value by the number of seconds the clock was running (3.5 seconds / 2592000 seconds = 0.00000135). Multiply that by one million (0.00000135 * 1000000 = 1.35) to get the drift in parts-per-million. In my example, this works out to be 1.35 ppm. Not bad.

      This method is very slow, but has the advantage of not requiring any manual effort other than setting and reading the clock. Letting it run quietly on a shelf for a month or two is pretty easy. It also means that the clock goes through many day/night cycles and is subject to temperature changes, so it helps measure the long-term stability of the clock.

      The fast method requires a precise time standard that outputs one pulse per second (e.g. a timing-grade GPS receiver) and an oscilloscope. Connect the PPS to one channel and set the oscilloscope to trigger on the PPS signal so it will update once per second. Configure the DS3231 to output a 32kHz square wave (see the datasheet — this only works with the crystal-based DS3231, not the MEMS-based DS3231M. They are quite different.) and connect it to a second channel on the oscilloscope. If you have it right, you should see the scope update once per second (since it’s triggering on the PPS signal) and showing a train of 32 kHz pulses from the RTC that will almost certainly be drifting slowly left or right, depending on if it’s running faster or slower than the reference clock.

      Start a timer or stopwatch when a rising edge of the 32kHz output reaches a convenient point (e.g. a specific mark on the graticule, or when it aligns with the PPS signal). Wait for it to drift until the rising edge of the neighboring 32kHz output pulse reaches the same point/mark and stop the stopwatch.

      Take the reciprocal of that time in seconds, then divide that by 32768.

      For example, let’s say it took exactly 15 seconds for the pulses to drift by one cycle. We calculate (1/15)/(32768) = 0.00000203. Multiply that by one million to get the results in ppm: 0.00000203 * 1000000 = 2.03 ppm.

      If you write to the aging offset and immediately trigger a manual temperature conversion the new offset will be applied immediately (otherwise you’ll have to wait up to 64 seconds). I wrote a shell script that will let me set the aging offset and send the manual conversion command so I can quickly tune the aging offset while looking at the oscilloscope (I adjust until the drift rate is minimized).

      This method is fast, taking only about a minute or two to measure, but is only applicable to the clock’s behavior at that specific temperature. If you look at the “FREQUENCY DEVIATION vs. TEMPERATURE vs. AGING VALUE” plot in the datasheet, you’ll see that the clock is calibrated to run within 2ppm across its full temperature range if the aging register is set to zero. However, if you set the aging register to a non-zero value while it’s at a particular temperature, the performance of the clock may be improved at that specific temperature, but if the temperature changes the clock may behave significantly differently (particularly if the aging offset and temperature changes are large).

      In short: to meet the rated spec in the specified temperature ranges you don’t need to do anything. Just set (or keep) the aging offset to zero and let the clock do its thing automatically. However, if you’re tuning the clock for specific performance requirements within a narrow range of temperatures the aging offset can be used to improve its performance.

      I hope this helps a bit. Good luck!

    2. Also, try doing some measurements yourself and see if you can get reasonable results. If you have questions, ask and I can try to help.

  2. I want to know that the production date of RTC, my concern is many DS3231 module buy on market the production date is many year ago, the technical specs say that the aging can up to ±5.0ppm after 1 year

    1. According to Maxim’s policy, date codes are basically irrelevant except for certain moisture-sensitive chips which are packaged accordingly.

      A commenter on a different post used to work at Dallas Semiconductor before it got borged by Maxim and said they’d often have dies sitting around for years in environmentally-controlled storage before being sent off for packaging, so older date codes aren’t a bad thing.

      As for the aging up to 5ppm after a year, you’re absolutely correct, but that only applies after the chip is soldered. Sitting on a shelf before being soldered isn’t going to change anything. Even then, that’s a worst-case spec — yours will probably not change all that much and it’s pretty straightforward to check to see if its drifted. I bet you could contact Maxim and explain your specific concerns to them and see if you can get more specifics about how the chips age over time. If you do, let me know, I’d love to know what they say.

      1. Currently, I am running my ds3231 with a display and found it drift 1 second around 1 weeks, so my RTC accuracy is around 1.6ppm, this RTC production date is 2010 year. You test result many sample is more accurate than 2ppm a lot, may be my RTC drift is not good enough to average.

        One more question, is the aging offset setting won’t lose if the battery still have power?

        1. Thanks for the info about your particular unit. Sounds like it’s meeting the specifications of <2ppm. I'm sure some specific chips are more or less accurate at any given point in time, but so long as it meets the advertised spec that's good.

          As for your question about the aging offset, the DS3231 does not have any non-volatile memory so all of the internal registers and settings will be cleared and reset to default if all sources of power are lost. If you have a battery connected and the main power is lost, the memory will retain the aging offset and other settings using the battery power.

          Depending on your specific needs, it may be worthwhile to characterize the drift of your chips during assembly, adjust the aging register as appropriate, and store that in non-volatile memory (e.g. EEPROM) somewhere. That way, a microcontroller or whatever system the RTC is connected to can read the EEPROM, compare it to the value in the DS3231's battery-backed RAM, and update the value as needed. For most uses, though, this is probably overkill.

Leave a Reply

Your email address will not be published. Required fields are marked *