Skip to content

Instantly share code, notes, and snippets.

@pvazteixeira
Last active March 27, 2022 22:35
Show Gist options
  • Save pvazteixeira/158370f9f231a21f8c815286e8164e87 to your computer and use it in GitHub Desktop.
Save pvazteixeira/158370f9f231a21f8c815286e8164e87 to your computer and use it in GitHub Desktop.
Using a raspi as a Stratum-1 NTP server

Using a Raspberry Pi as a Stratum 1 NTP server

Motivation/Background/Context

Having had some degree of success with the various tutorials on how to setup a raspi as a NTP microserver, the following are my personal notes on what worked for my setup (mostly based on the ntpsec guide, but with a few changes).

Hardware

  • Raspberry Pi (I'm using a Model B rev 1.0)
  • Adafruit Ultimate GPS Breakout v3 - currently out of stock on adafruit, but available on amazon for a bit more
  • Female-Female jumper wires (5)

Connecting the GPS

Note: If using a different GPS board, check the output levels on its TX, RX and PPS pins, as the raspi works with 3.3V logic levels and is not 5V tolerant on the GPIO

  • Connect the GPS's VIN and GND to the raspi's +5V and GND pins
  • Connect the GPS's TX and RX to the rapsi's GPIO14 and GPIO15 (respectively)
  • Connect the GPS's 1PPS pin to the raspi's GPIO18 pin

Raspberry Pi setup

OS

  • Download raspbian
  • Copy the image to the SD card
  • create an empty file named ssh in the /boot/ partition of the SD card - this is so that the pi will run an ssh-server
  • Insert the card and boot up the Pi

Configuration

  • run raspi-config (sudo raspi-config) and set the following options
    • 1 - Expand Filesystem
    • 2 - Change User Password (lest your pi get hacked into a spam email server and/or part of a bot net)
    • [Optional] 3 - Boot Options:
      • B1 - Desktop/CLI
        • B1 - Console (enable)
      • B2 - Wait for Network at boot (enable)
      • B3 - Splash screen at boot (disable)
    • 4 - Internationalisation Options - change locale, timezone, and keyboard layout to match yours
    • [Optional] 6 - Overclock - since I'm running an old model, I set it to 'modest'
    • 7 - Advanced Options
      • [Optional] A3 - Memory Split - set this to the minimum possible (16MB)
      • A4 - SSH (enable)
      • A8 - Serial - disable login shell over serial
  • Reboot (sudo reboot)
  • Edit the following lines in /boot/config.txt (sudo nano /boot/config.txt)
    • change enable_uart=0 (if it exists) to enable_uart=1

PPS module

  • Update the pi's sofware sources list (sudo apt-get update)
  • Install pps-tools (sudo apt-get install pps-tools)
  • Edit /boot/config.txt (sudo nano /boot/config.txt) to load the pps module and check for the PPS signal on GPIO pin 18 by adding the line dtoverlay=pps-gpio,gpiopin=18
  • Reboot the raspi
  • Confirm the pps-gpio module is present (sudo lsmod | grep -i pps)
  • Check for the pps signal by running sudo ppstest /dev/pps0. The output should look like
source 0 - assert 1487741039.003073221, sequence: 332 - clear  0.000000000, sequence: 0

GPSD

  • Install dependencies: sudo apt-get install git scons libncurses5-dev python-dev bc
  • clone the repo: git clone --depth 1 git://git.savannah.nongnu.org/gpsd.git
  • build: cd gpsd && scons timeservice=yes python=yes gpsdclients=yes gpsclock=yes nmea0183=yes mtk3301=yes ublox=true systemd=true controlsend=true
  • check that gpsd is working by running sudo ./gpsd -N -n -D 3 /dev/ttyAMA0 . You should see output similar to
gpsd:INFO: Sats used (5):
gpsd:INFO: PPS:/dev/pps0 Assert hooks called clock:  1487829690.596262000 real:  1487829691.000000000: accepted
gpsd:INFO: PRN= 19 az= 77 el=73 (0.284878, 0.065769, 0.956305)
gpsd:INFO: PRN= 17 az=103 el=56 (0.544861, -0.125791, 0.829038)
gpsd:INFO: PRN= 23 az= 76 el=16 (0.932708, 0.232550, 0.275637)
gpsd:INFO: PRN=  3 az= 42 el=15 (0.646331, 0.717823, 0.258819)
gpsd:INFO: PRN=  9 az=114 el=14 (0.886409, -0.394655, 0.241922)
  • check that gpsd is posting the PPS notifications to memory by running sudo ./ntpshmmon. You should see output similar to
ntpshmmon version 1
#      Name Seen@                Clock                Real                 L Prec
sample NTP0 1487829839.456846000 1487829839.049652000 1487829839.000000000 0 -20
sample NTP1 1487829839.600174000 1487829839.598784000 1487829840.000000000 0 -30

NTPD

  • Install dependencies: sudo apt-get install bison libevent-dev libcap-dev libssl-dev libreadline-dev
  • Clone the repo git clone --depth 1 https://gitlab.com/NTPsec/ntpsec.git
  • Configure the build cd ntpsec && ./waf configure --refclock=shm (pay attention to any warnings about missing dependencies)
  • Build ./waf build
  • Edit etc/ntp-conf.d/example.conf to use the gpsd shared memory updates by uncommenting the first line (includefile use-gpsd-shm)
  • With the gps daemon still running, start the NTP daemon: `sudo ./build/main/ntpd/ntpd -g -c etc/ntp-conf.d/example.conf
  • Finally, check the NTP status: ./ntpclients/ntpq -p. Your output should look like this
     remote                                   refid      st t when poll reach   delay   offset   jitter
=======================================================================================================
xSHM(0)                                  .GPS.            0 l   34   64  377   0.0000 -68.7369  11.0842
xSHM(1)                                  .PPS.            0 l   28   64  377   0.0000 394.3782   4.8676

Check that the reach is greater than zero for both sources - a value of zero for GPS/PPS is likely caused by the NTP daemon not getting NMEA/PPS updates (respectively) from GPSD.

Optional steps

Optimizations

Performance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment