Design Solutions

Crystal Calibration with GPS Redux

Written by Stuart Ball

Stuart revisits an article from 2020 with a different approach, exploring the calibration of microcontroller clock crystals using GPS technology, aimed at enhancing timing accuracy in various applications. Key findings highlight the importance of calibration for long-term timing precision, detailing methods to achieve significant improvements in accuracy.


  • Why does crystal tolerance cause cumulative timing errors?
  • How can GPS PPS signals be used for crystal calibration?
  • How does this method work on MCUs without RTC hardware?
  • How does temperature affect crystal frequency accuracy?
  • How can crystal calibration be applied in production systems?
  • GPS
  • Microcontroller timers
  • Quartz crystal oscillators
  • Microchip | www.microchip.com
  • Texas Instruments | www.ti.com

I described a method of calibrating a 32kHz clock crystal in a TM4C1233D5 microcontroller (MCU) with a GPS module in my article, “Calibrating an MCU’s RTC Using GPS: Put Time on Your Side” (Circuit Cellar 360, July 2020) [1]. The Texas Instruments (TI) TM4C parts have an internal 32KHz oscillator for implementing a real-time clock (RTC). This new approach does the same thing but with a more generalized method that applies to MCUs without a dedicated RTC oscillator and calibration register.

CRYSTAL ACCURACY

A typical crystal, as used in an MCU, has some tolerance, measured in parts per million (ppm). So the frequency of a 14.7456MHz crystal, as I’m using in this design, will vary. It’s exactly like the tolerance in a resistor or capacitor, but the tolerance of resistors and capacitors is measured in percent, or parts per hundred. Crystals are more accurate, so their tolerance is measured in ppm; 1ppm is equivalent to 0.0001%. Just like resistor/capacitor tolerance, the crystal frequency can be higher or lower than the nominal frequency.

To convert this to practical numbers, if the 14.7456MHz crystal I used in this design has a tolerance of ±30ppm, then the frequency variation is ±442Hz (14.7456MHz x 30/1,000,000). Therefore, the frequency of any given part may vary from 14.745158MHz (14,7456,000 – 442) to 14.746042MHz (14.456,000 + 442).

WHY CALIBRATE?

Why does any of this matter? In most applications, it doesn’t. Crystal accuracy is usually close enough. However, you need calibration when any timing error is cumulative. Say you are using an MCU timer to divide the 14.7456MHz clock by 14,400 to produce a 1,024Hz interrupt. If the crystal is operating at the low end of the tolerance range (14.745158MHz), then over the course of a minute there will be 61,438 interrupts. With the nominal 14.7456MHz crystal frequency, there will be a total of 61,440 interrupts; the lower frequency produces two fewer interrupts in 1 minute.

This difference matters if you are using the interrupts to time something over a long period. The obvious application is some kind of clock, such as an alarm clock. But other applications may require accurate long-term timekeeping, and you don’t always have access to the Internet to verify the time. Think of the controller for a sprinkler system, or a remote monitoring station, or anything that needs accurate time of day but can’t access an external reference. If you were using the aforementioned timer interrupt to keep track of time, then over a week the time would be off by about 20 seconds. In a month, the time is off by over a minute. In a year, more than 10 minutes. Therefore, if you need to maintain accurate time without an Internet connection, you must make the clock more accurate.

In some situations, you could incorporate a GPS receiver to track the time. But that isn’t always an option, due to either cost or location. The equipment won’t always be situated where a GPS signal is available, such as under a metal roof. The way quartz crystal wristwatches maintain accurate time is by adjusting the actual crystal frequency with a variable capacitor. That’s always an option but requires an additional manufacturing step and an accurate frequency counter.

THE CIRCUIT

Figure 1 shows a schematic of the demo circuit. U1 is a Microchip ATMega324 MCU. J1 is the MCU programming header, J2 is a diagnostic/debug serial port connector, and J3 is a socket header for a GPS module.

Figure 1
Schematic of the calibration demo board.
Figure 1
Schematic of the calibration demo board.

The GPS module I used (Figure 2) comes with a separate patch antenna that is plugged into the module. I have a couple of these modules with different pinouts for the Rx and Tx serial data. W1 lets me switch between modules. The GPS module is there to demonstrate the concepts used here. In a real product, you would use an external GPS module and only connect it when calibrating the oscillator.

Figure 2
The GPS module used in the demo circuit.
Figure 2
The GPS module used in the demo circuit.

