NTP Server via DCF77 on a Raspberry Pi

In this tutorial I will show how to set up a Raspberry Pi with a DCF77 receiver as an NTP server. Since the external radio clock via DCF77 is a stratum 0 source, the NTP server itself is stratum 1. I am showing how to connect the DCF77 module and I am listing all relevant commands as a step by step guide to install the NTP things. With this tutorial you will be able to operate your own stratum 1 NTP server. Nice DIY project. ;) However, keep in mind that you should only use it on a private playground and not on an enterprise network that should consist of high reliable NTP servers rather than DIY Raspberry Pis. Anyway, let’s go:

This article is one of many blogposts within this NTP series. Please have a look!

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) Connecting the DCF77 Module

At first you need a DCF77 module in order to receive the radio clock from Germany. I used the “Conrad” module. It needs a pull up resistor with 3-10 kOhm between ports 2 and 4 (VCC and DCF-). Have a look at the PDFs from the Conrad store that show the port assignment, as well as this two german pages that give several hints. Long story short: use three cables:

  1. DCF77 module port 1 (GND): Pi pin 9, GND
  2. DCF77 module port 2 (VCC): Pi pin 1, +3.3 V
  3. DCF77 module port 3 (DCF+): not used
  4. DCF77 module port 4 (DCF-): Pi pin 10, RXD0 (UART)

I first soldered the cables directly to the Pi, while I later added a 3,5 mm jack to the housing of the Pi with a 2 meter cable on the DCF77 module:

2) Installing NTP w/ DCF77 Support

The first step is to install NTP with the support of DCF77. This is not the case if you’re simply doing a sudo apt-get install ntp. Anyway, please install the NTP server with this command first in order to have the startup scripts in place, etc. After that you need to build NTP from source (note the “–enable-RAWDCF” option) which involves the following steps:

(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:

 

3) Leveraging the Serial Port

At first you must disable the serial port of the Pi while keeping the port hardware enabled. Open 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 when exiting raspi-config.

A very basic test with “screen” should indicate some output, though completely useless:

Add the user “ntp” (which runs the ntp daemon) to the “tty” group in order to have access to the tty console. Verify it with the second command shown below:

In order to have a symbolic link to /dev/refclock-0 (which is needed by NTP later), add the following three lines to the init script from NTP, while commenting out the latter three lines sudo nano /etc/init.d/ntp :

Reload the systemctl and restart the NTP process:

Verify that the symbolic link is present:

Now you need to use driver number 8 from the NTP software in “mode 5” for the Conrad DCF77 module. That is: Open the ntp configuration file:  sudo nano /etc/ntp.conf and add your “server” aka DCF77 module in the following way:

I have commented out the default “pool 0.debian.pool.ntp.org iburst” lines but entered a few IPv6 enabled servers as well, though without the “prefer” option:

Finally, restart the NTP daemon: sudo service ntp restart.

Now, in theory, the DCF77 receiver should work, but only if you have a good radio signal and quality and correct angle of the antenna, which was not the case in my scenario at the first time. Use “ntpq -p” to print a list of NTP servers that are in use. As you can see in this example, the “GENERIC(0) .DCFa.” server (first line) was never reached so far:

Have a look at the syslog messages. If they list something like this, you don’t have a good signal quality, while the receiver at least works in general: ;)

Note that the DCF77 receiver must point orthogonal with its longer side to Mainflingen, Germany, which is south-east of Frankfurt. (Fun fact: Since I am living just a few kilometers in the north of Frankfurt, my actual direction of the receiver must not show to Frankfurt directly, but more precisely to Mainflingen. However, for almost everyone else the receiver must simply “look” into Frankfurt.) Furthermore, you must omit any interfering/disturbing sources such as switching power supplies or the like in the room where your receiver resides. At its best, the receiver is placed outside a building (waterproof, lightning protection!), which is not that easy at all. In addition I came across some weird observations, since my signal quality was way better as I turned the antenna just a few degrees in one direction. TL;DR: If you’re lacking signal quality, try a few different positions of your antenna. Be creative. ;)

If you have a good signal strength and quality, the ntpq -p output should look like this, in which the “GENERIC(0) .DCFa.” source has a reach of 377 while the * symbol indicates, that it is used as the system peer:

 

4) Adjusting the Fudgetime

You need to adjust the fudgetime of the DCF77 receiver which is the compensation of the offset from the radio clock to the “real” time. That is: You need to compare the time received from your DCF77 module to some other working NTP sources. The offset should be minimal after that.

Without any “fudgetime” options in your ntp.conf file, the “RAW DCF77 CODE (Conrad DCF77 receiver module)”, as it is called by NTP, has a built-in fudgetime1 of 292.000 ms. You can see this with “ntpq -c cv”, since it “displays a list of clock variables for those associations supporting a reference clock”:

After some time running NTP you will see either this, in which all other NTP servers have a comparable but huge offset (in this situation about 590 ms, while the DCFa receiver is not used due to the “x” in the first column):

or this, in which all other NTP servers have a low offset, while the DCFa receiver has one with a much higher negative value (while still not used):

–> Now you need to adjust the fudgetime1 to compensate this difference. In my case, since the pre-configured fudgetime was 292 ms while my offset of the DCF77 receiver was about -592 ms (hence needed an even higher compensation), I had to add a fudgetime1 of 292 + 592 = 884. Open the configuration file again: sudo nano /etc/ntp.conf and add the following below your “server 127.127.8.0 […]” line:

Followed by a restart of NTP: sudo service ntp restart.

A couple of minutes later you should have very small offsets among all NTP servers, the external ones as well as your DCFa receiver:

Very good! You’re almost done.

5) Reducing Ethernet Latency

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

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

Links

This post used several information from a couple of (german) articles and posts:

Featured image “dcf77 module-stapel” by ledmaster33 is licensed under CC BY-NC 2.0.

Leave a Reply

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