Saturday, April 22, 2017

Adventures in Time, part 1: Interfacing an Oven Controlled Crystal Oscillator to a Computer Running NetBSD

In this series of blog posts I will adventure into the field of precision timekeeping. Part one will explore how to interface a precision clock source to a computer. In future posts I will attempt to calibrate the clock source with NTP and measure it's performance.

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
I purchased two of these used OCXOs from an Ebay listing a few years ago because I wanted to learn more about precision timekeeping. (But then for some reason I shelved them and forgot about them until now!) They are powered by a +12 V rail and generate a 50 Ω ±800 mV sine wave signal at 10 MHz. They contain an internal 2.5 V reference voltage which should be used by external circuitry to generate a calibration voltage.

Modified OCXO
The modules arrived without any leads or calibration, so first I had to modify them. I glued a trim pot to the side of the can. Resistors, like crystals, also have temperature coefficients. I figured that since the oven is temperature controlled the resistor should maintain a reasonably constant temperature if glued directly to the lukewarm can. The idea then is that the trim pot can be used as a voltage divider to generate the calibration voltage. For the signal output I used some thin coaxial wire salvaged from a laptop WiFi antenna.

Connecting OCXOs to a Computer

The 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
So, instead we will try to replace the computer's existing reference clock. The computer we will use is a Banana Pi M1 SBC running NetBSD/evbarm. The M1 uses an Allwinner A20 SoC, designed to be used with a single 24 MHz reference clock, which is multiplied and divided to synthesize all the clock signals required by the board. Everything from the CPU to serial UARTs and the HDMI port is referenced to this clock. For example the CPU clock runs at 24 Mhz × 38 = 912 MHz.

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

Location of X24 pins on SoC
Figure 1: Location of X24* pins on SoC
The A20 SoC contains an internal PLL circuit. on the SoC there are two pins X24MI (clock input) and X24MO (clock output), across which the SoC expects a 24 MHz crystal to be connected (Figure 1).

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 Measurements

Scope 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.

OSC24 input

OSC24 output

10 MHz reference clock terminated to 50 Ω

Clock Adapter Circuit

I 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 Modifications

Next 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. :-)


Replacing 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.

Thursday, October 30, 2014

How to solve "No certificate file found in the SD card" on Android

Short blogpost since I just wasted a lot of time trying to import a CA certificate on my Phone. The cert wouldn't be recognized no matter what kind of encoding I used. The error message "No certificate file found in the SD card" is actually very misleading. Solution: You need to store the certificate on the Phone's internal storage, not the SD card.

Wednesday, April 9, 2014

How Farnell Element14 ships 5 ICs

I don't even have a pick and place machine, what do I do with all these QFP trays?!

Sunday, May 19, 2013

Hacking a finicky Sun Blade 1500 workstation

So I wanted to upgrade my trusty old Sun Blade 1500 from 2x512MB to 4x2GB RAM. Went on Ebay and picked up 8GB for $25 (4 x Elpida PC2100R-25330-N1, DDR ECC REG memory).

Memory arrived a few days later but the Sun wasn't having any of it. POST said:

ERROR: CPU0 DIMM 0 SPD reports DIMM cycle time is less than 133 MHz.

It turns out that these machines are really picky about memory timings if you have the latest Openboot firmware. Most forum posts found with google suggest downgrading the firmware, but this isn't an option anymore since Oracle have since long pulled all firmwares from their support site.

Apparently you need CL2 memory with an SPD1.0 ROM which is practially impossible to find these days.

Hmm. Since there is the workaround of downgrading the Openboot firmware, I guessed the modules would actually be electrically compatible if you could somehow replace the SPD EEPROM. Time to fire up the scope and soldering iron!

Cue impromptu SPD dumper / flasher tool:

Fortunately Elpida was kind enough not to write-protect the EEPROM so I didn't actually need to desolder it. The EEPROM needs 3.3V but the micro is 5V. A resistor divider with a cap provides the 3.3V rail.

