PNG time
        server logo
JPG rpi 2 model
                ublox neo-6m gps

PNG rpi 2 model b pinout

The primary reason that I had originally purchased my first Raspberry Pi 2 Model B SBC (Single Board Computer) was to operate my Flight Tracking Station.

With the prices of GPS modules dropping to extremely affordable levels (about $4 CDN), I decided to swap out the U-Blox NEO-6M GPS module for one that had a 5th pin -- a PPS (Pulse-Per-Second) contact that I could use to implement a high-accuracy NTP (Network Time Protocol)  stratum 1 time server!  In other words, using the primary (stratum 0) time clock sources available on GPS satellites to make my own secondary (stratum 1) shareable computer time source.

My primary source of information on how to do this came from these excellent sources:

Setting up a Stratum 1 NTP server on a Raspberry Pi
The Raspberry Pi as a Stratum-1 NTP Server
GPSD Time Service HOWTO
A Guide To GPS Network Time Synchronization

The wiring for the GPS module that I used is as follows:

Raspberry Pi
  RXD (GPIO15)

Power (VCC/3V3) and Ground (GND) pins are basic.  The Receive-Data (RXD) and Transmit-Data (TXD) are used to receive and transmit the serial-based GPS data stream (notice that reversal when connecting the pins i.e. the GPS 'transmit' pin is connected to the Raspberry Pi 'receive' pin, and vice versa).  The magic comes from the Pulse-Per-Second (PPS) GPS pin being connected to the Raspberry Pi Pulse-Code-Modulation (PCM) pin (also acting as Pulse-Width-Modulation (PWM0)).

When a good GPS satellites lock has been achieved, my GPS will transmit useful time (as well as position) data (at 9600 baud) using various NMEA sentence structures.  The one that the NTP utility uses to extract time are the following:
Here are some samples of those sentences from my GPS (with position information obscured):
Here is a sample NTP time statistics from my time server soon after it was running:
pi@raspberrypi ~ $ ntpq -p 
     remote           refid      st t when poll reach   delay   offset  jitter
 LOCAL(0)        .LOCL.          10 l  45h   64    0    0.000    0.000   0.000
oGPS_NMEA(0)     .GPS.            0 l    8   16  377    0.000    0.003   0.002
*   2 u   37   64  377   51.341    1.001 166.392
+kirdu.smartacti  2 u    3   64   77   42.552   10.272  99.637
+host1.hosttechn  2 u   20   64  377   38.465   10.301 161.560      2 u   65   64  376   34.556    0.719  52.451
In this sample, the GPS source is providing a time accuracy of 0.003 microseconds (3 millionths of a second) to my computer network!  This time source is good enough to join (if I chose to do so) the list of other NTP time sources used by millions of computers around the world: How do I join

If everything is working OK, and a PPS lock has been established (sometimes tricky inside my home), this text will show the NTP statistics results:

Embedded Text Document

UPDATE: After upgrading my Raspberry Pi linux version to Raspbian/Debian 9 'Stretch', my GPS/PPS functionality stopped working -- which I have now finally fixed by doing the following -- since I found out that the '/dev/ttyAMA0' device was being used by the 'login' process, which was interferring with 'ntp' from getting at it as well:
  • Type: "sudo raspi-config"
  • Pick: "5 Interfacing Options  Configure connections to peripheral"
  • Pick: "P6 Serial Enable/Disable shell and kernel messages on the serial connection"
  • Answer 'No' for: "Would you like a login shell to be accessible over serial?"
  • Answer 'Yes' for: "Would you like the serial port hardware to be enabled?"
  • Type: "sudo reboot"

I also did the following, but was not sure whether it was necessary or helped:

systemctl stop serial-getty@ttyAMA0.service
systemctl disable serial-getty@ttyAMA0.service
systemctl mask serial-getty@ttyAMA0.service
UPDATE: I also activated the same feature on my backup server: an Orange Pi PC Plus (info here, purchased here and here).  I chose this particular model since it was the best 'bang-for-the-buck' that I could find in the Orange Pi series, was less expensive than the boards offered by the Raspberry Pi foundation, and had an 8GB eMMC flash memory module on it (to avoid eventual wear-out of removable SD cards).  A good resource comparing the various Orange Pi models is here.

PNG orange pi pc plus
PNG orange pi pinout
The wiring for the GPS module that I used is as follows:

Orange Pi
  PA14 (UART3_RX)
PA6 (PWM1)

