Project 1: GPS-based NTP server
Source: Microsecond accurate NTP with a Raspberry Pi and PPS GPS
Info
This page describes setting up a GPS module with a Pi to act as a Stratum1 NTP server. The GPS module must have a 3-5V input, with serial AND PPS outputs (5 pins minimum). Example: Adafruit Ultimate GPS Breakout.
PPS = Pulse Per Second. While the serial data from the GPS module contains the actual time & date information required for the NTP server, the PPS input is required to keep sub-millisecond accuracy. the PPS output puts out EXACTLY 1 pulse per second, +/- a few nanoseconds. The PPS software running on the Pi uses this
Setup:
-
Install packages:
sudo apt install pps-tools gpsd gpsd-clients gpsd-tools chrony
('pps/gpsd' packages are for interperating GPS data, chrony is an NTP server)
-
Add these lines to the end of
/boot/config.txt
# the next 3 lines are for GPS PPS signals dtoverlay=pps-gpio,gpiopin=18 enable_uart=1 init_uart_baud=9600
-
Add this text to the end of
/etc/modules
:pps-gpio
These programs and config changes enable PPS time sync inputs on GPIO pin 18 (real Pin 12), and initializes the serial COM port with a baud rate of 9600.
- disable system handling the COM port:
sudo systemctl mask serial-getty@ttyS0.service
This prevents the system from taking control of the port. Check this command worked after rebooting: /dev/ttyS0
should be owned by root:dialout
and have permissions crw-rw----
.
Wire up the GPS module:
Pinout:
- GPS PPS to RPi pin 12 (GPIO 18)
- GPS VIN to RPi pin 2 or 4
- GPS GND to RPi pin 6
- GPS RX to RPi pin 8
- GPS TX to RPi pin 10
Picture reference (note that all the Pi pins are seqential):
Check GPS functionality
The GPS device should put out either 3.3V or 5V on the antenna connector to power the antenna. With the GPS module powered, The on-board LED will light solid. The LED will start blinking once it has a GPS lock. The module spits data to the serial lines at all times, there is no bi-directional communication!
-
Check that the pps serice is running:
lsmod | grep pps
Should return at least the service
pps_core
. -
Check for PPS pulses (after GPS has a lock):
sudo ppstest /dev/pps0 ### Output: trying PPS source "/dev/pps0" found PPS source "/dev/pps0" ok, found 1 source(s), now start fetching data... source 0 - assert 1655253832.999996389, sequence: 966 - clear 0.000000000, sequence: 0 source 0 - assert 1655253834.000004254, sequence: 967 - clear 0.000000000, sequence: 0 source 0 - assert 1655253835.000001120, sequence: 968 - clear 0.000000000, sequence: 0 source 0 - assert 1655253836.000000985, sequence: 969 - clear 0.000000000, sequence: 0 source 0 - assert 1655253836.999996852, sequence: 970 - clear 0.000000000, sequence: 0 source 0 - assert 1655253838.000001719, sequence: 971 - clear 0.000000000, sequence: 0 source 0 - assert 1655253839.000002586, sequence: 972 - clear 0.000000000, sequence: 0 source 0 - assert 1655253840.000001453, sequence: 973 - clear 0.000000000, sequence: 0 ### ...etc
If there is a timout, then there is likely not a good GPS lock yet.
Set up software:
- Edit
/etc/default/gpsd
:- change
GPSD_OPTIONS=””
toGPSD_OPTIONS=”-n”
- change
START_DAEMON="false"
toSTART_DAEMON="true"
- change
DEVICES=””
toDEVICES=”/dev/ttyS0 /dev/pps0″
- change
- edit
/etc/chrony/chrony.conf
file, add this block of code to the top:### GPS TIME SYNC INFO # 'delay' describes the error of the time source, in seconds. Larger numbers deprioritizes the source. NMEA Source needs a delay else chrony loses sync. # 'offset' adjusts source arrival time forward and backward. Use to sync GPS and PPS signals (time in [brackets] in chrony sources list). # the delay adjusts it forward refclock SHM 0 delay 0.1 offset 0.1165 refid NMEA refclock PPS /dev/pps0 refid PPS # Allow all LAN IP Ranges so NTP server is network-agnostic (can be used on any LAN) allow 10.0.0.0/8 allow 192.168.0.0/16 allow 172.16.0.0/12 ### END GPS TIME SYNC INFO
- Reboot the Pi.
- Check: after rebooting, run the program
gpsmon
, it should display a window similar to this:
This confirms that the software is decoding the GPS info properly.
- Check Chrony is selecting GPS as a time source; run
chronyc sources
More info here under the header 'Time Sources'. TLDR: 'PPS' should have a '*' next to it, and the [bracketed] time in the 'NMEA' row should be less than ~5msec. change the offset in the### Output: MS Name/IP address Stratum Poll Reach LastRx Last sample =============================================================================== #- NMEA 0 4 377 15 +3794us[+3794us] +/- 470us #* PPS 0 4 377 16 +351ns[ +515ns] +/- 3000ns ^- time.cloudflare.com 3 6 377 70 -2009us[-2008us] +/- 16ms ^- smtp.us.naz.com 2 6 377 2 -26ms[ -26ms] +/- 105ms ^- hc-007-ntp1.weber.edu 2 6 377 5 +3131us[+3131us] +/- 72ms ^- dns2.kcweb.net 2 6 377 6 +1296us[+1296us] +/- 88ms
chrony.conf
file to adjust this value, and restart chrony with the commandsudo systemctl restart chrony
. A "Reach" of '377' indicates source was polled sucessfully all 8 of the last 8 tries, ups trustworthiness. Lower numbers mean polls have been missed, less reliable.
Set up other machines to use the Pi as an NTP server (Linux):
- Install
ntp
package on the machine - Edit
/etc/ntp.conf
and addserver [pi.local.ip] true
to the list of servers - start the ntp service (on Arch:
sudo systemctl start ntpd
) - Check the NTP sources with
ntpq -p
:
Check back in about 20 minutes, after which one source should have a '*' next to it to indicate that server is the chosen server. Remove default NTP servers and restart the ntp service if the pi is not selected. Note:remote refid st t when poll reach delay offset jitter ============================================================================== 192.168.1.137 .PPS. 1 u 35 64 1 1.851 +144501 0.001 time.walb.tech 50.205.244.21 3 u 34 64 1 82.802 +144501 0.001 li1187-193.memb 132.163.96.3 2 u 30 64 1 179.522 +144501 0.001 time-dfw.0xt.ca 68.166.61.255 2 u 33 64 1 106.817 +144501 0.001 LAX.CALTICK.NET 17.253.26.253 2 u 32 64 1 118.527 +144501 0.001
true
added after the pi's IP in the config indicates it is more "trustworthy" than other sources, and is more likely to be picked. - If NTP source is registered correctly, and you are ready to use NTP, enable the ntp service (on Arch:
sudo systemctl enable ntpd
)
Set up other machines to use the Pi as an NTP server (Windows):
- Install Dimension 4.
- add the pi as an SNTP source, set the sync time to every 5 minutes.
- In the advanced settings menu, force the program to only sync the selected server to force it to use the pi.