NTP Server via GPS on a Raspberry Pi

This post shows how to use a GPS receiver with a Raspberry Pi to build a stratum 1 NTP server. I am showing how to solder and use the GPS module (especially with its PPS pin) and listing all Linux commands to set up and check the receiver and its NTP part, which is IPv6-only in my case. Some more hints to increase the performance of the server round things off. In summary this is a nice “do it yourself” project with a working stratum 1 NTP server at really low costs. Great. However, keep in mind that you should not rely on such projects in enterprise environments that are more focused on reliability and availability (which is not the case on self soldered modules and many config file edits).

This article is one of many blogposts within this NTP series. Please have a look!
Note that this project uses a GPS receiver with a PPS (pulse per second) pin, that is: It does not only get the imprecise time sent over a serial console (standard NMEA 0183 output, more details here), but also the highly precise sync tick which accurately declares the start of every second. This involves some soldering. ;)

At the time of writing (Nov 2018) I am using a Raspberry Pi 1 B (yes, the old one), kernel 4.14.71+ and Raspbian GNU/Linux 9 (stretch). I installed a few relevant packages and gave it a static IPv6 address. Legacy IP (IPv4) is not used at all, only IPv6.

1) Soldering the GPS Module

It’s all about the GPS module “GY-GPS6MV2”, though I am quite sure that there are some other GPS modules with a PPS pin out there. Google for it and get one from China for a couple of Euros. ;) I soldered the five cables directly to the Pi, while I used a small Pigtail from the Hirose  connector (the one on the GPS module) to SMA female (not RP-SMA!) to mount it on the housing of the Pi. This SMA connector is commonly used by GPS antennas for cars. In fact I did not use the small GPS antenna that was delivered with the GPS module at all, but a slightly more robust one that can be used outside as well.

Following is the assignment of the five cables from the GPS module to the Raspberry Pi. You need to look at the product details of the module to find the PPS pin. I used a ribbon cable, refer to the photos below:

  1. GPS module VCC, white: Pi pin 1, +3.3 V
  2. GPS module GND, black: Pi pin 6, GND
  3. GPS module RX, grey: Pi pin 8, TXD0
  4. GPS module TX, purple: Pi pin 10, RXD0
  5. GPS module PPS, blue: Pi pin 12, GPIO18

This is what it looked like on my desk:

When you’re finished you can just power on the Pi again. If you have a good GPS signal your GPS module will blink blue once a second:


2) Getting started with mere GPS

The first step is to check whether the GPS module is running and whether the Pi receives the generic NMEA 0183 sentences. You have to disable the serial login shell first while keeping the hardware port enabled: sudo raspi-config , navigate to “5 Interface Options” -> “P6 Serial” and:

  1. Would you like a login shell to be accessible over serial? –> No
  2. Would you like the serial port hardware to be enabled? –> Yes

followed by a reboot. After that you can use “screen” to get some output: sudo screen /dev/ttyAMA0 9600 . You can close it with Ctrl+a \ y . The output should be like:

Now you need to install the gpsd daemon which needs to run in the background at startup:

After the reboot, check that the daemon is running:

With tools such as cgps -s or gpsmon you get user friendly information from your GPS module such as:

Good so far. Your GPS is up and running. ;D

3) Leveraging PPS

You now have to activate the pulse per second functionality:

After the reboot, check that the pps module is loaded, which is the case if “lsmod” lists some drivers such as this:

and try to get a tick every second (cancel it with Ctrl+c as always):

Good again.

4) Configuring NTP

I have first installed NTP via sudo apt-get install ntp to have all those dependencies and startup scripts in place, but built it from source afterwards as well to run the server in the latest version:

(Fun fact: Since I am running my NTP server via IPv6-only meanwhile the NTP download page is IPv4-only, I had to download and copy the ntp package from another machine to the Raspberry Pi. Sigh. Yes, I know, DNS64/NAT64 would solve the problem.)

