I recently wanted to set up a Stratum 1 time source using a Raspberry Pi (running Arch Linux). I bought the excellent Adafruit Ultimate GPS Hat and dutifully soldered on the connector. So far so good. Unfortunately, from that point on, I found lots of conflicting information. Not, I hasten to add, because the sources were wrong, but rather that evolving kernels and NTP versions rapidly obsolete instructions. Here is my version of requirements, as of October 2016.
Remove console from ttyAMA0. The GPS wants this serial port for talking to the Pi.
root=/dev/mmcblk0p2 rw rootwait console=tty1 selinux=0 plymouth.enable=0 smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 elevator=noop
Add Pulse Per Second modules to the kernel.
/boot/config.txt – Add new line:
Note: gpiopin=4 represents the pin number on the module that PPS is on.
Load the PPS module on boot.
At this point, it’s useful to be able to test PPS is working. There’s an excellent tool for this here. Just run make and then run the tool from whatever directory you extracted it into. If all is well, you’ll see something like this:
root@ticktock:pps-tools# ./ppstest /dev/pps0 trying PPS source "/dev/pps0" found PPS source "/dev/pps0" ok, found 1 source(s), now start fetching data... source 0 - assert 1477494632.000003379, sequence: 1210414 - clear 0.000000000, sequence: 0 source 0 - assert 1477494633.000001527, sequence: 1210415 - clear 0.000000000, sequence: 0
Now install the gpsd package:
pacman -S gpsd
And configure it in /etc/gpsd:
START_DAEMON="true" GPSD_OPTIONS="-n -D 2" DEVICES="/dev/ttyAMA0" #USBAUTO="true"
At this point, everything is there and working. Unfortunately, the packaged version of NTP isn’t configured to use a PPS time source so it’s necessary to download and compile a local version:
./configure --enable-all-clocks --enable-parse-clocks --enable-SHM \ --disable-debugging --without-ntpsnmpd --disable-local-libopts \ --enable-ATOM
I’ve no idea if all these switches need to be enabled and I have no plans to perform a process of elimination. As of ntp-4.2.8, these work for me.
Finally, configure NTP to use the GPS and PPS time sources:
server 127.127.28.0 prefer fudge 127.127.28.0 time1 +0.520 flag1 1 refid GPS stratum 1 server 127.127.22.0 minpoll 4 maxpoll 4 fudge 127.127.22.0 time1 +0.0 flag2 0 refid PPS # Associate to Arch's NTP pool server 0.arch.pool.ntp.org server 1.arch.pool.ntp.org server 2.arch.pool.ntp.org server 3.arch.pool.ntp.org restrict default kod limited nomodify nopeer noquery notrap restrict 127.0.0.1 restrict ::1 # Location of drift file driftfile /var/lib/ntp/ntp.drift
This retains the default NTP pool which provides some sanity that the local clock is accurate. A query of the NTP should produce something like this:
root@ticktock:~# ntpq -pn remote refid st t when poll reach delay offset jitter ============================================================================== *127.127.28.0 .GPS. 1 l 59 64 377 0.000 53.155 21.298 o127.127.22.0 .PPS. 0 l 9 16 377 0.000 0.002 0.004 +184.108.40.206 220.127.116.11 3 u 33 64 377 30.713 -3.681 0.170 +18.104.22.168 22.214.171.124 3 u 42 64 377 20.914 -3.539 0.348 +2001:418:3ff::5 249.224.99.213 2 u 52 64 377 20.722 -3.742 0.090 +126.96.36.199 241.76.5.73 2 u 63 64 377 21.381 -3.664 0.346
The GPS clock is pretty inaccurate, thanks to serial connectivity, but it doesn’t matter as the PPS provides very accurate pulses per second to provide the fine granularity. It’s only important that GPS is accurate to within 500ms to ensure NTP can ascertain which second the pulses relate to. Enjoy!