Although the Rx pin from the GPS is connected to the MCU, it is not needed here; this project only uses the Pulse Per Second (PPS) signal from the GPS module. Once the GPS module synchronizes with the GPS satellites, it generates a very accurate pulse on the PPS line once per second. If you want to duplicate what I did here, be sure to get a GPS module with a 5-pin header. I’ve seen some that only provide 4 pins, omitting the PPS pin.

The PPS signal drives pin PD6, the input capture pin for T1, which triggers a capture of the 16-bit timer 1 (T1) count in the T1 input capture register (ICR). You could also use the analog comparator on PD3 to trigger a capture if PD6 was needed for something else.

The circuit operates at 5V simply because I needed a higher voltage for the original project. But you could operate it at 3.3V, as long as everything else works at that voltage.

Figure 3 is a schematic of the RS232 adapter to connect the debug port to a PC. If you’ve seen my articles using my standard debug/programming connector, you’ve seen this schematic. PCs don’t have serial ports anymore, so this plugs into a USB-to-RS232 adapter. It cables to the demo board via a 4-pin cable.

Figure 3
Schematic of the Interface circuit between the demo board and the PC.
Figure 3
Schematic of the Interface circuit between the demo board and the PC.
TIMER 1

This example uses Timer 1 of the ATMega device. Other devices will have other timer options. The OCR1A register is loaded with the value 57,600. Each time that Timer 1 decrements to zero, it is reloaded with the value in the OCR1A register (Figure 4).

Figure 4
Timer 1 rollover and reload.
Figure 4
Timer 1 rollover and reload.

If OCR1A is modified with a different value, the next rollover will happen at that count value instead of 57600. This is the basis of the time calibration adjustment. The Timer 1 ICP (input capture) pin is connected to the 1 PPS signal from the GPS. Each time a 1 PPS signal occurs, the count value in Timer 1 is captured and stored in a register (Figure 5). The count value is just made up for this example.

Figure 5
Timer 1 capture with the GPS 1 PPS signal.
Figure 5
Timer 1 capture with the GPS 1 PPS signal.
THE SOFTWARE

In the original TMC1233 project, the RTC register would auto-update periodically, so once the correction value was entered, it simply had to be initialized, and it would run forever. Using the ATMega MCU requires an extra step. Each time the T1 timer rolls over (that is, gets reloaded with the value of 57,600), the software has to service that event. It can either be polled, or it can use an interrupt. I polled it in the demo code. The T1 routine increments a rollover counter to keep track of when 1 second has elapsed; 256 T1 rollovers is 1 second (assuming the crystal is exactly 14.7456MHz). When that happens, the OCR1 register is loaded with the corrected count (57,600 plus or minus the correction value, as needed). On the next rollover, the OCR1 register is loaded with the original 57,600 value. Thus, once per second the correction value replaces the normal divisor, and then the normal divisor is used in all other cases. This corrects for the accumulated error over the previous second.

When a GPS PPS pulse occurs, the software sends the elapsed time in seconds to the debug serial port, followed by the captured T1 count for that interval. The code also has a #define that causes the GPS time in HH:MM:SS to be added to the output. Elapsed time and captured T1 count are hex values; the GPS time is in ASCII decimal, as it is received from the GPS module. Here are a couple of example lines with GPS time included:

000C BE87 14:46:20
000D BE89 14:46:21

The GPS time is received from the GPS module on the module serial port. Since the GPS time isn’t needed for this demo project, it’s entirely optional, and the GPS serial port doesn’t even need to be connected for the demo to work. Obviously, if the serial port isn’t connected, there is no point in setting the flag to display the GPS time.

For this demo the software is all consolidated into one main.c file. Microchip Studio was used for development, although any AVR toolset should work.

HOW IT WORKS

Let’s say that the crystal is running fast (frequency is higher than nominal) by 100ppm. This means that in one second, there will be 1474.56 more clock cycles than there would be if the frequency were exactly 14.7456MHz. T1, operating as a down-counter, will count 57,600 clocks then reload with 57,600 and start over. When the PPS signal from the GPS module occurs, the T1 count will be captured in the ICR. If the frequency was exactly nominal, T1 will be within 1 cycle of 57,600, so the count will always be the same, ±1. But in this case, it is off by 1,474 cycles per second, or 5.75 counts each 57,600-count interval. There are 256 of these intervals in a second. When the GPS PPS signal occurs, since the crystal is a little too fast, the error will have accumulated over a second, resulting in a T1 count error of 1,474. This is used as a calibration factor for adjusting the clock.

