Circuits, details and code for an Arduino based clock that uses a 10 MHz OCXO as a reference.
This project describes a digital clock that uses a 10 MHz reference oscillator as its timing reference. This opens the possiblity of using a high stability OCXO reference to ensure high precision, beyond that of the convnetional clock. Precise time and frequency is an important requirement in many scientific applications. This used to be way beyond the scope of budget of many enthusiasts. There are those out there who go with the nickname Time Nut who scour online auctions for vintage atomic references like a Hewlett Packard 5061B Caesium clock so that they can poses a frequency reference with a stability accuracy of 2x10^-12. Recently these have come down in price to the point with Microchip offering a Rubidium Oscillator in a small compact package with an accuracy of <5x10^-11 for $2000. These may be beyond the scope of many, but temperature controlled crystal oscillators (TCXO) and oven controlled crystal oscillators (OCXO) with accuracies of 1x10^-6 and 5x10^-8 respectably. This is far better than the typical 20x10-6 of the 32.768 kHz crystals used in most digital clocks and the DS3231 which forms the basis of many digital clocks implemented on an Arduino or other micro-controller based platforms. Even worse is the 0.5% accuracy of the ceramic resonators used by the Arduino as a clock. There are of course other options. Here in the UK the MSF transmissions at 60 kHz can be picked up by alarm clocks and watches to offer 2x10^-12 accuracy at home. Similar for the DCF77 in Germany at 77 kHz and WWV in the USA. GPS reception also offers an accuracy of 3x10^-8. All of this pushes the desire for a clock with an accuracy which is better than possible by the conventional 32.768 kHz crystal. This was the inception for this project, what accuracy is possible using modern crystal oscillators. 10 MHz has become the standard frequency for references, and so from hereon, it is assumed that this will be used. This project is highly flexible by its nature, so references with others frequencies could easily be used if desired.
Previous work in this area had resulted in a divider chain to produce 32.768 kHz from 10 MHz. This was achieved by dividing 10 MHz by 1.25 x 2.5^6 using 74XX series discrete logic. The objective with this project was to build a clock from the ground up which could offer an accuracy far beyond anything which was consumer available. Although there is an appeal to building a clock completely in discrete logic, that limits the displays to generally seven segment LED types. For more complex displays, a micro-controller platform offers more options. The basic platform here is an Arduino Nano which offers far more processing power than is necessary for performing a simple hours-minutes-seconds type clock but is cheap and simple to use. There are many designs available online for such clocks, but they all inevitably rely on the DS3231 real-time clocks with its 2x10^-6 accuracy. One option could have been to drive the DS3231 with the divider chain mentioned above, but this was considered messy and would not really provide any great advantage. The Arduino uses a 16 MHz ceramic resonator for its clock as mentioned above. It is not easy to change the frequency of this, to say 10 MHz without modify the firmware, and 16 MHz is used to derive the USB communications timing. Internet searches did not find any Arduino based clocks which used an external crystal reference surprisingly, so that was not an option. A physical switch to switch between 16 MHz and 10 MHz was an option, but not very practical. All microprocessors includes interrupts, which when triggered can pause the normal code running, move the registers to a memory location, carry out an interrupt service routine and then return to normal operation. These can generally be triggered by a clock driven timer or an external input on a dedicated pin. The Arduino includes three interrupt timers Timer0 and Timer1 can also be driven by an external clock source through the T0 and T1 pins. Timer0 is 8-bits where as Timer1 is 16 bit. The prescalars allows 2N division up to 1024, but are only accessible through the internal clock source. Setting CS10,CS11 and CS12 selects the external clock, but doing so bypasses the prescalar When used with an external clock on T0 or T1, the signal is sampled relative to the system clock. Using a maximum Nyquist sampling factor of 2.5, a realistic maximum external input frequency of 6.4 MHz results. Adding a 4 bit binary counter after the 10 MHz reference results in a 625 kHz, which when divided by 62500 (<216) results in 10 Hz. This triggers the interrupts and a chain of counters for seconds, minutes and hours as shown in Figure 3. Further dividers are implemented in software to generate 1 Hz, and then units and tens of the seconds, minutes and hours as separate LED displays are used for each. This will be explained in a further section which details the software and hardware implementation.
An Arduino Nano is chosen for the platform, as it offers the same capabilities as the bigger platforms but is in a more compact form factor and is very cheap. Like most cheaper platforms it uses a ceramic resonator for timing, making it unsuitable for any critical applications. It does however include the usual SPI and I2C interfaces which make it easy to interface to modern displays with built in drivers. The OCXO (X1) chosen is a Raltron Electronics OX4120A-D3-5-10.000-3.3 available from Digikey. Any suitable OCXO could be used, even one with a difference frequency by changing the divider ratio. It also comes in a standard 14-pin dual-in-package (DIP) package. As the most expensive component, during most of the development a standard low cost 10 MHz oscillator was used. All of the components used in this project are either in DIP format or available in DIP modules for easy construction. The PCB is produced in KiCad and is made available both as KiCad files and gerbers through github for others to modify under the creative commons licence (File: OCXO_Clock_code_03_08_23). This allows components of different layouts to be used for example. Similarly, the 4-bit binary counter (U3) between OCXO and Arduino is a 74HC191. Any binary counter could be substituted for this provided it provides division. The OCXO is a 3.3V part, so a LD1117V33C linear low-drop-out (LDO) voltage regulator U2 derived this from the 5V system voltage. The 74HC191’s inputs are compatible with 3.3V logic levels so a translator is not necessary. The regulator is not critical, alternative LDO or switching types could be used. A second identical regulator U3 provides 3.3V to the displays.
The display chosen are six Adafruit CharliePlex FeatherWing (A2-A7). These consist of 7x15 pixel array of LEDs which can be driven individually in a graphical mode or using fonts built into the Adafruit_IS31FL3731 library. They are communicated with by an I2C. The address of each can be set to one of two values: by default 0x74 but you can be changed to 0x77 by bridging a link. To drive multiple displays an I2C expander chip the TCA9548A (A8) is used. It has the address 0x77 (TCAADDR). The procedure for driving the TCA9548A is that first a command is sent to it to direct the input data to one of eight outputs. Then the command for the display digit is sent. The TCA9548A is only available in a surface mounted (SMT) package, but is available from Adafruit as the 2717 break out board in a DIP adapter board. This is available through Digikey and other online sellers. The CharliePlex displays in this project they are driven graphically with a separate look-up-table (LUT) for each character (0-9) and a whole byte for each pixel storing either a 0 or a 1. Although inefficient in the amount of memory space it takes up, this allows custom fonts to be easily programmed. A separate variable is used to set the brightness of the display. This could allow for dimming the brightness of the display at night if required. The seconds-minutes divider and minutes-hours divider are two separate LEDs. These are toggled on and off at a rate of 0.5 Hz by the one second divider chain. Their function or operation could be easily changed by modify the software.
A single rotary encoder with a momentary press switch is used as the user interface. This gives the clock a modern minimalist feel. Separate press switches could of course be used with only minimum changes to the hardware and/or software. The rotary encoder software aims to mimic the operation of a monostable to reduce the impact of switch bounce. It was largely successful, although a few erroneous counts got through. Alternative rotary encoder software could easily be substituted into the clock. Although the prototype was built on one printed circuit board, it was designed so that it could easily be cut into two, so one mounted behind the other with header connectors for a more compact layout. This is reflected in the schematic with J1-4.
The software is available here. Only two libraries, the aforementioned Adafruit_IS31FL3731 and the common Wire which enables serial communication including I2C and SPI. Next is the LUTs for the display. It is obvious by looking at them which digits are stored in which LUT. The setup checks that each of the displays is functioning correctly and will send a command over the serial interface if not. Next Timer1 is setup for an external clock and to divide by 62499. This is 62499 and not 62500 as one instruction is needed to reset the counter. The primary function of the main loop is to call the rotary encoder subroutine. The encoder subroutine aims to mimic a monostable to eliminate switch bounce. The code could easily be change here by a user. The displays are also driven here, but only when a toggle bit is enabled from the interrupt timer. Driving the displays in the graphical mode requires individually programming each of the 105 LEDs (15x7). There is also a brightness variable here which is user settable and the variable for increasing the brightness of a digit when it is being set. The Timer1 interrupt service routine is next which is called ten times a second. It consists of the divider chain. The LEDs between the seconds and minutes, and the minutes and hours are flashed here. Their function could be easily changed if desired. The final subroutine tcaselect deals with the TCA9548A I2C expander chip.
The schematic is exported to KiCad’s PCB layout. The final board is not complex and designed as a double sided board which is easy to solder. It is designed to be easily broken into two sections along the two cutouts either with a saw or scoring and snapping. Pads are fitted so that headers can be soldered in to plug the boards one behind the other making a more compact form suited to a desk clock. In this form, the “top” board holds the display and rotary encoder, with all else on the back board. The rotary encoder is fitting in the centre of the board, but this could course be moved to elsewhere and attached via flying leads. The prototype PCB was ordered through JCL in China, but any PCB fabrication house could be used for this or builders could do it themselves with a chemical process or routing machine. A photograph of the final board is shown in Figure 5, note there were some were some errors in the original layout which have been corrected in the final layout in Github. The bottom portion of the board contains the Arduino, the I2C expander, the OCXO, divider chain and voltage regulators. The voltage regulators are mounted with the tabs facing outwards so heatsinks can be fitted if required. This wasn’t found necessary in the prototype, but if for example the displays are driven at a high current it maybe necessary. If the boards are mounted one behind the other, they are placed back to back, so all the components will be accessible from the back of the clock. This will make the design easier to hack if required. M3 holes are fitted in the board for easy mounting and these line up for the upper and lower parts of the board if they are mounted back to back with headers. Metal spacers can be fitted to provide the correct clearance and mechanical stability. Two mounting holes are also fitted above and below the OCXO. This is to provide mechanical stability. The OCXO is a relatively heavy component and held into the board simply by four bits in a DIP socket. This is also mounted vertically, so not particularly stable. A piece of wire can be threaded through the two holes with its ends twisted together to hold the OCXO is place. Cable ties could also be used, or a clamp if available. There are two sets of schematics, PCBs and gerbers files. This is because the TCA9548A modules comes in two flavours. The Adafruit one has a spacing of 0.6 inches between the rows (the "N" version) and the modules available on ebay have a 0.7 inch spacing. Double check which one you are using before fabricating the PCBs.
The OX4120A-D3-5-10.000-3.3 is a fixed OCXO – it does not allow the ability to adjust the frequency. Alternative OCXOs do by applying a control voltage to one of the pins. This decision was made as its stability was believed to be high enough. However, the PCB could be easily modified to incorporate a trimmer resistor, or one fitted on flying leads so it is easily accessible. The problem then resides of how to check the accuracy of the clock and calibrate if needed. This requires a higher accuracy reference clock. The best the author had in his lab was a HP 53150A frequency counter with its own OCXO reference. It was last calibrated in 2013. When measuring the OCXO reference the frequency on the counter fluctuated between 10,000,000 and 9,999,999. This suggests an agreement and hence accuracy of better than <10-7. Being newer, it is likely that the OCXO in this clock is better than HP counter!
This project features several modules which are fitted with headers. These could be soldered directly to the PCB, but for convenience female sockets should be fitted as described in the BOM. This will allow parts to be changed in they become damaged or just for easy modification. Similarly, ICs sockets are fitted for U3 (74HC191) and X1 (OCXO).