My first cuts at the crazy clock calibrator were using TCXOs with two different firmware loads. One load would test the clocks, the other load would accept a GPS PPS signal and would display the oscillator's drift relative to GPS. I could then subtract that drift out of the measurements of the clocks.
I tried to think of ways to allow the controller to do both at once. After all, a PPS signal (in principle) shouldn't distract the controller too terribly much. The problem is that the ATMega328P controller I like to use has only one input capture pin. Recall that the input capture pin allows you to use a non-prescaled timer (running at the system clock speed) to time things at maximum resolution, while the clock's value will be "frozen" by a rising edge on the ICP pin.
Since you can't watch two events at once with a single ATMega, it briefly occurred to me in a humorous way to simply use two. But in a "ha ha only serious" moment, it immediately occurred to me to simply separate the two problems - resulting in a frequency counter with a separate clock source, and a hyper-accurate disciplined clock generator.
The basic design of the project centers around either a VCTCXO - a Voltage Controlled Temperature Compensated Crystal Oscillator or a VCOCXO - a Voltage Controlled Oven Controlled Crystal Oscillator. At first, that nomenclature seems contradictory. Which is controlling the oscillator? A voltage or the temperature compensation? In fact, what a VCTCXO is is a normal TCXO (a crystal oscillator which is "steered" by a temperature compensation circuit) with a voltage input that allows the output frequency to be trimmed over a relatively narrow range. The specification of the oscillator says that a voltage ranging from 0.3 to 3.0 volts will push or pull the TCXO ±10 ppm or the OCXO ±400 ppb. A VCOCXO is like a VCTCXO, except that the crystal is housed in an oven that tightly controls the temperature of the crystal. OCXOs are much more stable than TCXOs, but the oven requires a great deal of current.
The microcontroller is going to need to be able to manage the control voltage to trim the frequency from the GPS feedback. I briefly considered using the traditional Arduino method of PWM duty cycle manipulation to effect a D/A converter, but quickly rejected that. The TCXO has a basic short-term stability of 1 ppb. If we want to try and keep it in trim, we need to be able to have at least that level of granularity of control, preferably much less. We're already using the 16 bit timer for measuring the frequency. If you do the math, a one volt change in the reference is 7 ppm (or so), meaning that dividing our 2.7 volt tuning range into 256 levels results in a granularity of ~70 ppb per step. That's not nearly good enough. Using a 16 bit D/A converter, by contrast, gives us a granularity of just under 0.4 ppb. We can do better than that, however, because the outer 0.3v of the DAC range is "dead space" to the oscillator. Also, the long term accuracy specification of the oscillator lists < 5 ppm of total, lifetime drift. That means we can throw away half of the DAC tuning range (the outer 25% on the top and bottom) and still be able to steer the oscillator more than its lifetime expected error range. That doubles our granularity to around 0.2 ppb.
Connor Winfield has an application note that actually includes a schematic for a D/A trimmed oscillator. We started with that design, but a lot of the things they recommend have gone by the wayside. Their design included a buffer OP amp. Along the way, we turned that into a compression amp, but the design now is simply a voltage divider consisting of just 3 resistors. The aim of the voltage divider is to reduce the range of the DAC to the useful portion of the oscillator's control voltage input. For the TCXO, we reduce the swing to 50% of the 3.3v DAC output range, and for the OCXO, we reduce the swing by around 25%. But in both cases, we want the center of the range to remain at 3.3/2, or 1.65V. To do that, we use a pair of 10kΩ resistors in a divider configuration, then apply the DAC output through a third resistor. For the TCXO, the value is 4.7kΩ, for the OCXO it's 1kΩ. We also use a high precision voltage regulator to feed the voltage divider and the DAC's Vref rather than using the oscillator supply rail. Connor Winfield's application note warns of differential temperature curves between separate supplies causing a compound frequency error, but in our experience deriving the control voltage from the oscillator supply degrades the resulting stability because of supply noise. The high precision LDO is simply less noisy.
Our first GPS receiver was the venerable AdaFruit Ultimate GPS module, which is the GlobalTop PA6H. The board has an SMA external antenna connector because when you place the module in an enclosure, the internal patch antenna won't get good enough reception. Placing the device in an enclosure is important, as it helps the oscillator maintain maximal stability by avoiding temperature shifts due to airflow. The current GPS receiver is the SkyTraq Venus838LPx-T timing module. This module doesn't have an internal antenna, so an external antenna is even more mandatory than before. The SkyTraq module doesn't include any facilities for providing active antenna power, so it's coupled to the antenna with a 0.033 µH inductor. The module has a blocking cap on its input, so a full bias-T is not required. There's also a UHF RF rated TVS diode across the SMA connector, and the DC power goes through an AP2331 current limiter to protect the rest of the system from shorts and transients on the antenna line. The Venus838LPx-T is a timing module rather than a navigation module. This means that it operates under a basic assumption that it's installed in a fixed location and that it can therefore optimize the solution for accurate time information rather than position. It also includes a sawtooth correction NMEA sentence that can be used to increase the precision of the PPS edge (in our case, it's a correction applied to the phase measurement described below).
The PPS output of the GPS module connects to the ICP pin of the controller, which will be the first calibration source. I say "first," because if all you get is 1 pps, then the measurement granularity is 100 ppb per second (that is, one ten-millionth of a second granularity). If that's all you have, then your time constant must be very long, which will make medium term ADEV suffer and make startup take a very long time. As an alternative, directly measuring the phase of the output is desirable so that the measurement granularity can be increased. To do this, we use a 4046 PLL chip's "number 3" phase discriminator. One of the fan-out chip's 10 MHz outputs is fed into a decade counter configured as a divide-by-ten. The output of that is fed into the signal pin of the 4046. The reference pin is fed from the PPS signal from GPS. The result of that is a pulse between 0 and 1 µs on the PD3 output. The VCO section of the 4046 is disabled by pulling the INH pin high. The output pulse can be converted into a (roughly) proportional voltage with a Schottky diode and an RC network. The time constant of the RC circuit is 680 ns, which makes the output voltage roughly 0 to 2 volts or so. To improve the linearity, a JFET is used as a constant current source for charging the cap. The result is not perfectly linear, but it doesn't really have to be. What matters is that the drift rate can be measured repeatably. A 1 MΩ resistor across the cap makes the discharge time constant 680 µs, which insures the cap is discharged before the next PPS pulse arrives, but not so quickly that the PPS ISR in the firmware doesn't have a chance to read it. By choosing the 1.8 volt ADC reference, we arrive at close to a 0-1023 ADC range corresponding to 0 to 1 µs pulse width. The top of the range doesn't line up with the reference perfectly, but in practice it's close enough to work well.
Stability of the power supply feeding the oscillator and analog sections of the circuit are critical. On one of the prototypes, blinking the LEDs actually resulted in measurable frequency modulation on the output. To prevent this sort of thing, the digital section's power rail is separated from the power input with an inductor. The inductor should resist passing changes in current from one side to the other. The voltage on the digital side will be less stable (because the inductor will limit the stabilizing influence of the regulator), but that doesn't matter much. In addition to this, the analog section has its own separate high precision regulator fed directly from the 5 volt input power. This reference supply feeds the VREF input of the DAC and its virtual ground voltage divider. The oscillator has its own 3.3 volt supply - an LDO for the TCXO and a buck converter for the OCXO (with an extra LC filter on the output to further reduce noise and ripple). Lastly, the GPS module has a dedicated 3.3 volt LDO fed from the digital 5 volt rail.
Earlier versions of the project used an ATTiny4313 controller, but with the addition of the phase discriminator, we needed to add an ADC. The next controller was the ATTiny841. The 841 has fewer pins, but the trade-off is that it is a smaller form factor (SOIC-14 instead of -20). The controller also has two UARTs, one of which we use as the combined diagnostic and GPS communication port. The other UART, unfortunately, doesn't have a pinning option that doesn't interfere with some other function we need. Of the 14 pins, 3 of them are power and !RESET, one is used for the input clock, one for the PPS input, one for the phase discriminator, two for LEDs, three for the DAC, two for serial, and one is unused (except that it's part of the programming interface). When the timing receiver was added to the system the 841's flash wasn't enough, so the controller was upgraded to the ATMega328PB. That has plenty of flash and RAM space, and also has the other facilities needed (UART and ADC). That needed to be swapped out because the FEI board variant (read below) needed to be able to change clock sources programmatically, and the 328PB couldn’t. The new controller is the ATXMega32E5. While it wasn’t strictly necessary to upgrade the OCXO board, the benefit to doing so is that now the firmware source can be shared between the two variants. The difference between the two (as far as the controller is concerned) is that the SPI DAC is exchanged for serial commands to set the EFC. There’s also a !OSC_RDY pin we have to wait for before the Rubidium oscillators can be disciplined. The XMega controller requires 3.3v and is not 5v tolerant, so it’s powered from the 3.3v LDO that powers the GPS module and a single-gate inverter chip is used to translate the clock to 3.3v.
There's another newer variant of this project: the FE-5680A discipline module. It's intended to power and discipline an FE-5680A or FE-5650A rubidium frequency standard. These standards are widely available from eBay. Their short term ADEV is not as good as an OH300, but starting at a tau of around 10 seconds they are better. Since the board doesn't include the oscillator, it's less expensive by itself. Originally it required a 30W+ 17-24 VDC power supply (a surplus laptop power supply was the best source), and has two buck converters to supply both the module and the discipline circuitry. The first made 15V @ 2A, the second 5V @ 500 mA. Since then, however, this has changed to using USB-C PD. The input power is controlled by the CYPD3177 BCR (barrel connector replacement) chip. This chip is configured to request (and only accept) 15V @ 2.25A. The BCR chip controls a beefy P MOSFET to gate input power to the rest of the system, and it won't turn on unless the PD negotiation is successful and the input power supplied is correct. This is fed directly to the oscillator and a buck converter centered around the AP63205 is used to make 5 volts. Just about any 45+ watt USB C power supply can be used. The only other difference is that the DAC has been traded for an RS-232 level converter, as the frequency of the FE-5680A can be trimmed with serial commands. The FE-5650A differs from the FE-5680A in that the serial port is TTL level instead of RS-232, and the output is delivered to an SMA jack rather than the DB9. The board has solder jumpers to accommodate these differences. The ATXmega32E5 has two UARTs, and the second is dedicated to the oscillator for this purpose. A self-biased inverter gate is used to convert the oscillator's sine output into a square wave. All the rest - the phase discriminator, controller and output buffering - is the same (albeit in a different form factor). The board can also correctly discipline an FE-405B, which is just an OCXO (but a particularly good one). The rub is that the 405B output is 15 MHz instead of 10, so some tweaks to the firmware are necessary.
I'd like to acknowledge the generous assistance of Jim Harman for his suggestion of the design for the phase discriminator, and Tom Van Baak for his generous assistance in testing my numerous design iterations.