Skip to content

Instantly share code, notes, and snippets.

@wohali
Last active August 6, 2021 08:53
Show Gist options
  • Save wohali/daf3e8214bd9835567727f829309b4ae to your computer and use it in GitHub Desktop.
Save wohali/daf3e8214bd9835567727f829309b4ae to your computer and use it in GitHub Desktop.

How to set up a Raspberry Pi as a Stratum 1 GPS Clock

Hardware setup

Good reference for the HARDWARE PART ONLY: https://ava.upuaut.net/?p=951 if you use this board. Stop when you get to "Enabling PPS/ATOM support in NTPD." and skip down to "Setting stationary mode."

Other hardware guides include https://blog.webernetz.net/ntp-server-via-gps-on-a-raspberry-pi/ and https://robrobinette.com/pi_GPS_PPS_Time_Server.htm but follow the hardware setup section only, including editing your /boot/cmdline.txt, /boot/config.txt and /etc/modules files.

Initial software setup

You need at least Raspbian Buster, which has ntp 4.2.8p12 as of this writing.

As root:

apt install ntp gpsd gpsd-clients
ln -s /dev/ttyAMA0 /dev/gps0

Now, edit /etc/default/gpsd and make these changes:

START_DAEMON="true"
USBAUTO="false"
DEVICES="/dev/gps0 /dev/pps0"
GPSD_OPTIONS="-n"

Get your antenna connected, then run cgps -s. If you don't see 3D FIX in the left column, and reasonable values for the other fields, stop here and debug until you get your hardware working. Also, take note of the number of satellites being used for a fix in the right hand side. You want at least 5; more is better.

Now you need to edit your ntp.conf file. You can use the top part of my final ntp.conf file below, through line 20. Then, read on.

Activating the gpsd_json NTP clock driver, with PPS initially disabled:

Add the following to the end of your ntp.conf, keeping in mind that order matters:

# Other settings up here removed for simplicity.
# Remember: order matters when specifying multiple prefer lines!

server 127.127.46.0 noselect
fudge 127.127.46.0 time1 0.0 time2 0.0 flag2 0 refid GPSD

# You do need to talk to an NTP server or two (or three).
# If you know of good, local, specific servers, add them here:
# server foo.bar.1
# server foo.bar.2
# server foo.bar.3
# server foo.bar.4

# If not, add some pools. These are the Canadian pools;
# check at https://www.ntppool.org/en/use.html for the right
# aliases for your country.
# If you've added specific servers above, you can disable
# pool selection by adding "noselect" to the end of the
# lines below.
pool 0.ca.pool.ntp.org iburst
pool 1.ca.pool.ntp.org iburst
pool 2.ca.pool.ntp.org iburst
pool 3.ca.pool.ntp.org iburst

