Files
RPi5-PTP-server/conf.md
2026-09-07 00:27:05 +02:00

6.1 KiB

Install

sudo apt install gpsd gpsd-clients pps-tools chrony linuxptp

GPSD

change /etc/default/gpsd to have

# Default settings for the gpsd init script and the hotplug wrapper.

# Start the gpsd daemon automatically at boot time
START_DAEMON="true"

# Use USB hotplugging to add new USB devices automatically to the daemon
USBAUTO="true"

# Devices gpsd should collect to at boot time.
# They need to be read/writeable, either by user gpsd or the group dialout.
DEVICES="/dev/ttyAMA0 /dev/pps0"

# Other options you want to pass to gpsd
GPSD_OPTIONS="-n"

and then restart gpsd.service

Chrony

The PTP server can also be used to server NTP

edit /etc/chrony.conf to have the following

# This directive specifies the location of the file containing ID/key pairs for
# NTP authentication.
keyfile /etc/chrony/chrony.keys

# This directive specifies the file into which chronyd will store the rate
# information.
driftfile /var/lib/chrony/chrony.drift

# Save NTS keys and cookies.
ntsdumpdir /var/lib/chrony

# Uncomment the following line to turn logging on.
#log tracking measurements statistics

# Log files location.
logdir /var/log/chrony

# Stop bad estimates upsetting machine clock.
maxupdateskew 100.0

# This directive enables kernel synchronisation (every 11 minutes) of the
# real-time clock. Note that it can't be used along with the 'rtcfile' directive.
rtcsync

# Step the system clock instead of slewing it if the adjustment is larger than
# one second, but only in the first three clock updates.
makestep 1 3

# Get TAI-UTC offset and leap seconds from the system tz database.
# This directive must be commented out when using time sources serving
# leap-smeared time.
leapseclist /usr/share/zoneinfo/leap-seconds.list

# Include configuration files found in /etc/chrony/conf.d.
#confdir /etc/chrony/conf.d


# ACL
# I have set it to RFC1918 because I'm using my firewall to explicitly allow access to NTP server
allow 192.168.0.0/16
allow 10.0.0.0/8
allow 172.16.0.0/12

# Explicitly tell clients that we are stratum 1
local stratum 1


# Onboard GPS clock

#refclock SHM 0 refid NMEA offset 0.000 precision 1e-3 poll 3 noselect
refclock SHM 0 refid NMEA offset 0.0 precision 1e-1 poll 3 noselect
refclock PPS /dev/pps0 refid PPS lock NMEA poll 3

then restart chrony.service

PTP

sudo mv /etc/linuxptp/ptp4l.conf /etc/linuxptp/ptp4l.conf.original

Then edit the ptp4l.conf file

sudo vim /etc/linuxptp/ptp4l.conf

[global]
verbose                 1

# Use NIC hardware timestamping / PHC
time_stamping           hardware

# PTP domain
domainNumber            0

# Normal IEEE 1588 over UDP/IPv4
network_transport       UDPv4
delay_mechanism         E2E

# Force this node to serve, not become a client/slave (won't revert to slave).
serverOnly              1

# BMCA priority; lower wins
priority1               128
priority2               128

# Advertise GNSS/PPS-backed grandmaster quality
# clockClass=6 for GNSS reference
# other classes = https://documentation.nokia.com/srlinux/24-10/books/network-synchronization/ieee-1588-ptp.html
clockClass              6
clockAccuracy           0x23
offsetScaledLogVariance 0xFFFF

# timeSource is where time comes from (this value doesn't discipline anything, it is only informational)

# |  Value | Meaning               | Use case                                |
# | -----: | --------------------- | --------------------------------------- |
# | `0x10` | `ATOMIC_CLOCK`        | Direct atomic/rubidium/cesium reference |
# | `0x20` | `GPS`                 | GPS/GNSS-disciplined time source        |
# | `0x30` | `TERRESTRIAL_RADIO`   | Radio time source                       |
# | `0x40` | `PTP`                 | Synced from another external PTP source |
# | `0x50` | `NTP`                 | Synced from NTP                         |
# | `0x60` | `HAND_SET`            | Manually set by human/operator          |
# | `0x90` | `OTHER`               | Other external source                   |
# | `0xA0` | `INTERNAL_OSCILLATOR` | Free-running/local oscillator/default   |

timeSource            0x20

# Useful while testing
summary_interval        1

[eth0]

To test manually run these commands in separate windows. First run the ptp4l command, and then the phc2sys command

sudo ptp4l -i eth0 -f /etc/linuxptp/ptp4l.conf -m
sudo phc2sys -s CLOCK_REALTIME -c /dev/ptp0 -w --step_threshold=0.5 -m

# -s CLOCK_REALTIME   source = Linux system clock, disciplined by chrony/PPS
# -c /dev/ptp0        destination = NIC PTP hardware clock
# -w                  wait for ptp4l and get UTC/PTP offset from it
# -m                  print logs

Verifying

You can use the following commands to see if the PTP server works correctly.

sudo pmc -u -b 0 'GET PORT_DATA_SET'
sudo pmc -u -b 0 'GET GRANDMASTER_SETTINGS_NP'
sudo pmc -u -b 0 'GET TIME_STATUS_NP'

The first command should return MASTER as portState

The second command should return 0x20 as the timeSource and 0x23 as the clockAccuracy. Just like we have set in /etc/linuxptp/ptp4l.conf

The third command returns the gmIdentity which is the MAC address of the NIC

Making the PTP persistent

In order to make the PTP persistent, create a systemd service

sudo vim /etc/systemd/system/ptp4l-gm.service

[Unit]
Description=PTP grandmaster on eth0
After=network-online.target chrony.service
Wants=network-online.target
Requires=chrony.service

[Service]
Type=simple
ExecStart=/usr/sbin/ptp4l -i eth0 -f /etc/linuxptp/ptp4l.conf -m
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

and a second phyc2sys service

sudo vim /etc/systemd/system/phc2sys-gm.service

[Unit]
Description=Sync eth0 PHC from chrony-disciplined system clock
After=ptp4l-gm.service chrony.service
Requires=ptp4l-gm.service chrony.service

[Service]
Type=simple
ExecStart=/usr/sbin/phc2sys -s CLOCK_REALTIME -c /dev/ptp0 -O 37 --step_threshold=0.5 -m
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Enable the services

sudo systemctl daemon-reload
sudo systemctl enable --now ptp4l-gm.service
sudo systemctl enable --now phc2sys-gm.service