Currently the 'best' source of Linux distros for the Orange Pi boards comes from Armbian, rather than from the manufacturer itself (which provides almost no support, and with non-100%-functional software!).  A useful discussion forum for the Allwinner H3 boards with mainline Linux kernel is here.
  • For 'legacy' kernel, no PPS features are present, so a new kernel needs to be compiled (lots of work!):
ORANGE PI PLUS H3 with GPS/PPS – — The Black Magic Boxes
  • For 'mainline' kernel, PPS feature is already present, but needs to be activated:

Add to the '/boot/armbianEnv.txt' file, specifically entries for 'overlays' to activate 'pps-gpio' and 'uart3' (if that is the pins you have decided to use), and 'param_pps_pin=PA6' (again, if that is the pin you have opted to use for the PPS signal):

overlays=pps-gpio uart3

After rebooting, you should see 'pps' entries in 'dmesg':

[    8.277867] pps pps0: new PPS source pps@0.-1
[    8.277928] pps pps0: Registered IRQ 64 as PPS source

You should also be able to run 'ppstest' on the new device:

darren@orangepipcplus:/boot$ sudo 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 1524664406.998850031, sequence: 1743 - clear  0.000000000, sequence: 0
source 0 - assert 1524664407.998835994, sequence: 1744 - clear  0.000000000, sequence: 0
source 0 - assert 1524664408.998835038, sequence: 1745 - clear  0.000000000, sequence: 0
source 0 - assert 1524664409.998825706, sequence: 1746 - clear  0.000000000, sequence: 0
source 0 - assert 1524664410.998834955, sequence: 1747 - clear  0.000000000, sequence: 0
source 0 - assert 1524664411.998817203, sequence: 1748 - clear  0.000000000, sequence: 0
source 0 - assert 1524664412.998810533, sequence: 1749 - clear  0.000000000, sequence: 0
source 0 - assert 1524664413.998828901, sequence: 1750 - clear  0.000000000, sequence: 0
Here is what my NTP configuration file looks like, which also supports the running of a parallel GPSD process:
# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help

# Local
fudge stratum 10

server mode 17 minpoll 4 maxpoll 4 iburst true prefer 
fudge flag1 1 refid GPS

# GPS with PPS enabled
server mode 17 minpoll 4 maxpoll 4 iburst true prefer 
fudge flag1 1 refid PPS
#server mode 17 minpoll 4 maxpoll 4 iburst true prefer 
#fudge flag1 1 refid GPS

# Internet time servers for sanity
server iburst prefer 
server iburst 
server iburst 
server iburst

# By default, exchange time with everybody, but don't allow configuration.
restrict default kod nomodify notrap nopeer noquery 
restrict -6 default kod nomodify notrap nopeer noquery

# Local users may interrogate the ntp server more closely.
restrict -6 ::1

# Drift file etc.
driftfile /var/lib/ntp/ntp.drift 

# stats
enable stats
statistics loopstats
#statistics loopstats peerstats clockstats
statsdir /var/log/ntp/
#filegen peerstats file peers type day link enable
#filegen loopstats file loops type day link enable
filegen loopstats file loopstats type day link enable

The default 'ntp' app from the respositories doesn't appear to support PPS properly (without patching), so I got and compiled the 'NTPsec' fork, which has the bonus of providing the 'ntpmon' app.  Some instructions for compiling NTPsec are here, but basically they are:

cd $HOME/Downloads
git clone --depth 1
cd ntpsec
sudo ./buildprep
./waf configure
./waf build
sudo ./waf install

In order for the NTP logging to work properly, the directory '/var/log/ntp' needs to be created for every reboot, and with the correct (open) permissions.  Add the following to '/etc/rc.local':

mkdir /var/log/ntp
chmod 777 /var/log/ntp

After that is set up, I start the NTP process this way:

sudo service ntp start

For GPSD, here is what the '/etc/default/gpsd' configuration file looks like:

# Default settings for the gpsd init script and the hotplug wrapper.

# Start the gpsd daemon automatically at boot time

# Use USB hotplugging to add new USB devices automatically to the daemon

# Devices gpsd should collect to at boot time.
# They need to be read/writeable, either by user gpsd or the group dialout.

# Other options you want to pass to gpsd
GPSD_OPTIONS="-n -b -G "

The way to start the process is thus:

sudo service gpsd start
If everything is working OK, and a PPS lock has been established (sometimes tricky inside my home), this text will show the NTP statistics results:

Embedded Text Document

Using 'ntpviz', here are some GnuPlot graphs over time showing interesting data:

PNG offset

PNG offset histogram

For the full page of info, see NTPGraphs