setup a Raspberry Pi as an Stratum One NTP server.
it is a private project i have made for myself.
i did not keep an eye on network security.
the script will override some existing configurations
(a backup of the changed configuration files will be stored to backup.tar.xz)
USE IT AT YOUR OWN RISK
Please give me a 'Star', if you find that project useful.
╔═══╗ ╔══════╗ ╔══════╗ GPS-Antenna
──╢ s ║ ║RPi as╟RX───────╢GPS- ║ ═╪═
║ w ║ ║NTP- ╟TX───────╢module║ │
║ i ║ ║server║ ╠═══╗ ║ │
╔══════╗ ║ t ╟───eth0╢ ╟GPIO#4───╢PPS║ ╟─────┘
║ RPi ╟──────╢ c ║ ║ ║ ╚═══╩══╝
╚══════╝ ┌──╢ h ╟──┐ ║ ╟GPIO#7╴╴╴╢PPS║ ╟╴╴
│ ╚═══╝ │ ╚══════╝ ╚═══╩══╝
╔══╧══╗ ╔══╧══╗
║ PC1 ║ ║ PC2 ║
╚═════╝ ╚═════╝
(without external NTP servers)
╔═══════╗ ╔══════════════════╗
║ GPS ╫──RX───╫──┐ KERNEL ║
║ ╔═════╣ ║ │ ║ ╔══════════════
║ ║NMEA─╫──TX───╫─[+]─/dev/ttyAMA0─╫────────┬───NMEA──x ║ CHRONY
║ ╠═════╣ ║ ║ │ ║
║ ║ PPS─╫─GPIO4─╫─────/dev/pps0────╫──────┬─)────────────────────────────╫──[+]────PPS0
╚═╩═════╝ ╴╫╴╴┐ ║ │ │ ║ │
╠═════╣ ╴╫╴[+]╴/dev/ttyAMA1╴╫╴╴╴┐ │ │ ║ │
║ ║*PPS╴╫╴GPIO7╴╫╴╴╴╴╴/dev/pps1╴╴╴╴╫╴┬╴)╴╴)╴)╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╫╴╴╴)╴[+]╴PPS1*
╚═╩═════╝ ╚══════════════════╝ ╵ ╵ │ │ ╔══════════════════╗ ║ │ ╵
╵ ╵ │ │ ║ GPSD ║ ║ │ ╵
╵ ╵ │ │ ║ ║ ║ │ ╵
╵ ╵ │ └─╫─GPS0──┬──────────╫─SHM0──╫───)──)──GPS0
╵ ╵ │ ║ │ ┌─╫─SHM1──╫───┴──)──PSM0
╵ ╵ └───╫─PPS0─[+]───────┴─╫─SOCK0─╫──────)──PST0
╵ ╵ ║ ║ ║ ╵
╵ └╴╴╴╴╴╴╫╴GPS1╴╴╴╴╴┬╴╴╴╴╴╴╴╫╴SHM2╴╴╫╴╴╴╴╴╴)╴╴GPS1*
╵ ║ │ ┌╴╫╴SHM3╴╴╫╴╴╴╴╴╴┴╴╴PSM1*
└╴╴╴╴╴╴╴╴╫╴PPS1╴╴╴╴[+]╴╴╴╴┴╴╫╴SOCK1╴╫╴╴╴╴╴╴╴╴╴PST1*
╚══════════════════╝ ╚══════════════
*) optional second PPS device
- Raspberry Pi (with LAN)
- SD card
- working network environment (with a connection to internet for installation only)
- GPS module with PPS output (e.g. Adafruit Ultimate GPS Breakout - 66 channel w/10 Hz updates - Version 3
- optionally a second PPS device
- Raspberry Pi OS Bullseye (2021-10-30 or newer, (link))
assuming,
- your Raspberry Pi is running Raspberry Pi OS Bullseye (2021-10-30 or newer),
- and has a proper connection to the internet via LAN.
- and your SD card is expanded,
- and you connected the GPS module direct to the RPi's RX/TX pins of the GPIO and the GPS PPS pin to the RPi' GPIO #4
- run
bash install-gps-pps.sh
to install necessary packages and setup Kernel PPS, GPSD, and NTP with PPS support. - reboot your RPi with
sudo reboot
- in case you have a RPi3, RPi3+, RPi4 or RPi0w with a built-in Bluetooth adapter, and the script didn't disabled Bluetooth successfully, please run
sudo raspi-conf
and disable the Bluetooth adapter there. otherwise the built-in Bluetooth adapter will block the serial port of the GPIO pins.
done.
gpsd v3.20 available on bullseye repository may have an issue with autobaud feature (finding the correct baud rate of the gps device automatically).
you may have to set the correct baud rate explicitly in the file /etc/default/gpsd
e.g. for baud rate 115200:
GPSD_OPTIONS="--listenany --nowait --badtime --passive --speed 115200"
the chrony configuration files are in the /etc/chrony/statum1
folder.
only files with *.conf
will be included to the configuration.
all other files in that folder will be ignored.
by renaming the files you easily can enable and disable different configuration files.
PPS is a high precise pulse, without a time information.
GPS (NMEA) has date/time information, but with mostly lower precision.
to combine GPS and PPS in chrony, there is a specific requirement, (link)
that GPS data and PPS signal must have a time offset of less than +/-200ms
otherwise the PPS signal is seen as false-ticker and will be rejected by chrony.
depending on your GPS device the offset used in my script can be way too off.
to adjust the offset of GPS0 edit the file /etc/chrony/stratum1/10-refclocks-pps0.conf
refclock SHM 0 refid GPS0 precision 1e-1 offset 0.0 ...
to find the actual offset, you can use gnuplot (already installed by the script)
and run the plot script 99-calibrate-offset-gps0.gnuplot
to visualize the actual histogram of the measured offsets.
# stop gpsd and chrony, delete all log files, restart chrony and gpsd
# wait few seconds to give time to create a log file,
# and start the histogram.
sudo systemctl stop --now gpsd.{service,socket} && sudo systemctl stop --now chrony && \
sudo rm -r /var/log/chrony/*.log && \
sudo systemctl start --now chrony && sudo systemctl start --now gpsd && \
sleep 10 && \
gnuplot ~/RPi-GPS-PPS-StratumOne/gnuplot/99-calibrate-offset-gps0.gnuplot
the histogram will updated every minute. keep it running for at least 30 minutes. the longer you keep it running the better offset value you can find. (but not longer than 24h. every 24h a new log will started from zero)
the x-value of the highest spike in the histogram is the offset value for the GPS0 you can once you got a good offset, you can use your RPi + GPS offline.
-
GPS0 (NMEA), has a mostly a low accuracy.
-
PPS0, has the highest accuracy.
it is passed throught by the kernel to /dev/pps0.
in chrony there is a specific timing offset requirement to PPS, that may cause the PPS0 to be seen as false-ticker by chrony and may be rejected.
(see note2) -
PSM0, is coming from the gpsd service via shared memory and is a combination of PPS0+NMEA, but handled by gpsd service.
it has a similar accuracy than the PPS0 directly. -
PST0, is used by gpsd socket to provide PPS0+NMEA information.
it has the same accuracy as PSM0 because they have the same time source. -
GPS1, PPS1, PSM1, PST1, same as above, but only for the second GPS/PPS device.
to properly restart chrony, use:
sudo systemctl stop --now gpsd.{service,socket} && \
sudo systemctl restart --now chrony && \
sudo systemctl start --now gpsd
this will disconnect all connected gpsd-clients.
to enable a second PPS source (/dev/pps1), please uncomment the prepared lines in the following files:
-
/boot/config.txt
uncomment the line to:
dtoverlay=pps-gpio,gpiopin=7,capture_clear # /dev/pps1
-
/etc/default/gpsd
uncomment the line to:
DEVICES="/dev/ttyAMA0 /dev/pps0 /dev/pps1"
-
rename file
/etc/chrony/stratum1/11-refclocks-pps1.conf.disabled
to
/etc/chrony/stratum1/11-refclocks-pps1.conf
and reboot the system.
be warned: as long the kernel of the RPi uses "soft"-interrupts for the second PPS its accuracy is questionable.
for tests i feeded both gpio-pins with the same signal from the same pps-device (shorted both pins) and noticed a time difference of about 20µs in chrony between /dev/pps0 and /dev/pps1
see (two gpio pins has different delays?)