Basic use with NTP
This page describes how to use SatPulse to build an NTP server using general-purpose hardware, such as a Raspberry Pi. This applies to Linux only. If your machine has a network interface with a PTP Hardware Clock (PHC) that can timestamp a PPS signal, use the approach in Precision timing with a PHC instead, which covers NTP service as well as PTP.
The work is divided between satpulsed and the NTP daemon. satpulsed sends timing samples to the NTP daemon; these are based on the timing of the serial messages from the GPS receiver, so on their own they are imprecise: worse than you would typically get from NTP over a network. The NTP daemon also reads the PPS signal from the GPS receiver, using the kernel PPS subsystem. The PPS samples accurately mark the start of each second but do not identify which second it is. The NTP daemon combines the two sources: the PPS signal determines when a second starts, and the samples from satpulsed determine which second it is. The accuracy you can expect is in the microsecond range, because the time of each PPS edge is measured in software by the kernel.
This page shows the configuration for two NTP daemons: chrony and ntpd-rs. It assumes the baseline setup is complete.
Connect and verify the PPS
When using a Raspberry Pi, the PPS signal is connected to a GPIO pin.
GPS HATs typically wire the PPS signal to pin 12 (GPIO 18).
Configure that pin as a PPS pin by adding the following at the bottom of /boot/firmware/config.txt:
dtoverlay=pps-gpio,gpiopin=18
Reboot after this. To verify that the PPS signal is working, install pps-tools:
sudo apt install pps-tools
Then do:
sudo ppstest /dev/pps0
It should show PPS events once per second:
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1775392263.000000336, sequence: 170178 - clear 0.000000000, sequence: 0
source 0 - assert 1775392264.000000215, sequence: 170179 - clear 0.000000000, sequence: 0
Exit with Ctrl-C.
Configure satpulsed
Edit /etc/satpulse.toml to look like this:
[serial]
device = "/dev/ttyAMA0"
# fix to match your serial device speed
speed = 9600
[gps]
config = true
# Enable HTTP monitoring on port 2000
[[http]]
listen = ":2000"
[ntp]
# Use this for chrony
sock.path = "/var/run/chrony.satpulse.sock"
# Use this for ntpd-rs
# sock.path = "/run/ntpd-rs/satpulse.ttyAMA0.sock"
Uncomment the sock.path line for whichever of chrony or ntpd-rs you use.
The [ntp] table makes satpulsed send timing samples to the NTP daemon using chrony’s SOCK protocol.
With config = true in the [gps] table and an [ntp] table but no [phc] table,
satpulsed will configure the GPS receiver appropriately for this mode of operation
(e.g. enable the time pulse, enable time mode, enable messages reporting UTC time).
You can point a browser at port 2000 and you should get a page showing information from the GPS receiver.
Set up chrony
Make sure chrony is installed. The package is called chrony on both Fedora and Debian.
Create a file /etc/chrony/conf.d/satpulse.conf with the following
(on Fedora, add the lines to /etc/chrony.conf instead):
refclock PPS /dev/pps0 poll 2 lock GPS refid PPS
refclock SOCK /var/run/chrony.satpulse.sock offset 0.1 delay 0.2 refid GPS noselect
The refclock PPS line makes chrony use the kernel PPS API to read PPS samples from /dev/pps0.
These are accurate but lack time-of-day information.
The refclock SOCK line makes chrony read samples generated by satpulsed.
These are inaccurate but include time-of-day.
The offset 0.1 corrects for serial messages coming 0.1 second after the top of the second.
The lock GPS option makes chrony use the samples from satpulsed to complete the PPS samples;
the noselect option tells chrony not to use the satpulsed samples as an independent time source.
Then restart chrony. The service is named chrony on Debian, and chronyd on Fedora.
Verify that it is working:
chronyc sources
The output should include the PPS and GPS reference clocks.
Chrony can also use samples from other NTP servers to complete the PPS samples,
so if you want to check that this is really working,
you should at least temporarily comment out the pool line from /etc/chrony/chrony.conf.
To provide NTP service to other machines, add an allow directive such as this:
allow 192.168.1.0/24
Set up ntpd-rs
Ubuntu has announced plans to adopt ntpd-rs as its default NTP server, replacing chrony, primarily because of memory safety. Since SatPulse is written in Go, the combination of ntpd-rs and SatPulse provides a fully memory-safe timing stack. Like SatPulse, ntpd-rs uses TOML for its configuration files and supports Prometheus, so the combination makes for a pleasantly harmonious configuration and observability experience.
To install, download a deb file from the Releases page. You need at least version 1.7.2. (The version in Raspberry Pi OS will not work.)
Next, you will need to remove your existing NTP daemon (e.g. systemd-timesyncd or chrony):
sudo apt remove systemd-timesyncd chrony
Then install ntpd-rs
sudo dpkg -i ./ntpd-rs_1.7.2-1_arm64.deb
Now you need to set things up so that ntpd-rs can access /dev/pps0.
Create a file /etc/udev/rules.d/99-ntpd-rs-pps.rules containing the line
KERNEL=="pps0", GROUP="ntpd-rs", MODE="0640"
This ensures that when /dev/pps0 is created at boot time it will have a group and permissions
that enables ntpd-rs to access it. To make this take effect without rebooting, do
sudo udevadm control --reload
sudo udevadm trigger /dev/pps0
Now we need to configure ntpd-rs.
Put the following in /etc/ntpd-rs/ntp.toml:
[observability]
log-level = "debug"
observation-path = "/var/run/ntpd-rs/observe"
[[source]]
mode = "pps"
path = "/dev/pps0"
precision = 1e-7
accuracy = 1e-6
[[source]]
mode = "sock"
precision = 1e-2
path = "/run/ntpd-rs/satpulse.ttyAMA0.sock"
accuracy = 0.2
[synchronization]
minimum-agreeing-sources = 1
[[server]]
listen = "0.0.0.0:123"
ntpd-rs distinguishes the accuracy of a source from its precision.
Accuracy means how close measurements are to true time.
Precision means how much measurements vary from each other.
The serial timing measurements from satpulsed are quite precise
but are extremely inaccurate.
Specifying a low accuracy for samples from satpulsed
ensures that ntpd-rs uses the PPS samples as the primary source,
and uses the satpulsed samples just to complete the PPS samples.
But note that if you specify an accuracy of 0.25 or worse,
you need to increase maximum-source-uncertainty from its default of 0.25.
Now you can start ntpd-rs using
sudo systemctl start ntpd-rs
You can verify it’s working by using
ntp-ctl status