A Raspberry Pi makes an excellent GNSS-disciplined network time server and is much easier to set up than you might imagine. All you need is a Pi and GNSS receiver that outputs PPS.
There are a few things to keep in mind when using a Pi as a network time server. Most of these relate to maintaining the best performance and accuracy as possible.
dietpi-config
or raspi-config
utilities. Here's an example config.txt that I have found works well. This has been tested to work on the Pi2, 3, and 4.
# cut down GPU-allocated RAM gpu_mem_256=16 gpu_mem_512=16 gpu_mem_1024=16 # disable splash screen disable_splash=1 # disable audio dtparam=audio=off # enable I2C dtparam=i2c_arm=on dtparam=i2c1=on # configure DS3231 as hardware RTC dtoverlay=i2c-rtc,ds3231 # disable SPI dtparam=spi=off # enable UART (/dev/ttyAMA0) enable_uart=1 # disable speedstep and lock CPU freq force_turbo=1 arm_freq=800 # disable video core dtoverlay=dietpi-disable_vcsm # disable wifi and bt dtoverlay=disable-wifi dtoverlay=disable-bt # configure GPIO4 as the input for /dev/pps0 dtoverlay=pps-gpio,gpiopin=4 # set the activity LED to blink in a heartbeat pattern. # This provides a quick visual indicator of the system status. dtparam=act_led_trigger=heartbeat
These links include sample configurations.
There are a number of different tests you can perform to verify system operation if you're running into trouble. You will need to have minicom
and pps-tools
installed on the server to perform some of these tests.
Put a jumper across pins 8 and 10, creating a UART loopback. Run sudo minicom -b 9600 -D /dev/ttyAMA0
and type into the console. Everything you type should appear in the terminal. If it does not, make sure your configuration options in config.txt are correct.
First, make sure GPSD is stopped. Run sudo minicom -b 9600 -D /dev/ttyAMA0
(assuming your GNSS is running at 9600 baud, adjust as appropriate). If you do not see a constant flow of data from your GNSS receiver, make sure that you have properly connected the receiver and set the baud rate. Remember, Tx on the GNSS goes to Rx on the Pi, and vice versa!
Use cgps
to verify that your GNSS receiver has a lock and that gpsd is receiving and parsing its output correctly. . Here's example output indicating that gpsd is working and that the GNSS receiver has a good lock:
Verify that your system is picking up the PPS signal from your GNSS receiver with sudo ppstest /dev/pps0
. Output should look like this:
trying PPS source "/dev/pps0" found PPS source "/dev/pps0" ok, found 1 source(s), now start fetching data... source 0 - assert 1614093326.000000138, sequence: 1231 - clear 0.000000000, sequence: 0 source 0 - assert 1614093326.999999940, sequence: 1232 - clear 0.000000000, sequence: 0 source 0 - assert 1614093327.999999325, sequence: 1233 - clear 0.000000000, sequence: 0 source 0 - assert 1614093328.999999075, sequence: 1234 - clear 0.000000000, sequence: 0 source 0 - assert 1614093329.999999085, sequence: 1235 - clear 0.000000000, sequence: 0
If you do not see a result like this, verify that you have properly connected the PPS output from your GNSS receiver to the Pi at the pin you have specified in config.txt
and that your GNSS is properly sending this signal. On some GNSS receivers PPS can be disabled.
Verify that chrony is working properly with chronyc sources
MS Name/IP address Stratum Poll Reach LastRx Last sample =============================================================================== #* GPS 0 4 377 17 +317ns[ +455ns] +/- 177ns ^- time-a-g.nist.gov 1 7 377 13 -3510us[-3510us] +/- 23ms ^- time-a-wwv.nist.gov 1 7 377 12 +164us[ +165us] +/- 40ms ^- time-a-b.nist.gov 1 7 377 74 -746us[ -746us] +/- 41ms
If it's not, check the contents of /etc/chrony.conf
. Specifically, make sure that the refclock SOCK
entry is correct, and make sure that gpsd
is being started after chronyd
.
An easy way to check the startup order is to use the systemd-analyze plot >bootup.svg
command to generate an image of the order in which systemd
is starting services, and how long they take to start, drawn sequentially from top to bottom. Here's a subset of an example of such an plot on a system where chronyd
isn't connecting to gpsd
:
Here, we can see that while gpsd.service
is indeed starting after chronyd.service
, gpsd.socket
is starting earlier. gpsd.socket
is the component of gpsd
that writes to the SOCK that chronyd
creates - and if it's started first, it will not send data to chrony.