Sunday, March 9, 2014

NTP / PTP Server

I have always wanted to run a good Stratum 1 clock and have it serve up the time to all and sundry.  I was inspired (again) by another person with too much time on their hands. Initially, I copied the same approach with a Raspberry Pi with a GPS receiver attached. By configuring the kernel PPS discipline, it works quite well. The downside to the Pi is that the ethernet interface is connected over an internal USB connection. This means that there is significant receive latency (the Pi has to poll the ethernet interface). I did find a way to reduce the latency with a boot time variable.

Just edit
/boot/cmdline.txt
and add:
smsc95xx.turbo_mode=0
to the end of the line. This causes the ethernet controller to tell the host that it has a packet available as soon as it receives one (rather than waiting a short time to see if it gets another packet).

This seemed rather unsatisfactory, and so I moved on to using an Olimex development board -- the STM32-E407 -- which provides a tightly integrated ethernet MAC and a reasonably high performance CPU (ARM/Cortex-M4).

A little bit of work building a development environment around eclipse-arm, ChibiOS and LWIP got me up and running. If truth be told, the effort to get the development system working was significant. I'm using a cheap JTAG interface to connect to the target board, and eclipse doesn't play nice with it.

The nice thing about the STM32F407 is that it has support for precision time stamping of packets as they arrive and leave. The timer provides nano-second resolution, though the ticks are rather larger at around 12ns (1 / 84MHz).

The first version uses a little GPS board based on the u-Blox 6 receiver with an integrated antenna. With some care, the PPS signal can be captured by one of the CPU timers, and the second overflow of the precise clock can also be captured by the same timer. This gives the difference between the PPS signal and the internal clock second overflow calculated purely in hardware (no interrupt latencies to worry about).

It turned out that the crystal used for generating the system clock (12MHz crystal, divided by 12, then multiplied by 336 and then divided by 2 to get 168MHz) is pretty temperature sensitive.
 
The fairly sharp rise from about 6AM to 9AM is due to the house heating up in the morning. I have the temperature turned down to 60℉ overnight and then bring it up to 68℉ by 9AM. There are also significant excursions due (I suspect) to the GPS receiver changing its mind about the exact time.

The temperature dependance is around 60ppb per ℉. I suspect that this is quite good for a crystal.

The next step was to use a TCXO to provide the clock for the board. This involved some very delicate surgery, soldering a 26MHz oscillator in circuit. This needed a very steady hand (the power/gnd area is on a standard 0.1" grid).


The small component you can see in the middle (attached by a piece of double-sided tape to the board) is the oscillator. Each of the three bare wires (VCC and Gnd) is actually a single strand of power cord.

The performance of this is a lot better:


For the same time interval as above, the TCXO varied by about 40 ppb. This is (only) an order of magnitude better. Also, this chart is very much the same shape as the one above -- they were recorded on the same day with the two boards less than a foot apart.

You may note that I'm using two different clock frequencies -- this is because I am frugal. Digikey had (essentially) a special offer on the 26MHz TCXOs when I ordered them. I had to hack on the code to setup the clocking on the STM32F407 to work out which clock was attached, and then to pick the correct PLL divisors/multipliers.

More to follow.

No comments:

Post a Comment