Time
This time service is comprised built on a RPi with a LoRa board with a GPS module with PPS. An additional USB GPS dongle is also evaluated but is not a requirement and may even confuse the GPS daemon.
Linux
Minimal hardware configuration is necessary to enable PPS on a GPIO, enable SPI for the LoRa controller (if needed) and use a easily remembered persistent name for the dongle.
More complex kernel configuration may also be performed.
Configuration
First install some tools.
apt install cpufrequtils update-rc.d cpufrequtils disable update-rc.d loadcpufreq disable
config.txt
For a headless display use a minimal amount of RAM for video and enable the 1PPS output from the module on GPIO18. SPI is enabled if the LoRa module is required. On the Pi3, we switch the miniuart from the GPIO header to the BT module which we do not use.
gpu_mem=16 dtoverlay=pps-gpio,gpiopin=18 dtparam=spi=on dtoverlay=pi3-miniuart-bt
rc.local
During start-up set the CPU to use a fixed clock rate.
/usr/bin/cpufreq-set -g userspace /usr/bin/cpufreq-set -f 600000
After configuration, reboot the Pi.
UDEV
Add this to local rules.
# U-Blox AG [u-blox 7] KERNEL=="ttyACM*",\ ATTRS{idVendor}=="1546",\ ATTRS{idProduct}=="01a7",\ GROUP="dialout",\ MODE:="0666",\ RUN+="/bin/ln -sf %k /dev/ttyGPS"
New rules can be registered using udevadm.
udevadm control --reload-rules udevadm trigger
Kernel
Building a kernel with the following options enables kernel 1PPS time synchronisation.
General setup ---> Timers subsystem ---> Timer tick handling ---> (X) Periodic timer ticks ( ) Old Idle dynticks config (X) High resolution Timer Support Device Drivers ---> PPS support ---> [*] PPS kernel consumer support <M> PPS line discipline <M> PPS client using GPIO
See here for more information about building a RPi kernel.
The difference to the stock kernel is this:
diff .config.orig .config 85,87c85,86 < CONFIG_NO_HZ_COMMON=y < # CONFIG_HZ_PERIODIC is not set < CONFIG_NO_HZ_IDLE=y --- > CONFIG_HZ_PERIODIC=y > # CONFIG_NO_HZ_IDLE is not set 89c88 < CONFIG_NO_HZ=y --- > # CONFIG_NO_HZ is not set 2978a2978 > CONFIG_NTP_PPS=y
When running a kernel with the above options, the following is observed
ntpq -c kerninfo && ntptime associd=0 status=0115 leap_none, sync_pps, 1 event, clock_sync, pll offset: 0 pll frequency: 3.55501 maximum error: 0.505 estimated error: 1e-06 kernel status: pll ppsfreq ppstime ppssignal nano pll time constant: 4 precision: 1e-06 frequency tolerance: 500 pps frequency: 3.55486 pps stability: 0.0237427 pps jitter: 0.001 calibration interval 256 calibration cycles: 380 jitter exceeded: 68 stability exceeded: 0 calibration errors: 1 0:00.03s ntp_gettime() returns code 0 (OK) time e68bc700.3e61f18c Wed, Jul 27 2022 15:15:28.243, (.243682974), maximum error 505000 us, estimated error 1 us, TAI offset 37 ntp_adjtime() returns code 0 (OK) modes 0x0 (), offset 0.000 us, frequency 3.555 ppm, interval 256 s, maximum error 505000 us, estimated error 1 us, status 0x2107 (PLL,PPSFREQ,PPSTIME,PPSSIGNAL,NANO), time constant 4, precision 0.001 us, tolerance 500 ppm, pps frequency 3.555 ppm, stability 0.024 ppm, jitter 1.292 us, intervals 380, jitter exceeded 68, stability exceeded 0, errors 1.
NB ntpq and ntptime are part of ntp.
PPS
PPS is a hardware time signal delivered once per second from the GPS module. On the RPi this is connected to a GPIO, generally GPIO18, which was configured above.
When booting the system the following message will be found.
pps_core: LinuxPPS API ver. 1 registered pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it> pps pps0: new PPS source pps@12.-1 pps pps0: Registered IRQ 199 as PPS source pps_ldisc: PPS line discipline registered pps pps0: bound kernel consumer: edge=0x1
Test
Install the tools
apt install pps-tools
Begin teting
ppstest /dev/pps0 trying PPS source "/dev/pps0" found PPS source "/dev/pps0" ok, found 1 source(s), now start fetching data... source 0 - assert 1658756336.304112829, sequence: 2941 - clear 0.000000000, sequence: 0 source 0 - assert 1658756337.304112557, sequence: 2942 - clear 0.000000000, sequence: 0 source 0 - assert 1658756338.304110046, sequence: 2943 - clear 0.000000000, sequence: 0 source 0 - assert 1658756339.304109722, sequence: 2944 - clear 0.000000000, sequence: 0 source 0 - assert 1658756340.304110908, sequence: 2945 - clear 0.000000000, sequence: 0 source 0 - assert 1658756341.304108969, sequence: 2946 - clear 0.000000000, sequence: 0 source 0 - assert 1658756342.304108645, sequence: 2947 - clear 0.000000000, sequence: 0 ^C
Interrupts
egrep '(^ CPU|pps@)' /proc/interrupts CPU0 CPU1 CPU2 CPU3 199: 88888 0 0 0 pinctrl-bcm2835 18 Edge pps@12.-1
Issues
When running NTPD an error is reported regarding PPS.
refclock_nmea: time_pps_kcbind failed: Operation not supported
This error is due to LinuxPPS not supporting the bind feature, the FAQ for more details.
GPS
Install clients and server.
sudo apt-get install gpsd gpsd-clients
Disable services for now
sysv
update-rc.d gpsd disable
systemd
systemd hijacks the GPSD socket (like inetd) so you will need to try a few things to resolve this.
systemctl disable gpsd systemctl mask gpsd systemctl disable gpsd.sock systemctl mask gpsd.sock reboot
If you need ppscheck for some reason, compile it like this (not needed here).
sudo gcc -o /usr/local/bin/ppscheck /usr/share/doc/gpsd-clients/examples/ppscheck.c
GPS server
Initialise the serial port to 115200 baud
Refer to L80 GPS Protocol Specification #3.16. Packet Type: 251 PMTK_SET_NMEA_BAUDRATE
echo '$PMTK251,115200*1F\r\n' > /dev/ttyAMA0 stty -F /dev/ttyAMA0 115200
Run the daemon like this from runit or equivalent.
/usr/sbin/gpsd -G -n -N /dev/ttyAMA0 /dev/pps0 /dev/ttyGPS
Kernel logging will produce the following from the PPS module.
pps pps1: new PPS source ttyAMA0 pps pps1: source "/dev/ttyAMA0" added pps pps2: new PPS source acm0 pps pps2: source "/dev/ttyACM0" added
GPS monitor
GPSMON can view the running state of the GPS modules handled by GPSD. To pause the display press CTRL-S and CTRL-Q to continue.
View the device attached to the LoRa board
gpsmon localhost:gpsd:/dev/ttyAMA0 /dev/ttyAMA0:/dev/ttyAMA0 NMEA0183> ┌──────────────────────────────────────────────────────────────────────────────┐ │Time: 2022-07-24T14:56:23.000Z Lat: 00 00' 00.000" N Lon: 0 00' 00.000" E │ └───────────────────────────────── Cooked TPV ─────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ GPZDA GPRMC GPGGA GPGSA GPTXT GPGSV │ └───────────────────────────────── Sentences ──────────────────────────────────┘ ┌──────────────────┐┌────────────────────────────┐┌────────────────────────────┐ │Ch PRN Az El S/N ││Time: 145623.000 ││Time: 145623.000 │ │ 0 4 155 65 21 ││Latitude: 0000.0000 N ││Latitude: 0000.0000 │ │ 1 3 71 63 23 ││Longitude: 00000.0000 E ││Longitude: 00000.0000 │ │ 2 19 272 45 40 ││Speed: 0.00 ││Altitude: 8.7 │ │ 3 17 236 42 44 ││Course: 71.70 ││Quality: 1 Sats: 10 │ │ 4 9 200 37 29 ││Status: A FAA: A ││HDOP: 0.84 │ │ 5 1 134 33 16 ││MagVar: ││Geoid: 47.0 │ │ 6 6 304 32 22 │└─────────── RMC ────────────┘└─────────── GGA ────────────┘ │ 7 120 199 29 0 │┌────────────────────────────┐┌────────────────────────────┐ │ 8 31 53 21 18 ││Mode: A3 Sats: 4 3 19 17 9 ││UTC: RMS: │ │ 9 21 137 11 16 ││DOP: H=0.84 V=0.80 P=1.15 ││MAJ: MIN: │ │10 12 331 6 25 ││TOFF: 0.212566738 ││ORI: LAT: │ │11 22 40 6 0 ││PPS: ││LON: ALT: │ └────── GSV ───────┘└──────── GSA + PPS ─────────┘└─────────── GST ────────────┘
View the USB dongle.
gpsmon localhost:gpsd:/dev/ttyGPS /dev/ttyGPS:/dev/ttyGPS u-blox> ┌──────────────────────────────────────────────────────────────────────────────┐ │Time: 2022-07-24T14:55:38.000Z Lat: 00 00' 00.000" N Lon: 0 00' 00.000" E │ └───────────────────────────────── Cooked TPV ─────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ GPRMC GPVTG GPGGA GPGSA GPGSV GPGLL │ └───────────────────────────────── Sentences ──────────────────────────────────┘ ┌──────────────────┐┌────────────────────────────┐┌────────────────────────────┐ │Ch PRN Az El S/N ││Time: 145538.00 ││Time: 145538.00 │ │ 0 1 134 33 0 ││Latitude: 0000.00000 N ││Latitude: 0000.00000 │ │ 1 3 71 63 20 ││Longitude: 00000.00000 E ││Longitude: 00000.00000 │ │ 2 4 155 65 0 ││Speed: 0.440 ││Altitude: -17.9 │ │ 3 6 304 32 34 ││Course: ││Quality: 1 Sats: 05 │ │ 4 9 200 37 36 ││Status: A FAA: A ││HDOP: 1.97 │ │ 5 12 331 6 0 ││MagVar: ││Geoid: 45.5 │ │ 6 17 236 42 35 │└─────────── RMC ────────────┘└─────────── GGA ────────────┘ │ 7 19 273 45 38 │┌────────────────────────────┐┌────────────────────────────┐ │ 8 21 136 11 0 ││Mode: A3 Sats: 3 6 9 17 19 ││UTC: RMS: │ │ 9 22 40 6 0 ││DOP: H=1.97 V=5.85 P=6.17 ││MAJ: MIN: │ │10 25 7 1 0 ││TOFF: 0.064302730 ││ORI: LAT: │ │11 31 53 21 25 ││PPS: ││LON: ALT: │ └────── GSV ───────┘└──────── GSA + PPS ─────────┘└─────────── GST ────────────┘
Inspect the PPS dialog.
gpsmon localhost:gpsd:/dev/pps0 tcp://localhost:gpsd:/dev/pps0JSON slave driver> ------------------- PPS offset: 0.000006771 ------ ------------------- PPS offset: 0.000006804 ------ ------------------- PPS offset: 0.000007567 ------ ------------------- PPS offset: 0.000007550 ------ ------------------- PPS offset: 0.000007119 ------ ------------------- PPS offset: 0.000007523 ------ ------------------- PPS offset: 0.000006574 ------ ------------------- PPS offset: 0.000007086 ------ ------------------- PPS offset: 0.000006922 ------ ------------------- PPS offset: 0.000006395 ------ ------------------- PPS offset: 0.000006911 ------ ------------------- PPS offset: 0.000006647 ------ ------------------- PPS offset: 0.000007427 ------ ------------------- PPS offset: 0.000006958 ------ ------------------- PPS offset: 0.000005552 ------ ------------------- PPS offset: 0.000005591 ------ ------------------- PPS offset: 0.000006516 ------ ------------------- PPS offset: 0.000006557 ------ ------------------- PPS offset: 0.000006965 ------ ------------------- PPS offset: 0.000006905 ------ ------------------- PPS offset: 0.000007264 ------ ------------------- PPS offset: 0.000005958 ------ ------------------- PPS offset: 0.000006163 ------
GPS test clients CGPS & XGPS
cgps is the terminal client and xgps the X11 client. With XGPS we can see relative satellite positions in the sky.
cgps ┌───────────────────────────────────────────┐┌─────────────────────────────────┐ │ Time: 2022-07-24T15:22:54.000Z ││PRN: Elev: Azim: SNR: Used: │ │ Latitude: 0.000000 N ││ 3 52 079 21 Y │ │ Longitude: 0.000000 E ││ 6 43 303 37 Y │ │ Altitude: 9.5 m ││ 9 50 201 37 Y │ │ Speed: 0.0 kph ││ 17 32 226 37 Y │ │ Heading: 74.9 deg (true) ││ │ │ Climb: n/a ││ │ │ Status: 3D FIX (17 secs) ││ │ │ Longitude Err: +/- 11 m ││ │ │ Latitude Err: +/- 15 m ││ │ │ Altitude Err: +/- 18 m ││ │ │ Course Err: n/a ││ │ │ Speed Err: n/a ││ │ │ Time offset: 0.356 ││ │ │ Grid Square: JO01bl ││ │ └───────────────────────────────────────────┘└─────────────────────────────────┘
Shared memory (SHM)
When running the GPS daemon shared memory segments as follows are created.
ipcs -m ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x4e545030 0 root 600 80 2 0x4e545031 1 root 600 80 1 0x4e545032 2 root 666 80 2 0x4e545033 3 root 666 80 1 0x4e545034 4 root 666 80 1 0x4e545035 5 root 666 80 1 0x4e545036 6 root 666 80 1 0x4e545037 7 root 666 80 1 0x47505344 8 root 666 8928 1 cat /proc/sysvipc/shm key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap 1314148400 0 600 80 1372 6549 2 0 0 0 0 1658675058 1658675004 1626289289 4096 0 1314148401 1 600 80 1372 6549 1 0 0 0 0 1658675058 1658675004 1626289289 4096 0 1314148402 2 666 80 1372 8881 2 0 0 0 0 1658677299 1658677302 1626289289 4096 0 1314148403 3 666 80 1372 8881 1 0 0 0 0 1658677299 1658677302 1626289289 4096 0 1314148404 4 666 80 1372 8881 1 0 0 0 0 1658677299 1658677302 1626289289 4096 0 1314148405 5 666 80 1372 8881 1 0 0 0 0 1658677299 1658677302 1626289289 4096 0 1314148406 6 666 80 1372 8881 1 0 0 0 0 1658677299 1658677302 1626289289 4096 0 1314148407 7 666 80 1372 8881 1 0 0 0 0 1658677299 1658677302 1626289289 4096 0 1196446532 8 666 8928 1372 6549 1 0 0 0 0 1658675058 1658675004 1626289289 12288 0
Shared memory monitor for NTP
Inspect shared memory for GPS daemon updates.
ntpshmmon -n 10 ntpshmmon version 1 # Name Seen@ Clock Real L Prec sample NTP2 1658845391.052754250 1658845390.999997337 1658845391.000000000 0 -20 sample NTP3 1658845391.053073679 1658845390.064010972 1658845390.000000000 0 -1 sample NTP0 1658845391.195810090 1658845391.195208369 1658845391.000000000 0 -1 sample NTP3 1658845391.553218802 1658845391.064837160 1658845391.000000000 0 -1 sample NTP2 1658845392.000572481 1658845391.999998990 1658845392.000000000 0 -20 sample NTP3 1658845392.054219398 1658845391.064837160 1658845391.000000000 0 -1 sample NTP0 1658845392.197965917 1658845392.197500030 1658845392.000000000 0 -1 sample NTP3 1658845392.555309369 1658845392.063063232 1658845392.000000000 0 -1 sample NTP2 1658845393.000207934 1658845392.999998194 1658845393.000000000 0 -20 sample NTP3 1658845393.056027671 1658845392.063063232 1658845392.000000000 0 -1
NTP
NTP daemon is used to keep the time and provide a network service. In this example it will sync to internet time services and the local PPS clock pulse.
Install
apt install ntp ntpdate
/etc/init.d/ntp stop update-rc.d ntp disable
Bookworm
/etc/init.d/ntpsec stop update-rc.d ntpsec disable
systemctl stop ntpd systemctl disable ntpd systemctl mask ntpd
Master config
leapfile /usr/share/zoneinfo/leap-seconds.list statsdir /var/log/ntpstats/ statistics loopstats peerstats clockstats rawstats filegen loopstats file loopstats type day enable filegen peerstats file peerstats type day enable filegen clockstats file clockstats type day enable filegen rawstats file rawstats type day enable server ntp0.linx.net prefer server ntp1.linx.net server ntp2.linx.net pool uk.pool.ntp.org iburst # ACL; /usr/share/doc/ntp-doc/html/accopt.html restrict -4 default kod notrap nomodify nopeer noquery limited restrict -6 default kod notrap nomodify nopeer noquery limited restrict 127.0.0.1 restrict ::1 restrict source notrap nomodify noquery #restrict 192.168.0.0 mask 255.255.255.0 notrust broadcast 192.168.0.255 disable auth # https://doc.ntp.org/documentation/4.2.8-series/clockopt/ # https://doc.ntp.org/documentation/4.2.8-series/refclock/ # https://doc.ntp.org/documentation/drivers/driver22/ # PPS Clock Discipline server 127.127.22.0 minpoll 3 maxpoll 3 fudge 127.127.22.0 flag2 0 flag3 1 flag4 1 # https://doc.ntp.org/documentation/drivers/driver28/ # https://gpsd.gitlab.io/gpsd/gpsd-time-service-howto.html # Shared Memory Driver # GPS Serial data reference (NTP0) server 127.127.28.0 minpoll 3 maxpoll 3 fudge 127.127.28.0 flag1 1 time1 +0.130 refid GPS # GPS PPS reference (NTP1) server 127.127.28.1 fudge 127.127.28.1 flag1 1 refid PPS # Local PTP reference (NTP2) server 127.127.28.2 fudge 127.127.28.2 flag1 1 refid PTP
Slave config
leapfile /usr/share/zoneinfo/leap-seconds.list statsdir /var/log/ntpstats/ statistics loopstats peerstats clockstats rawstats filegen loopstats file loopstats type day enable filegen peerstats file peerstats type day enable filegen clockstats file clockstats type day enable filegen rawstats file rawstats type day enable #server ntp.example.com broadcastclient disable auth
Run it
Run it something like this
/usr/sbin/ntpd -n -p /var/run/ntp/ntpd.pid -c /etc/ntp.conf -g -N -u ntp:ntp
Test
This test was performed on a Pi 3 with the CPU clock fixed at 1GHz and only using the L80 GPS and not the U-blox.
ntpq -c rv -pn associd=0 status=011d leap_none, sync_pps, 1 event, kern, version="ntpd 4.2.8p15@1.3728-o Wed Sep 23 11:46:38 UTC 2020 (1)", processor="armv7l", system="Linux/5.15.56-v7-KEWL+", leap=00, stratum=1, precision=-20, rootdelay=0.000, rootdisp=1.015, refid=PPS, reftime=e68e93a8.0e87acf6 Fri, Jul 29 2022 18:13:12.056, clock=e68e93aa.080ea225 Fri, Jul 29 2022 18:13:14.031, peer=53321, tc=3, mintc=3, offset=+0.000603, frequency=-0.143, sys_jitter=0.000954, clk_jitter=0.001, clk_wander=0.001, tai=37, leapsec=201701010000, expire=202212280000 remote refid st t when poll reach delay offset jitter ============================================================================== uk.pool.ntp.org .POOL. 16 p - 64 0 0.000 +0.000 0.001 o127.127.22.0 .PPS. 0 l 2 8 377 0.000 +0.001 0.001 -127.127.28.0 .GPS. 0 l 8 8 377 0.000 -12.042 9.783 +127.127.28.1 .PPS. 0 l 24 64 377 0.000 +0.000 0.001 +127.127.28.2 .PTP. 0 l 24 64 377 0.000 +0.000 0.001 *2a01:40:5459:7: .PPS. 1 u 53 64 377 12.519 +2.788 0.651 +2a01:40:5459:7: .PPS. 1 u 56 64 377 12.567 +2.797 0.845 -2a01:40:5459:8: .GPS. 1 u 21 64 377 13.571 +2.954 0.488 -185.103.119.60 202.70.69.81 2 u 56 64 377 12.191 +2.466 2.297 -188.114.116.1 202.70.69.81 2 u 7 64 377 13.345 +2.479 0.746
The jitter seems very high on this device. I have no advice about that and the only option is to find other sample devices to test and prefer.
The first character of each peer line above is called the ntp tally code.
Code Message T Description 0 sel_reject discarded as not valid (TEST10-TEST13) 1 sel_falsetick x discarded by intersection algorithm 2 sel_excess . discarded by table overflow (not used) 3 sel_outlier - discarded by the cluster algorithm 4 sel_candidate + included by the combine algorithm 5 sel_backup # backup (more than tos maxclock sources) 6 sel_sys.peer * system peer 7 sel_pps.peer o PPS peer (when the prefer peer is valid)
Debug
apt install tcpdump && rehash tcpdump -ni wlan0 port 123 and udp
PTP
Precision time protocol.
This can be used to sync clocks on the local network.
PTPD
PTPD verison 2.
Install
apt install ptpd /etc/init.d/ptpd stop update-rc.d ptpd disable
Run server
ptpd -V -n -M -i eth0
Run client
ptpd -C -s -i eth0
Run master/slave with config file
Master or slave may be run with a configuration file.
mkdir -p /var/run/ptpd && ptpd -c /etc/ptpd.conf
Example slave config.
ptpengine:interface=eth0 ptpengine:ip_mode=multicast ptpengine:use_libpcap=n ptpengine:domain=0 ptpengine:preset=slaveonly global:lock_file=/var/run/ptpd/pid global:foreground=Y global:verbose_foreground=N global:log_status=Y global:status_file=/var/run/ptpd/status global:log_statistics=Y global:statistics_file=/var/run/ptpd/statistics global:statistics_log_interval=10 global:statistics_file_max_size=1024 global:statistics_file_max_files=5 global:statistics_file_truncate=Y
Issue
PTPD on Raspberry PI OS (debian) can freeze after a while and stop working.
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 5362 root 20 0 6912 2828 2400 R 100.0 0.1 937:21.95 ptpd
Using strace we see an infinite loop like this:
strace -p 5362 strace: Process 5362 attached --- SIGALRM {si_signo=SIGALRM, si_code=SI_TIMER, si_timerid=0x1, si_overrun=5, si_value={int=33321672, ptr=0x1fc72c8}} --- rt_sigreturn({mask=[]}) = 1 ...
The version matches the version available on SF.net
ptpd -v ptpd2 version 2.3.1
Linux PTP
This service requires driver support of transmit and receive of timestamps. Not all drivers support this.
Check with ethtool -T
Install
apt install linuxptp systemctl stop timemaster systemctl disable timemaster systemctl mask timemaster
More later…