You have just installed the latest version of NTP, while “holding” the ntp package within dpkg to not overriding/downgrading it with future “apt-get update”s. You can verify this with the following: (Note the “h” in the very first column which indicates that the ntp package is on hold.)

Similarly you can verify the running ntp version with:


Now you need to add the reference clock (GPS + PPS) to NTP: “Drivers have addresses in the form 127.127.t.u, where t is the driver type and u is a unit number in the range 0-3 to distinguish multiple instances of the same driver”, Reference Clock Support. In fact we have to use two drivers, one for the GPS to get the rough time (driver 28, SHM, shared memory driver which uses the gpsd daemon) and another one for the PPS (driver 22).

There are a few things to consider. First, concerning the PPS: “While this driver can discipline the time and frequency relative to the PPS source, it cannot number the seconds. For this purpose an auxiliary source is required, ordinarily a radio clock operated as a primary reference (stratum 1) source; however, another NTP time server can be used as well. For this purpose, the auxiliary source should be specified as the prefer peer, as described in the Mitigation Rules and the prefer Keyword page”, PPS Clock Discipline. And about the SHM and its “flag1”: “Skip the difference limit check if set. Useful for systems where the RTC backup cannot keep the time over long periods without power and the SHM clock must be able to force long-distance initial jumps. Check the difference limit if cleared (default)”, Shared Memory Driver.

TL;DR: I had many problems running the Pi with *only* GPS/PPS, because after reboots or temporarily loss of GPS signal it did not come back into normal working mode. The solution was to add some more NTP servers with the “prefer” statement to continuously have the time synced, while PPS can then do the exact and very precise timing.

In the end I used these lines for my two drivers in the sudo nano /etc/ntp.conf file:

in conjunction with some more (in my case: IPv6 capable) NTP servers:

(Note that I used “fudge time1 +0.130 …” to adjust the GPS time according to the other NTP servers. You can try some higher/lower values to have the offset of your SHM compared to the offsets of those other NTP servers very small.)

Finally, it should give you something like this:

Note the ° symbol (= PPS peer when the prefer peer is valid) before the PPS, as well as the * symbol (= system peer) before the SHM; refer to Peer Status Word. These symbols must be present. Otherwise your instance is not working correctly, which would show an x instead.

Congratulations! You have your own NTP server on a Raspberry Pi with GPS and PPS up and running. Go for it! :D

5) Enhanced PPS Performance

[UPDATE Nov. 2018] Please note that I was not able to reproduce this behaviour on a fresh Raspbian stretch installation in 2018 anymore. Independent of the below mentioned settings the jitter of the PPS was about 4 µs. The following listings are from an NTP server with Raspbian jessie, kernel 4.4.26+, in 2016/2017.[/UPDATE]

I came across the very detailed page from David Taylor in which he has some thoughts about reducing the (already very good) jitter for the PPS. Section “Enhanced PPS performance” on his page.

I opened the file sudo nano /boot/cmdline.txt and added nohz=off at the end of this single line. Of course with a space before it. Followed by a sudo reboot.

The jitter of the PPS driver decreased from about 0.005 ms = 5 µs to about 2 µs. Wow!


6) Reducing Ethernet Latency

And even one more hint from David Taylor about reducing the Ethernet latency on a Pi: Adding another option to the single line in sudo nano /boot/cmdline.txt that states: smsc95xx.turbo_mode=N (reboot needed) indeed reduces the “delay” as shown in the “ntpq -p” output again. I used two Raspberry Pis connected via a single switch, first time without the option, second with the option set on both Pis. The delay between those NTP servers decreased from about 0.916 ms to 0.632 ms. Nice.

That’s it for now. Wow! If you have any suggestions, please write a comment.


As always here are some links for further reading:

Featured image “Kompass_.jpg” by Rolf Schmitz is licensed under CC BY-SA 2.0.

Leave a Reply

Your email address will not be published. Required fields are marked *