I’ve been following Jeff Gerling’s videos on “nanosecond clock sync”, which got me looking into stratum 1 NTP servers. This was a fun little project i’ve wanted to do for a while now, and am glad i’ve finally got around to it. I want to share this with you guys as well. Worth mentioning that this works with a Raspberry Pi5’s just as well. Also, shoutout to Tom and Rodrigo from which i’ve put together this guide: https://blog.tomvoboril.com/, https://www.youtube.com/@linuxtechschool4841


Here are the links to all bits of hardware I have used followed by the setup:

Raspberry Pi GPS HAT with RTC - https://thepihut.com/products/raspberry-pi-gps-hat

GPS Antenna - https://www.amazon.co.uk/dp/B08NK887DV

Raspberry Pi4 1GB - https://thepihut.com/products/raspberry-pi-4-model-b

Raspberry Pi4 USB-C Power Supply UK - https://www.amazon.co.uk/dp/B07VKF1CK8

GPS HAT CASE for Raspberry Pi4 (v2.0) - https://thepihut.com/products/gps-hat-case-for-raspberry-pi-4


ssh ntp01 –> paul@ntp01:~ $

We’ll start by elevating privileges:

sudo -i

First off some tweaks raspi-config:

raspi-config

Select "Interface Options"

raspi-config

And enable "I2C"

raspi-config

Now let’s install python-smbus and i2c-tools:

apt-get install python3-smbus python3-gps python3-serial i2c-tools pps-tools -y

We will test it out:

i2cdetect -y 1

Here we can see the RTC (0x52) and GPS (0x42) on the I2C bus.

0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- 42 -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- 52 -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Add dtoverlay=i2c-rtc,rv3028, dtoverlay=pps-gpio,enable_uart=1, and lets disable bluetooth as well:

cat << EOF | tee -a /boot/firmware/config.txt
dtoverlay=i2c-rtc,rv3028
dtoverlay=pps-gpio
dtoverlay=disable-bt
enable_uart=1
EOF

Now let’s restart the pi:

reboot

On reboot rerun the i2cdetect line and you should see 52 has been replaced with UU to indicate the kernel driver is loaded.

Next we remove and disable fake-hwclock:

apt-get -y remove fake-hwclock
update-rc.d -f fake-hwclock remove
systemctl disable fake-hwclock

Remove entries from system files:

vim /lib/udev/hwclock-set

And we comment out the following lines:

#if [ -e /run/systemd/system ] ; then
#    exit 0
#fi

#/sbin/hwclock --rtc=$dev --systz
#/sbin/hwclock --rtc=$dev --hctosys

To read time:

hwclock -v -r

To write time:

hwclock -w

GPS/PPS Operation

First let’s install pps-tools:

apt-get install pps-tools

Add dtoverlay=pps-gpio to /boot/firmware/config.txt:

cat << EOF | tee -a /boot/firmware/config.txt
dtoverlay=pps-gpio
EOF

Add pps-gpio to /etc/modules:

cat << EOF | tee -a /etc/modules
pps-gpio
EOF

Reboot and test the config:

reboot
ppstest /dev/pps0

Configure NTP with chrony:

First let’s install prerequisites:

apt-get install gpsd chrony -y

We will enable the serial ports from raspi-config:

raspi-config

And we follow Interface Options, raspi-config

And Serial Port, once prompted for a login shell to be accessible over serial tap No Second prompt Would you like the serial port hardware to be enabled - >> "Yes" This will enable the serial port and pass the pps. raspi-config

Let’s get the serial device [entry will be easy to recognise]:

ls -la /dev/

Device in my case: ls-la-dev

To verify the operation of the GPS via serial:

apt-get install minicom
minicom -b 115200 -o -D /dev/ttyAMA0

Configure gpsd:

vim /etc/default/gpsd

In the first block:

DEVICES="/dev/ttyAMA0 /dev/pps0"
START_DAEMON="true"

Second block - options to pass to gpsd:

GPSD_OPTIONS="-b -n -D3 -s 115200"

For the third block we will disable USB GPS hot plug:

USBAUTO="false"

This is how the config file should look like: etc-default-gpsd

Next we will add makestep, PPS, and NMEA and allow all traffic from local networks RFC1918:

cat << EOF | tee -a /etc/chrony/chrony.conf
makestep .1 5
refclock PPS /dev/pps0 refid PPS prefer
refclock SHM 0 refid NMEA

allow 192.168.0.0/16
allow 172.16.0.0/12
allow 10.0.0.0/8
EOF

Restart the system:

reboot

Troubleshooting tools.

gpsmon is a great little tool that shows the incoming data on the GPS receiver:

gpsmon -n

gpsmon

chronyc will show sources and make comparison to other NTP servers on the internet:

watch -n 1 chronyc sources -v

chronyc

timedatectl will show all time standards used on the local server:

timedatectl

timedatectl

tcpdump is also useful in telling us which clients are actually using the NTP server by running:

tcpdump -Qin -ni any port 123

The makestep option on chronyc will force the hardware to sync immediately:

chronyc makestep

Our NTP server is done! :)

ntp01