Files
RPi5-PTP-server/RPi5_configs
2026-09-07 00:06:27 +02:00
..
2026-09-07 00:06:27 +02:00

Raspberry Pi 5 — GPS/PPS PTP Grandmaster

This directory contains the files used to turn the Raspberry Pi 5 into the PTP grandmaster for the lab.

The intended time chain is:

GT-U7 GNSS
  ├─ NMEA over UART ──> gpsd/chrony
  └─ PPS on GPIO18  ──> chrony
                         │
                         ▼
                  CLOCK_REALTIME (UTC)
                         │
                      phc2sys
                         │
                         ▼
                    eth0 NIC PHC
                         │
                       ptp4l
                         │
                         ▼
                  PTP domain 0

The Pi therefore has two jobs:

  1. discipline the Linux system clock from GNSS/PPS using chrony; and
  2. copy that time into the Ethernet PHC and advertise it as the PTP grandmaster.

Files in this directory

File Install/use as Purpose
config.txt execute the commands in the file once Adds the Pi 5 UART and PPS overlays to /boot/firmware/config.txt
ptp-gm.conf /etc/linuxptp/ptp4l-gm.conf ptp4l grandmaster configuration
ptp4l-gm.service /etc/systemd/system/ptp4l-gm.service Starts the PTP grandmaster
phc2sys-gm.service /etc/systemd/system/phc2sys-gm.service Synchronizes the eth0 PHC from CLOCK_REALTIME
ptp_nic_coalesce.service /etc/systemd/system/ptp_nic_coalesce.service Optional NIC interrupt-coalescing tuning

1. Install the required packages

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

2. Configure the Pi UART and PPS input

The config.txt file in this directory contains shell commands that append the required settings to the real Raspberry Pi boot configuration.

Back up the boot configuration first:

sudo cp /boot/firmware/config.txt /boot/firmware/config.txt.pre-ptp

Then review and execute the commands from config.txt.

The resulting lines in /boot/firmware/config.txt should include:

# GPS UART on GPIO14/GPIO15 for Pi 5
dtoverlay=uart0-pi5
init_uart_baud=9600

# GPS PPS on physical pin 12 / GPIO18
dtoverlay=pps-rp1,pin=18,pull-down,schmitt-trigger

pps-rp1 is a separate Pi 5 overlay. Make sure pps-rp1.dtbo has already been installed in the appropriate overlays directory before rebooting.

Reboot the Pi:

sudo reboot

After reboot, verify that the UART and PPS device exist:

ls -l /dev/ttyAMA0 /dev/pps0
sudo ppstest /dev/pps0

ppstest should report a new PPS assertion once per second.

3. Configure gpsd

Configure /etc/default/gpsd so gpsd opens both the GT-U7 UART and PPS device:

START_DAEMON="true"
USBAUTO="true"
DEVICES="/dev/ttyAMA0 /dev/pps0"
GPSD_OPTIONS="-n"

Restart and verify gpsd:

sudo systemctl restart gpsd
systemctl status gpsd
cgps -s

4. Configure chrony

Chrony disciplines CLOCK_REALTIME from the GNSS receiver. NMEA identifies the UTC second and PPS supplies the precise second boundary.

Add the following refclocks to the chrony configuration used by the Pi:

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

If this Pi should continue serving NTP to the lab, keep the required allow networks, for example:

allow 192.168.0.0/16
allow 10.0.0.0/8
allow 172.16.0.0/12

Also keep:

rtcsync
makestep 1 3
leapseclist /usr/share/zoneinfo/leap-seconds.list

Do not add local stratum 1 for the GNSS/PPS setup. A selected local refclock already makes chronyd serve the correct NTP stratum; local is a separate fallback/local-reference mode.

Restart chrony and verify that PPS becomes the selected source:

sudo systemctl restart chrony
chronyc sources -v
chronyc sourcestats
chronyc tracking

A healthy setup should show PPS selected (#* PPS on common chrony versions).

The NMEA offset 0.0 in the example is only a starting point. If the serial NMEA sentence latency is large, measure it and adjust the NMEA offset later.

5. Verify hardware timestamping on eth0

Before enabling PTP, verify the Pi 5 NIC exposes a PHC and hardware TX/RX timestamping:

ethtool -T eth0

You want hardware TX/RX/raw timestamp support and a non-negative PTP Hardware Clock number.

You can also identify the PHC with:

readlink -f /sys/class/net/eth0/device/ptp/ptp*

6. Install the PTP configuration and services

From this directory, install the files as follows:

sudo install -D -m 0644 ptp-gm.conf /etc/linuxptp/ptp4l-gm.conf
sudo install -D -m 0644 ptp4l-gm.service /etc/systemd/system/ptp4l-gm.service
sudo install -D -m 0644 phc2sys-gm.service /etc/systemd/system/phc2sys-gm.service

The bundled PTP configuration uses:

domainNumber            0
network_transport       UDPv4
delay_mechanism         E2E
serverOnly              1
clockClass              6
clockAccuracy           0xFE
timeSource              0x20
utc_offset              37
twoStepFlag             1

clockAccuracy 0xFE is intentionally conservative until actual accuracy has been measured. The utc_offset value is the PTP/TAI-to-UTC offset advertised to clients; review it if a future leap second changes the TAI-UTC difference.

Reload systemd and enable the services:

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

The direction is important:

chrony:       GNSS/PPS -> CLOCK_REALTIME
phc2sys-gm:  CLOCK_REALTIME -> eth0 PHC
ptp4l-gm:    eth0 PHC -> PTP network

7. Optional NIC coalescing tuning

ptp_nic_coalesce.service applies:

ethtool -C eth0 tx-usecs 4 rx-usecs 4

Treat this as an optional latency/jitter tuning step, not a requirement for PTP to work. First check what the driver supports:

ethtool -c eth0

If the settings are accepted and you want to keep them:

sudo install -D -m 0644 ptp_nic_coalesce.service /etc/systemd/system/ptp_nic_coalesce.service
sudo systemctl daemon-reload
sudo systemctl enable --now ptp_nic_coalesce.service

8. Verification

Service state:

systemctl status chrony
systemctl status ptp4l-gm
systemctl status phc2sys-gm

Live logs:

journalctl -fu ptp4l-gm
journalctl -fu phc2sys-gm

Query the local ptp4l management socket:

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'

Expected results include:

portState            MASTER/SERVER
timeSource           0x20
clockClass           6
clockAccuracy        0xFE
stepsRemoved         0

The grandmasterIdentity reported here is the identity that should remain visible through WOLF-HUNTER and NYATER.

9. Troubleshooting checklist

# PPS exists and pulses
sudo ppstest /dev/pps0

# GPS data is arriving
cgps -s

# chrony actually selected PPS
chronyc sources -v
chronyc tracking

# eth0 supports hardware PTP
ethtool -T eth0

# PTP services are healthy
journalctl -u ptp4l-gm -n 100 --no-pager
journalctl -u phc2sys-gm -n 100 --no-pager

Do not run another service that also tries to discipline the eth0 PHC. Chrony may continue to discipline CLOCK_REALTIME; that is intentional on the grandmaster.