The actual calibration factor isn’t the count itself. For one thing, you don’t know where in the 1-second interval of the PPS signal the count started. So you have to subtract two successive count values to get the difference, which is the actual calibration value.

Once the calibration value is calculated, you can then insert it into the code and now the software will, every 256 seconds, adjust the 57,600 count value by the calibration value, adjusting the total counts for a 1-second interval to actually represent 1 second.

HOW TO CALIBRATE IT

The calibration process for the demo is as below:

  1. Set the (#define) correction value to 0.
  2. Capture the serial output of the elapsed time and captured count value for a few seconds.
  3. Calculate the offset by subtracting successive counts.
  4. Average a few values.
  5. Insert the correction value into the code.

Below are 10 lines from the unadjusted output of the demo circuit:

0001 471B
0002 4643
0003 456C
0004 4495
0005 43BE
0006 42E6
0007 420F
0008 4138
0009 4061
000A 3F89

The left column is the elapsed GPS seconds, the right column is the captured values from the T1 timer. If you subtract the values in the right column from each other, you will see that the difference averages about 215. This works out to about 14.6ppm, as follows:

215 cycles per second/14.745MHz
= 14.58 cycles per million clock cycles, or 14.6ppm
This works out to 14.5µs error every second.

Since the value gets smaller on each sample, we know that the crystal is running a little slow; the captured count isn’t keeping up with the PPS signal. The calibration value in the code was set to -215 (negative because the crystal is running slow). Here are the adjusted results:

0009 AA85
000A AA86
000B AA86
000C AA87
000D AA87
000E AA87
000F AA87
0010 AA88
0011 AA89
0012 AA89

It isn’t quite exact, of course, because you can only adjust the count in integral values; no fractional values are allowed. But the original, unadjusted value would be off by 8.8 seconds per week (604,800 seconds/week x 14.5µs/second = 8.8 seconds). This is over 7 minutes per year. The corrected value, allowing for ±2 counts because the actual correction isn’t an exact integer, will be 0.08 seconds in a week and a little over 4 seconds per year, or more than 100x better accuracy.

Once the crystal is calibrated, the GPS module and input capture pin are no longer needed. The internally stored correction factor will continue to be used. The input capture feature is only needed to capture the T1 count so that the calibration constant can be calculated. It would be entirely possible to write software that just does calibration and then use different software that uses the capture pin for something else entirely and doesn’t even include the capture/display code. The demo software just demonstrates the capture and calibration method; the only parts that are needed in operating code are the parts that initialize timer T1, count T1 overflow events, and insert the calibrated crystal offset once per second to produce highly accurate time. Everything else could be easily discarded.

Frequency vs. Accuracy

The original 2020 article [1] focused on a quick way to calibrate a 32.768KHz clock crystal, using the TM4C dedicated RTC timer. The ATMega324, as well as a number of other MCUs, can operate from a 3KHz clock crystal; this is typically done to reduce power in a battery-operated design. This technique will also work with other crystals, including a 32kHz crystal, with some caveats.

If a 32.768 crystal has a 100ppm tolerance, then the frequency ranges from 32764.7Hz to 32771.3Hz. 100ppm is a difference of only 3.27 cycles per second for the 32kHz crystal. The problem is that at 32kHz, you can’t accumulate enough cycles in a single second to get a good calibration value. To compensate for this, the TM4C RTC performs a correction every 64 seconds, so that more clock cycles are collected and the correction is more accurate.

The 14.7456MHz crystal used in this demo is a high enough frequency that 1ppm variation is 14 clock cycles per second. A 7.3728MHz crystal would have 7 clock cycles at 1ppm variation. Both of those can achieve 1ppm accuracy with a 1-second measurement. But at frequencies below 1MHz, you will have to accumulate more than one second of clock cycles to measure and calibrate to 1ppm. Because of this, calibration will necessarily take longer. To get to 1ppm accuracy, you need to accumulate at least 1 million clock cycles, which is over 30 seconds for a 32kHz crystal. To calibrate any crystal operating below 1MHz, you will have to accumulate errors over multiple PPS events, and you will need at least two samples (about a full minute at 32KHz). In practice, you would want to accumulate several minutes and average the counts. The bottom line is that the time it takes to get a calibration value using this method depends on crystal frequency below 1MHz. Of course, you may not need 1ppm accuracy, and calibrating to 2ppm or 5ppm will take less time.

TEMPERATURE

Crystal frequency changes with temperature. The crystal is a piece of quartz of a specific size and shape. Like all materials, the size changes a little when temperature changes. There are two ppm values for a crystal—the tolerance and the temperature stability. The tolerance in ppm is the deviation from the specified frequency at some temperature, typically 25°C. So the example 14.7456MHz crystal described here with a 30ppm tolerance will vary no more than 30ppm from the specified frequency at 25°C.

Frequency stability is a different value and is specified over some temperature range such as -10°C to 60°C (Figure 6). The 30ppm crystal might have a stability of 50ppm over -10°C to 60°C. This means that while the tolerance at 25°C is 30ppm, the frequency can vary by as much as 50ppm over the full temperature range. The effect of tolerance and stability are additive, so that hypothetical crystal will have a total tolerance of 30ppm + 50ppm over the temperature range. It will still have a 30ppm tolerance at 25°C, but the further the temperature gets from 25°C, the more it will vary. Note that this is the maximum range; if the actual crystal is accurate to 10ppm, then the total tolerance plus stability will be 60ppm for that specific part.

Figure 6
Crystal temperature variation.
Figure 6
Crystal temperature variation.

Crystals come in different temperature ranges, so if your operating temperature is fairly wide (e.g., a clock in a car), you might want to use a crystal with better temperature stability. You’ll pay for it, of course. Note that different cuts of crystals have different temperature variation curves; Figure 6 is just an example.

Temperature Compensation

If you need better accuracy over a wider temperature range, you can calibrate the crystal for that as well. You would heat and/or cool the crystal (or the entire product) over the temperature range where it needs to operate and at each temperature step. Maybe you vary the temperature in 10°C steps. When you’re done, you have a table of calibration constants versus temperature. Embed that in your MCU EEPROM and you know what calibration constant to use at any given temperature. Of course, the MCU has to be able to measure ambient temperature for this to work. Calibration will take longer as you have to step through the temperature range, allow it to stabilize, and then capture the timer deviation to build the table of calibration constants. This is something you would only want to do if you really need to high accuracy over a range of temperatures.

This might seem to be overkill since so many electronics operate at or near room temperature. But a product operating outdoors through all four seasons in a hot or cold climate may need temperature compensation.

COMMERCIALIZING IT

Of course you wouldn’t want a GPS module installed in every production unit; that would defeat the purpose. What you could have is a master GPS module that drives multiple units at the final test stage of the product and add code to do the calculations and set the offset, storing it in the MCU EEPROM (instead of as a hard-coded #define). Each unit could self-calibrate in a few seconds.

OTHER MCUs

You could implement this on different MCUs; the key features are a timer that has auto-reload of a divisor value and an ability to capture the count value in an internal register in response to an external signal. A number of the ATMega parts have this capability. The Microchip XMega parts also support this. In addition, some of the TI TM4C1233 parts have this capability.

This is far from an exhaustive list of MCUs that can implement this technique. If you have a specific MCU family that you want to try, you’ll have to look through the datasheet to see if the necessary timer features are supported.

CONCLUSION

Measuring accurate time is sometimes important. You can’t always connect to a Wi-Fi network, and you can’t always embed a GPS module in your product. In my last article on this subject, I explained a way to quickly calibrate the built-in RTC in the TI TM4C family of parts. Here, I’ve demonstrated how to apply the same basic technique to a wider expanse of MCUs, using general-purpose timers. If you are in a situation where you need this kind of long-term timing accuracy, I hope this is helpful. 

— ADVERTISMENT—

Advertise Here

RESOURCES
Microchip | www.microchip.com
Texas Instruments | www.ti.com

REFERENCES
[1] Stuart Ball, “Calibrating an MCU’s RTC Using GPS: Put Time on Your Side.” Circuit Cellar 360, July 2020.

PUBLISHED IN CIRCUIT CELLAR MAGAZINE • JUNE 2025 #419 – Get a PDF of the issue

Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.


Note: We’ve made the Dec 2022 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article
+ posts

Stuart Ball recently retired from a 40+ year career as an electrical engineer and engineering manager.  His most recent position was as a Principal Engineer at Seagate Technologies.

Supporting Companies

Upcoming Events


Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2026 KCK Media Corp.

Crystal Calibration with GPS Redux

by Stuart Ball time to read: 13 min