then: rm /var/log/ntpstats/* && service ntpd stop && service ntpd start. (For some reason, service ntpd restart doesn't seem to work on my Raspbian Buster.)

Now, you need to wait so ntpd can gather some good statistics.

After 24 hours...

First, check the instantaneous performance via the ntpq tool:

# ntpq -p

     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 0.ca.pool.ntp.o .POOL.          16 p    -   64    0    0.000    0.000   0.004
 1.ca.pool.ntp.o .POOL.          16 p    -   64    0    0.000    0.000   0.004
 2.ca.pool.ntp.o .POOL.          16 p    -   64    0    0.000    0.000   0.004
 3.ca.pool.ntp.o .POOL.          16 p    -   64    0    0.000    0.000   0.004
 GPSD_JSON(0)    .GPSD.           0 l   23   64  377    0.000  -95.614   0.850
+ntp1.torix.ca   .PTP0.           1 u  441 1024  377    4.388    0.420   5.196
+ntp2.torix.ca   .PTP0.           1 u 1014 1024  377    4.436    0.361   2.331
*ntp3.torix.ca   .PTP0.           1 u  355 1024  377    5.067    0.397   1.626
-dns4.eis.utoron 206.108.0.132    2 u  361 1024  377    5.236    2.691   2.022
+64.ip-54-39-23. 192.99.2.8       3 u  346 1024  377   11.151    0.200   0.406

Looking good. Our GPS clock is roughly 95 milliseconds behind, which is about average for local radio clocks.

Next, I'll run the ntpd awk script to calculate summary statistics based on the peerstats being logged by the daemon. This is better than using the instantaneous output because it calculates an average over all 24h I've waited, not just on the instantaneous value seen when I get back to my console.

The script is at scripts/stats/peer.awk in the source code, or available from GitHub here: https://github.com/ntp-project/ntp/blob/master-no-authorname/scripts/stats/peer.awk

Run the script as follows (output has been filtered to show only the high- count hits on my system):

# LANG=C awk -f /home/pi/ntp-4.2.8p11/scripts/stats/peer.awk /var/log/ntpstats/peerstats*

       ident     cnt     mean     rms      max     delay     dist     disp
==========================================================================
127.127.28.0     326    9.290    0.969    1.952    0.000    1.088    0.983
206.108.0.133    122   -0.135    0.636    2.070    4.384  940.665   28.696
206.108.0.132    120   -0.275    0.631    1.928    4.365  940.575   25.387
206.108.0.131    128   -0.155    0.610    1.935    4.372  940.509   48.204
128.100.56.135   128    0.718    0.850    1.974    4.915  955.360   76.372
54.39.23.64      126   -0.083    0.624    1.642   11.170  943.160   59.715
127.127.46.0    1788  -94.425    2.416    6.691    0.000  938.296    4.626

So, the average offset for the GPSD connection is 94.425 ms - more than 15ms less than I was getting with the SHM driver described in other writeups on the net (!)

Divide the value by 1000 to get the offset in milliseconds: 0.094425. The offset applied is positive to zero out the negative offset seen by ntpd. I'll add this offset to ntp.conf, and now I'll turn on the PPS clock (via flag2 1) and allow ntpd to select the gpsd_json driver.

So, change the stanza in ntp.conf to read:

server 127.127.46.0
fudge 127.127.46.0 time1 0.0 time2 0.094425 flag2 1 refid GPSD

then: rm /var/log/ntpstats/* && service ntpd stop && service ntpd start to reset our gathered statistics and restart ntpd.

Now, wait a couple of days.

After another 48h:

       ident     cnt     mean     rms      max     delay     dist     disp
==========================================================================
206.108.0.133    342    1.120    2.075    6.733    4.280   17.583    3.488
128.100.56.135   328    0.287    2.374    8.337    4.788   37.959   19.165
206.108.0.132    336    1.246    2.072    6.511    4.276   21.645    3.545
206.108.0.131    362    1.049    2.167    6.650    4.307   21.218    3.648
149.56.27.12     268    0.917    1.926    5.623   10.927   25.184    4.848
127.127.46.0    1478   -0.053    1.478   11.030    0.000  938.236    3.196

This is very good performance! On average my GPS clock is now just 53 microseconds off.

Dividing by 1000, I'll apply a positive 0.000053 offset to the PPS signal via the time1 setting. The new ntp.conf stanza looks like:

server 127.127.46.0 noselect
fudge 127.127.46.0 time1 0.000053 time2 0.094425 flag2 1 refid GPSD

then: rm /var/log/ntpstats/* && service ntpd stop && service ntpd start again.

TODO

Show gathering & graphing offset metrics after setup is complete

# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help
driftfile /var/lib/ntp/ntp.drift
statsdir /var/log/ntpstats/
statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats peers type day enable
filegen clockstats file clockstats type day enable
# By default, exchange time with everybody, but don't allow configuration.
restrict -4 default kod notrap nomodify nopeer limited
restrict -6 default kod notrap nomodify nopeer limited
# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict -6 ::1
# Needed for adding pool entries
restrict source notrap nomodify noquery
# And limit to your local network.
restrict 192.168.1.0 mask 255.255.255.0
# Setting up a Raspberry Pi with a GPS hat
#
# For more reading:
# https://wiki.archlinux.org/index.php/Network_Time_Protocol_daemon
# https://www.eecis.udel.edu/~mills/ntp/html/drivers/driver46.html
# http://support.ntp.org/bin/view/Support/AdjustingRadioclocks
# https://www.eecis.udel.edu/~mills/ntp/html/decode.html#peer
# https://www.eecis.udel.edu/~mills/ntp/html/cluster.html
#
# No longer recommended, but good background info for hardware
# configuration *only*:
# https://robrobinette.com/pi_GPS_PPS_Time_Server.htm
# https://blog.webernetz.net/ntp-server-via-gps-on-a-raspberry-pi/
#=========================================================
# GPSD native ntpd driver
#=========================================================
# This driver exists from at least ntp version 4.2.8
#
# the .0 means the driver will ask gpsd to access /dev/gps0
# so, # ln -s /dev/ttyAMA0 /dev/gps0
server 127.127.46.0 prefer
fudge 127.127.46.0 time1 0.000053 time2 0.094425 flag2 1 refid GPSD
# You do need to talk to an NTP server or two (or three).
server ntp1.torix.ca
server ntp2.torix.ca
server ntp3.torix.ca
server tick.utoronto.ca
pool 0.ca.pool.ntp.org iburst
pool 1.ca.pool.ntp.org iburst
pool 2.ca.pool.ntp.org iburst
pool 3.ca.pool.ntp.org iburst
@mibere
Copy link

mibere commented Jul 9, 2020

Thanks for the how-to.

Maybe I'm wrong, but I understand the flag2 differently. Regarding driver 46 documentation

flag2 0 | 1 [Primary Unit] When set, disables the processing of incoming PPS records

flag2=1 means PPS disabled in my understanding, but you use flag2=0 to disabled it (and flag2=1 to enable).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment