Awesome! We have wired a GPS with its PPS to the motherboard, and now what?
First, we need a few missing components: "gpsd" will handle the GPS, while "chrony" will take care of the NTP.
# Installing required packages apt install gpsd gpsd-clients pps-tools chrony # Making sure PPS kernel module is loaded modprobe pps_ldisc # Attaching PPS device on serial port ldattach PPS /dev/ttyS1 # Allow Chrony sockets in AppArmor apt install apparmor-utils aa-complain /usr/sbin/chronyd
By now, the PPS LED on the GPS module is ticking meaning we should have a GPS fix. Let's test the PPS output to see if it is working. It is indeed ticking as expected:
root@rsfo-ntp01:~# 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 1682168016.866888991, sequence: 2171 - clear 1682168015.966901011, sequence: 2952 source 0 - assert 1682168016.866888991, sequence: 2171 - clear 1682168016.966901919, sequence: 2953 source 0 - assert 1682168017.866881448, sequence: 2172 - clear 1682168016.966901919, sequence: 2953 source 0 - assert 1682168017.866881448, sequence: 2172 - clear 1682168017.966892630, sequence: 2954 source 0 - assert 1682168018.866880401, sequence: 2173 - clear 1682168017.966892630, sequence: 2954 source 0 - assert 1682168018.866880401, sequence: 2173 - clear 1682168018.966878452, sequence: 2955 source 0 - assert 1682168019.866878585, sequence: 2174 - clear 1682168018.966878452, sequence: 2955 source 0 - assert 1682168019.866878585, sequence: 2174 - clear 1682168019.966890814, sequence: 2956 source 0 - assert 1682168020.866877816, sequence: 2175 - clear 1682168019.966890814, sequence: 2956 source 0 - assert 1682168020.866877816, sequence: 2175 - clear 1682168020.966887531, sequence: 2957
Now, let's configure the GPSD daemon. This daemon will talk to the GPS module while allowing multiple processes to access the GPS information. This would not be possible if we were using the serial port directly from the NTP server. Edit the file "/etc/default/gpsd":
# GPS is conected to ttyS1, the 2nd hardare serial port DEVICES="/dev/ttyS1" # Options we want to pass to gpsd # -s 9600 = baudrate, -G = listen to any address, -n = don't wait for clients to poll GPS GPSD_OPTIONS="-s 9600 -G -n" # We don't care about USB modules, let's ignore them! USBAUTO="false"
We also need to configure the Chrony daemon by editing the file "/etc/chrony/chrony.conf". The "makestep" should not be required, but since the Meru has a bad RTC/BIOS battery the time would keep reverting to 2002... Chrony doesn't like that and doesn't update the time with such an offset in timing. With this command, Chrony will force updates on the first 10 syncs.
# Allow connections from remote allow # Reference clocks, PPS locked on GPS refclock SOCK /run/chrony.ttyS1.sock refid GPS precision 1e-1 refclock PPS /dev/pps0 lock GPS refid PPS precision 1e-9 poll 2 # Step the clock on first 10 updates if ofset is larger than one second makestep 1 10
I had trouble starting Chrony on boot because the PPS device (/dev/pps0) would not be initialized yet. So I added an "ExecStartPre" command in Chrony's daemon service file located at "/lib/systemd/system/chrony.service":
[Unit] Description=chrony, an NTP client/server Documentation=man:chronyd(8) man:chronyc(1) man:chrony.conf(5) Conflicts=openntpd.service ntp.service ntpsec.service Wants=time-sync.target Before=time-sync.target After=network.target ConditionCapability=CAP_SYS_TIME [Service] Type=forking PIDFile=/run/chrony/chronyd.pid EnvironmentFile=-/etc/default/chrony ExecStartPre=bash -c '/usr/sbin/ldattach PPS /dev/ttyS1 && /bin/sleep 10' ExecStart=/usr/sbin/chronyd $DAEMON_OPTS PrivateTmp=yes ProtectHome=yes ProtectSystem=full ProtectControlGroups=yes ProtectKernelModules=yes ProtectKernelTunables=yes [Install] Alias=chronyd.service WantedBy=multi-user.target
Make sure the GPSD service is set to start after Chrony, edit the file "/lib/systemd/system/gpsd.service" and look for the line "After=chronyd.service":
[Unit] Description=GPS (Global Positioning System) Daemon Requires=gpsd.socket # Needed with chrony SOCK refclock After=chronyd.service [Service] Type=forking EnvironmentFile=-/etc/default/gpsd ExecStart=/usr/sbin/gpsd $GPSD_OPTIONS $OPTIONS $DEVICES [Install] WantedBy=multi-user.target Also=gpsd.socket
Reboot the server with the "reboot" command to make sure everything starts correctly on boot... Then let's have a look at the GPS output with the "gpsmon" command. U-Blox is detected, we have a 3D fix, TDOP is low, that's a good start.
/dev/ttyS1 u-blox> lqqqqqqqqqqqqqqqqqqqqqqqqqqklqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk xCh PRN Az El S/N Flag U xxECEF Pos: +45xxxxx.61m +3xxxxx.98m +43xxxxx.21m x x 0 2 52 60 10 040d Y xxECEF Vel: -0.01m/s -0.03m/s -0.02m/s x x 1 7 331 4 0 0104 xx x x 2 8 280 13 25 040d Y xxLTP Pos: 43.xxxxxxxxxf 4.xxxxxxxxf 106.00m x x 3 10 154 24 30 050d Y xxLTP Vel: 0.00m/s 0.0f 0.00m/s x x 4 16 296 69 23 040d Y xx x x 5 18 53 56 25 040d Y xxTime: 6 13:05:47.00 x x 6 22 0 -91 0 0110 xxTime GPS: 2258+565547.000 Day: 6 x x 7 23 117 40 33 060d Y xx x x 8 26 176 65 39 060d Y xxEst Pos Err 10.93m Est Vel Err 0.00m/s x x 9 27 291 45 20 040d Y xxPRNs: 9 PDOP: 1.6 Fix 0x03 Flags 0xdd x x10 29 86 5 13 040d Y xmqqqqqqqqqqqqqqqqqqq NAV_SOL qqqqqqqqqqqqqqqqqqqqqj x11 31 202 13 7 030c xlqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk x12 120 207 36 0 0110 xxDOP [H] 1.1 [V] 1.2 [P] 1.6 [T] 0.8 [G] 1.8 x x13 124 155 37 0 0110 xmqqqqqqqqqqqqqqqqqqq NAV_DOP qqqqqqqqqqqqqqqqqqqqqj x14 126 151 35 0 0110 xlqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk x15 xxTOFF: -0.295365554 PPS: -0.429079607 x mqqqqqq NAV_SVINFO qqqqqqqqjmqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj blablablablablablablabla (26) blablablablablablablabla (24) blablablablablablablabla
Let's now have a look at the NTP with the "chronyc" command... Not bad, everything is working :)
root@rsfo-ntp01:~# chronyc sources -v .-- Source mode '^' = server, '=' = peer, '#' = local clock. / .- Source state '*' = current best, '+' = combined, '-' = not combined, | / 'x' = may be in error, '~' = too variable, '?' = unusable. || .- xxxx [ yyyy ] +/- zzzz || Reachability register (octal) -. | xxxx = adjusted offset, || Log2(Polling interval) --. | | yyyy = measured offset, || \ | | zzzz = estimated error. || | | \ MS Name/IP address Stratum Poll Reach LastRx Last sample =============================================================================== #- GPS 0 4 377 11 -796ns[ -951ns] +/- 100ms #* PPS 0 2 377 2 -1965ns[-2129ns] +/- 3142ns root@rsfo-ntp01:~# root@rsfo-ntp01:~# root@rsfo-ntp01:~# chronyc sourcestats -v root@rsfo-ntp01:~# chronyc sourcestats -v .- Number of sample points in measurement set. / .- Number of residual runs with same sign. | / .- Length of measurement set (time). | | / .- Est. clock freq error (ppm). | | | / .- Est. error in freq. | | | | / .- Est. offset. | | | | | | On the -. | | | | | | samples. \ | | | | | | | Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev ============================================================================== GPS 12 9 177 -0.012 0.015 -811ns 612ns PPS 59 25 232 -0.000 0.013 -1ns 1987ns root@rsfo-ntp01:~# root@rsfo-ntp01:~# root@rsfo-ntp01:~# chronyc tracking Reference ID : 50505300 (PPS) Stratum : 1 Ref time (UTC) : Sun Apr 23 16:58:14 2023 System time : 0.000000327 seconds slow of NTP time Last offset : -0.000000122 seconds RMS offset : 0.000000652 seconds Frequency : 2.603 ppm slow Residual freq : -0.000 ppm Skew : 0.032 ppm Root delay : 0.000000001 seconds Root dispersion : 0.000007401 seconds Update interval : 4.0 seconds Leap status : Normal
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.