What is a Crystal Oscillator?Quartz crystals are electronic components that resonate at some particular frequency. They are used in computers to generate clock frequencies, both directly for the real time clock as well as reference inputs to chips that generate the high frequency clock signals needed for the CPU, memory and I/O buses.
What is an Oven Controlled Crystal Oscillator?Like most electronic components, crystals are dependent on temperature. The rated frequency shifts slightly up or down depending on ambient temperature. This is undesirable for precision timekeeping. OCXOs compensate for this by putting the crystal in a temperature regulated heated can ("the oven").
Description of Hardware Used
|Salvaged Trimble 65256 unit|
Connecting OCXOs to a ComputerThe kernel timekeeping framework, timecounter(9), makes it easy to hook up arbitrary digital counters and use them as a source for time. We could easily build a microcontroller circuit that counts the sine wave signal and feeds the counter serially into a gpio(4) pin. But then we need a microcontroller and also we have to characterize and account for the latency and jitter of reading a GPIO pin.
|Banana Pi M1 SBC|
A problem is that our replacement reference clock runs at 10 MHz, not 24 MHz, so time will slow down by a factor of 10/24. The board itself doesn't really care or even know about this, but it becomes an issue when interfacing with the rest of the world. For example the serial UART baud rate will be wrong. Fortunately this can mostly be compensated for in software by reprogramming relevant clock multipliers.
How Clock Signals Are Generated On The M1 Board
|Figure 1: Location of X24* pins on SoC|
On the M1 board the crystals are connected according to Figure 2. The crystal is labeled X1 on the board and is easy to locate visually (Figure 3).
|Figure 2: M1 Oscillator schematic|
|Figure 3: X1 location and pins|
|Figure 4: simplified model of internal clock amp|
We don't know anything about how the clock amplifier circuit inside the SoC is designed, but a typical clock amplifier circuit looks something like figure 4 and for our purpose this simplified model serves fine. We need to desolder X1 and adapt the 10 MHz signal to make it suitable to inject at X24MI. The amplifier circuit will then take care of cleaning up the signal for us.
Oscilloscope MeasurementsScope snapshots from X24MI, X24MO and the 10 MHz signal for comparison. The amplifier output has some undershoot/overshoot but that's okay because it gets further filtered and cleaned up inside the SoC.
|10 MHz reference clock terminated to 50 Ω|
Clock Adapter CircuitI made this simple adapter board to connect the clock. The purpose is to shift the signal upwards to be centered around roughly Vcc/2 and to terminate it to roughly 50 Ω. The exact values are not hugely important. We just want to make sure we don't feed negative voltage into the amplifier input as that could potentially destroy the SoC.
|Clock adapter schematic|
|Clock Adapter on veroboard. Note that the 24 Mhz crystal has been removed from the board.|
|System Powered up.|
Kernel ModificationsNext we must tell the kernel that we have changed the reference clock from 24 MHz to 10 MHz. In NetBSD this is controlled by AWIN_REF_FREQ and we can accomplish what we need by changing a single line in the source code.
Here is a diff comparison of dmesg(8) output after changing this constant:
-cpu0 at mainbus0 core 0: 912 MHz Cortex-A7 r0p4 (Cortex V7A core)
+cpu0 at mainbus0 core 0: 380 MHz Cortex-A7 r0p4 (Cortex V7A core)
-armgtmr0 at armperiph0: ARMv7 Generic 64-bit Timer (24000 kHz)
+armgtmr0 at armperiph0: ARMv7 Generic 64-bit Timer (10000 kHz)
Unfortunately as a side effect our CPU speed has slowed down quite a bit. But 380 MHz was enough to run an NTP server in the 1990s so it should suffice now. Running slower is also more power efficient. :-)
ConclusionReplacing the reference clock on this board was quite easy. It would be interesting to attempt the same operation on an x86 motherboard at some point. But it would probably be much harder to adjust all the clock multipliers on an x86 system.
In the next post I will attempt to calibrate the clock with NTP.