In the following we describe the process of using the Draguino GPS/LoRa hat as ntp time source. It provides the PPS pulse on a GPIO and NMEA sentences on the UART. This approach works also with other hats, the GPIO pin for the PPS might need be changed. Another nice tutorial with more information can be found on satsignal.eu.
Build ntp with PPS support on rasbian stretch
We build ntpd with ATOM enabled, like it is proposed on ntp.org. We do not build a kernel, since the currently kernel in Rasbian Stretch supports already the PPS input.
apt-get source ntp aptitude build-dep ntp
Change the uppermost entry in debian/changelog, so the version number is incremented by 1, and “~pps1” is in the end. So, for example:
4.2.8p10+dfsg-2+deb9u1
becomes
4.2.8p10+dfsg-3+deb9u1~pps1
Then use
dpkg-buildpackage -b cd .. sudo dpkg -i ntp_4.2.8p10+dfsg-3+deb9u1\~pps1_armhf.deb
to build and install the package.
Preparing a Raspberry Pi 2
In principle we follow this approach, but we do not install the gpsd.
Furthermore, you need to ensure the serial port is not used for the console, so ‘/boot/cmdline.txt’ should look similar to this:
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
After that we disable the getty service.
sudo systemctl stop serial-getty@ttyAMA0.service sudo systemctl disable serial-getty@ttyAMA0.service
To automatically generate the symlinks, create the following file in ‘/etc/udev/rules.d/99-gps.rules’.
KERNEL=="pps0",SYMLINK+="gpspps0" KERNEL=="ttyAMA0", SYMLINK+="gps0"
Now we restart the system:
sudo reboot
Preparing a Raspberry Pi 3
In principle we follow this approach, but we do not install the gpsd. On the Raspberry Pi 3, the UART is used for the Bluetooth module per default. But, we are able to redirect it to the normal GPIO pins. Nevertheless, Bluetooth is then not available anymore. Add at the bottom of “/boot/config.txt”:
dtoverlay=pps-gpio,gpiopin=18 dtoverlay=pi3-disable-bt-overlay core_freq=250 enable_uart=1 force_turbo=1
Change the GPIO pin number to the pin to which you have connected the PPS signal, if necessary.
Ensure there is no console using the serial port, so “/boot/cmdline.txt” should look similar to this:
dwc_otg.lpm_enable=0 console=tty1 root=PARTUUID=5fadc8b0-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
Disable bluetooth:
sudo systemctl disable hciuart
Replace “serial1” with “ttyS0” in ‘/lib/systemd/system/hciuart.service’. And disabel the getty service.
sudo systemctl stop serial-getty@ttyS0.service sudo systemctl disable serial-getty@ttyS0.service
To automatically generate the symlinks, create the following file in ‘/etc/udev/rules.d/99-gps.rules’.
KERNEL=="pps0",SYMLINK+="gpspps0" KERNEL=="ttyS0", SYMLINK+="gps0"
Now we restart the system:
sudo reboot
Setting up ntpd
First we estimate the time delay of the NMEA sentences from the PPS pulse. The procedure is described here, where you also find some more info on the definition of the mode and the flags we use in ‘ntp.conf’. First, we enable NMEA sentences (mode 17 ensures ‘RMC’ is used), but don’t select it is time input. We ensure the previously used servers are still available, so just add this before the first server statement in ‘/etc/ntp.conf’
server 127.127.20.0 mode 17 minpoll 4 noselect fudge 127.127.20.0 flag1 0 time2 0.000 refid GPS0
With “mode 17” we assume that the “RMC” sentences are first. But, you can check with
cat /dev/gps0
which are the first one in each second.
After the clock settled, use
ntpq -p
To get an output like:
remote refid st t when poll reach delay offset jitter ============================================================================== GPS_NMEA(0) .GPS0. 0 l - 16 377 0.000 -172.54 22.219 +ntp1.sptime.se .PPS. 1 u 20 64 377 58.349 2.085 0.638 *ntp2.sptime.se .PPS. 1 u 28 64 377 51.921 5.399 0.615
We either use the offset directly, or we compute the average over some time. To compute the average, we need to collect some data. We can do this (preferably inside of a ‘screen’) with
while true; do ntpq -p | grep NMEA >> NMEA.txt; sleep 16; done <CTRL+C> cat NMEA.txt | nawk '{print $(NF-1)}' | ministat
and we get this nice statistical analysis:
+--------------------------------------------------------------------------+ | x | | x | | x | | x | | x | | x | | x | | x | | x | | x | | x | | x | | x | | x | | x | | x x | | x x | | x x | | x x | | x x | | x x | | xx x | | xx x | | xx x x | | xx x x | | xx x x | | xx x x | | xx x x | | xx x x | | xx x x | | xx x x | | xx x x | | xx x x | | xx x x | | xx xx x x | | xx xxx x x | | xx xxx x x | | xx xxx x x | | xx xxx x x | | xx xxx x x | | xx xxx x x | | xx xxx x x | | xx xxx x x | | xx xxx x xx | | xx xxx xx xx | | xx xxx xx xx | | xx xxx xx xx | | xx xxx xx xx | | xx xxx xx xxx | | xxx xxx xx xxx | | xxx xxx xx xxx | | xxxx xxx xx xxx | | xxxx xxx xxx xxx | | xxxx xxx xxx xxx | | xxxx xxx xxx xxx | | xxxx xxx xxx xxx | | xxxx xxx xxx xxx | | xxxx xxx xxx xxx | | xxxx xxx xxx xxx | | xxxx xxx xxx xxx | | xxxx xxx xxx xxx | | xxxx xxx xxx xxx | | x xxxxx xxx xxx xxx | | x xxxxx xxx xxx xxx | | x xxxxx xxx xxx xxx | | x xxxxx xxxx xxx xxx | | x xxxxx xxxx xxx xxxx | | xxxxxxx xxxx xxx xxxx | | x xxxxxxx xxxx xxx xxxx | | x xxxxxxx xxxx xxx xxxx x | | x xxxxxxx xxxx xxx xxxx x | | x xxxxxxx xxxx xxx xxxx x | | x xxxxxxxxxxxxxxxx xxxx x | | x xxxxxxxxxxxxxxxxxxxxx x | | x xxxxxxxxxxxxxxxxxxxxx x | | x xxxxxxxxxxxxxxxxxxxxxx x | | x xxxxxxxxxxxxxxxxxxxxxx x | | x xxxxxxxxxxxxxxxxxxxxxx x | | x xxxxxxxxxxxxxxxxxxxxxx x | | x xxxxxxxxxxxxxxxxxxxxxx x | | x xxxxxxxxxxxxxxxxxxxxxx x | | xxxxxxxxxxxxxxxxxxxxxxxx x | | xxxxxxxxxxxxxxxxxxxxxxxx xx | | xxxxxxxxxxxxxxxxxxxxxxxx xxx | | xxxxxxxxxxxxxxxxxxxxxxxx xxx | | xxxxxxxxxxxxxxxxxxxxxxxx xxx | | xxxxxxxxxxxxxxxxxxxxxxxx xxx | | xxxxxxxxxxxxxxxxxxxxxxxx xxxx | | x xxxxxxxxxxxxxxxxxxxxxxxx xxxxx | | xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxx | | xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxx | | x xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxx | | x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xx x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | x xx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | x x xx xxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | x x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | xx x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| | |__________AM_________| | +--------------------------------------------------------------------------+ N Min Max Median Avg Stddev x 1928 -300.69 -190.33 -228.57 -229.40727 16.453036
We see that the absolute value of the average is now 229, instead of the offset of 173 ms we saw earlier.
Now we replace the previously added rows in ‘ntp.conf’ with:
server 127.127.20.0 mode 17 minpoll 4 prefer fudge 127.127.20.0 flag1 1 flag2 0 flag3 1 flag4 0 time1 0.000 time2 0.229 refid GPS0 # flag1: use PPS # flag2: falling edge of PPS # flag3: Kernel mode discipling, setting to 0 might give you better results # flag4: obfuscate position # time1: time offset PPS # time2: time offset NMEA
N.B. we are using the absolute value of the offset for ‘time2’. Now, we restart the ntpd and it should use the PPS source.
sudo systemctl restart ntp
The final result should look like this, here we used ‘flag3 0’:
remote refid st t when poll reach delay offset jitter ============================================================================== oGPS_NMEA(0) .GPS0. 0 l 12 16 377 0.000 -0.009 0.002 +ntp1.sptime.se .PPS. 1 u 32 64 377 57.983 -0.487 17.328 -ntp2.sptime.se .PPS. 1 u 30 64 377 52.487 2.199 41.311
Troubleshooting
The following error in the syslog might indicate the ntpd cannot read the serial port for NMEA messages
refclock_params: time_pps_kcbind: Operation not supported