====Time====
{{:tools:gpsd.jpg?200}}
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
PPS line discipline
PPS client using GPIO
See [[https://wiki.kewl.org/dokuwiki/tools:raspbian#kernel|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 [[tools:time#ntp|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
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 [[http://linuxpps.org/doku.php/linuxpps_faq|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...
===Resources===
{{downloads:QUECTEL:L80-brochure.pdf|L80 GPS overview}}
{{downloads:QUECTEL:L80-hardware.pdf|L80 GPS hardware}}
{{downloads:QUECTEL:L80-protocol.pdf|L80 GPS protocol}}
[[https://sourceforge.net/projects/ptpd/|PTPD version 2 on SourceForge]]
[[http://linuxptp.sourceforge.net/|Linux PTP]]