Now it was just a matter of dumping the first 64 bytes of the SPD of the working 512MB module:

8008070d0b0148000470750282040401 |......H..pu.....|
0e040c010226c075750000503c502d80 |.....&.uu..P<P-.|
909050500000000000414b3032756400 |..PP.....AK02ud.|
00000000000000000000000000001077 |...............w|

The new module:

8008070d0c0248000475750282040401 |......H..uu.....|
0e040c010226c0a0750000503c502d01 |.....&..u..P<P-.|
909050500000000000414b3032750000 |..PP.....AK02u..|
000000000000000000000000000000b6 |................|

And patch stuff related to timing but not to size:

8008070d0c0248000470750282040401 |......H..pu.....|
0e040c010226c075750000503c502d01 |.....&.uu..P<P-.|
909050500000000000414b3032756400 |..PP.....AK02ud.|
000000000000000000000000000010fa |................|

This adjusts byte 9 (cycle time at highest CAS latency), byte 23 (cycle time at medium CAS latency), byte 46 (reserved value?), byte 62 (SPD revision) and byte 63 (checksum).

Success! Openboot and NetBSD detect both the old and the new memory:

spdmem0 at iic0 addr 0x50
spdmem0: DDR SDRAM (registered), data ECC, 512MB, 286MHz (PC-2300)
spdmem0: 13 rows, 11 cols, 1 ranks, 4 banks/chip, 7.0ns cycle time
spdmem0: tAA-tRCD-tRP-tRAS: 1-3-3-7
spdmem0: voltage SSTL 2.5V, refresh time 7.8us (self-refreshing)
spdmem1 at iic0 addr 0x51
spdmem1: DDR SDRAM (registered), data ECC, 512MB, 286MHz (PC-2300)
spdmem1: 13 rows, 11 cols, 1 ranks, 4 banks/chip, 7.0ns cycle time
spdmem1: tAA-tRCD-tRP-tRAS: 1-3-3-7
spdmem1: voltage SSTL 2.5V, refresh time 7.8us (self-refreshing)
spdmem2 at iic0 addr 0x52
spdmem2: DDR SDRAM (registered), data ECC, 2GB, 286MHz (PC-2300)
spdmem2: 13 rows, 12 cols, 2 ranks, 4 banks/chip, 7.0ns cycle time
spdmem2: tAA-tRCD-tRP-tRAS: 1-3-3-7
spdmem2: voltage SSTL 2.5V, refresh time 7.8us (self-refreshing)
spdmem3 at iic0 addr 0x53
spdmem3: DDR SDRAM (registered), data ECC, 2GB, 286MHz (PC-2300)
spdmem3: 13 rows, 12 cols, 2 ranks, 4 banks/chip, 7.0ns cycle time
spdmem3: tAA-tRCD-tRP-tRAS: 1-3-3-7
spdmem3: voltage SSTL 2.5V, refresh time 7.8us (self-refreshing)

Curiously reports it as PC-2300 when it's supposed to be PC-2100 but oh well, it boots and seems to be stable enough for use.

Monday, February 25, 2013

Worthy successor of the Logitech UltraX flat keyboard?

For years I've searched for a worthy replacement of the discontinued Logitech UltraX flat keyboard.  I think I finally found something which looks and feels very close. The Plexgear SL-X. Plexgear is a low-end OEM brand of the Kjell & Co electronics outlet store here in Sweden, but the keyboards are probably made in China and sold under many different brands. Some pictures for comparison:

Wednesday, April 18, 2012

Electroplating experiments

I'm trying to develop a DIY through-hole electroplating process. Initial results are promising. Will write more about it later, but for now only some pictures.
Sodium persulfate and some copper pipes dissolved in distilled water. Pretty colour. Gnarly stuff. Don't drink this.

Adding value to a 5 SEK coin.

Friday, April 13, 2012

DIY benchtop photolithography system

Today's hack is a benchtop photolithography system for developing printed circuit boards. It's made out of a pringles can. The inside of the pringles can is coated with aluminum which should help reflect UV light.