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