Table of Contents
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.
Things to Keep in Mind
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.
- Don't use the Pi for anything other than a network time server. A low and predictable system load will keep everything running smoothly.
- Make sure the Pi is connected to a stable power source. Low-voltage brownouts impact the onboard clock significantly.
- Use Ethernet when possible. Even on Pis that use USB-connected NICs (everything before the Pi4) the performance is better than WiFi, at least in my own testing.
- Disable Bluetooth. On some Pis this is necessary because the Bluetooth interface uses the hardware UART. On all Pis Bluetooth will use additional power, clock cycles, and potentially introduce interference.
- Add a hardware real time clock. The Pi uses a software RTC which is not very stable (±20ppm, or worse). A hardware RTC will improve short term stability (particularly useful if your GNSS loses its lock for any reason) and, if it's battery backed, will make sure the Pi comes up instantly with the correct date and time should it lose power for any reason. I highly recommend the DS3231. See DS3231 on Raspberry Pi.
- Lower the CPU speed and prevent it from speedstepping. I have found that 700 or 800MHz is perfectly suitable. This has a few benefits: it lowers the power usage (thus lowering the chance of brownouts), lowers the idle temperature, and overall makes the clock more stable. This can be done at the firmware level (by editing config.txt in the boot partition) or in the OS level by changing the OS-defined CPU governor to userspace. This can easily be done through the
- Use an operating system with low overhead. I'm a big fan of DietPi. Raspberry Pi OS Lite, Alpine, or Arch are also suitable, but you may experience configuration challenges. All of my writing assumes DietPi and applies to Pi OS as well. Alpine and Arch are very different.
- Set a static DHCP address assignment, same as any other server should have.
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
Verify Operation and Troubleshooting
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
pps-tools installed on the server to perform some of these tests.
Basic UART operation
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.
UART from the GNSS
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!
GPSD and GNSS operation
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
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.
Verify that your clients can get a valid response from the server. On windows I am fond of NTP Check