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.
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.
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.
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.
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.
Show gathering & graphing offset metrics after setup is complete
Thanks for the how-to.
Maybe I'm wrong, but I understand the flag2 differently. Regarding driver 46 documentation
flag2=1 means PPS disabled in my understanding, but you use flag2=0 to disabled it (and flag2=1 to enable).