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. [UPDATE Oct 2021: I updated some commands and procedures. I am still using a Raspberry Pi 1 B but with Raspberry Pi OS 10 (buster), kernel 5.10.63+. If you’re using a Raspberry Pi 3 or later, you must replace “ttyAMA0” in this tutorial by “ttyS0”.]

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 these 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 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 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 “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 /usr/lib/ntp/ntp-systemd-wrapper : [Thanks to the comment from Thomas for keeping it up-to-date.]

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 systemctl restart ntp.service.

Now, in theory, the DCF77 receiver should work, but only if you have a good radio signal and quality and the 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 kilometres 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 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 for 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 systemctl restart ntp.service.

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, the 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.

23 thoughts on “NTP Server via DCF77 on a Raspberry Pi

  1. Hello Johannes ,
    I’m wondering if building NTP from sources is really necessary. Why are you doing this ?
    Many thanks for your tutorial, very clear :)
    Regards

    1. Hey Pete,

      using the ntp packages via “apt install ntp” misses the driver for the raw DCF77 receiver. Hence, you need to install it from sources. Especially this line for configuration:
      ./configure --enable-RAWDCF --prefix=/usr
      Otherwise you won’t be able to use those DCF77 receivers.

      And in general: Only when installing/updating the ntp packages from its source, you are getting the most current (and bug-fixed) versions.

      1. Hello Johannes,

        At the time of writing (Apr 2020) I am also using an old Raspberry Pi 1 B, kernel 4.19.97+ and Raspbian GNU/Linux 10.3 (buster).

        The install of ntp from Debian packages “apt install ntp” works :)

        I started this project a long time ago (3 years). I recently decided to re-install the Pi, so I re-started using old tutorials (the “2 german pages” indeed).
        I have followed your tutorial starting with §3 : this is why I missed the ntp installation from sources …

        => Do you know if possible to check the Debian’s package configure options ?

        Thanks again for your tutorial :)
        Regards

          1. Many thanks Patrick, exactly the info I was looking for :)
            That’s perfectly clear now !
            Best regards
            Pete

      2. Hi.
        I’m using a Symtrik-RFT-77 module directly connected to the GPIO of a RPI. The reference signal is another RPI with a DCF77 transmitter program from Andreas Spiess, that is working OK, setting the correct time on several DCF77 clocks.
        My problem: I can’t get the /dev/refclock-0 after the modification of the /etc/init.d/ntp file and restart of the NTP service.
        I only can see the RPI getting data from the DCF77 receiver, if I do a manual command “sudo ln -s /dev/ttyAMA0 /dev/refclock-0”. But after a reboot, I have to give that command again.
        What did I do wrong?

        1. Bad results…
          Aug 27 11:19:00 RPI-DCF77-Receiver ntpd[24248]: parse: convert_rawdcf: start bit / parity check FAILED for “###############RADMLS1248124P124812P1248121241248112481248P”
          Aug 27 11:20:00 RPI-DCF77-Receiver ntpd[24248]: parse: convert_rawdcf: start bit / parity check FAILED for “###############RADMLS1248124P124812P1248121241248112481248P”
          pi@RPI-DCF77-Receiver:~/ntp-4.2.8p15 $ ntpq -c cv
          associd=0 status=0012 1 event, clk_bad_format,
          device=”RAW DCF77 CODE (Conrad DCF77 receiver module)”,
          timecode=”###############RADMLS1248124P124812P1248121241248112481248P”,
          poll=6, noreply=0, badformat=1, baddata=0, fudgetime1=292.000, stratum=0,
          refid=DCFa, flags=0, refclock_time=””, refclock_status=””,
          refclock_format=”RAW DCF77 Timecode”,
          refclock_states=”NOMINAL: 00:00:39 (10.15%); *BAD FORMAT: 00:05:45 (89.84%); running time: 00:06:24″
          pi@RPI-DCF77-Receiver:~/ntp-4.2.8p15 $

          1. Hey Rui,

            yes, I had bad results for days and days, until I changed the position of the antenna! The DCF77 signal was disturbed by other signal noise. As I placed the antenna outside my room, the signal was perfectly fine.

            Ciao
            Johannes

        2. Maybe a little bit late, but I had the same problem. So the answer may be helpful for others: It seems that this is because Raspian uses now systemd as init process. I’m not an expert in this topic, but for me it seems that there are the “old” init scripts in /etc/init.d but they (or at least the ntp script) are no longer used.
          Therefore, the change of /etc/init.d/ntp has no impact. Instead, the file /usr/lib/ntp/ntp-systemd-wrapper (this file is called by /usr/lib/systemd/system/ntp.service) should be modified. The modifications are the same than in /etc/init.d/ntp .
          What I don’t know is whether there can be situations where /etc/init.d/ntp is executed anyway. To be safe, I modified both files and it worked for me.

          @Johannes: Thank you very much for this great tutorial. Maybe you could verify my answer and add this to the tutorial?

          1. Uh, kann gut sein, dass mein Tutorial hier schon wieder veraltet ist. Das geht ja leider schnell. :( Danke dir für den Hinweis! Wenn ich irgendwann mal dazu komme und die Schose noch mal aufsetzen werde, werde ich das korrigieren. Don’t wait for it. ;)

  2. Johannes,

    are you saying, that your setup has a delay from antenna to Raspi calculating the actual time of almost one second? That would scare me.

    >fudge 127.127.8.0 time1 0.884

    Fabian

  3. Thanks a lot for the how-to.

    I have a Gude ‘Expert Mouse Clock 0107’ (DCF77, USB) device connected to a Raspberry Pi 3 with Raspbian 10.4.

    What I don’t understand…

    After installing ntp via ‘apt-get ntp’ (currently ntpd 4.2.8p12) I’ve configured the device with ‘server 127.127.8.0 mode 19’ in /etc/ntp.conf. After some time ntpd automatically selected it as preferred source in ‘ntpq -p’.

    The output of ‘ntpq -c cv’ contains
    ‘RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)’ and
    ‘refclock_format=”RAW DCF77 Timecode’.

    So, why do we have to compile ntp with ‘–enable-RAWDCF’?

    1. Uh, interesting. Maybe it is compiled with RAWDCF support by default.

      At least if you want to update your ntp version to the lasted one, you have to do it manually anyway. The current version is 4.2.8p15. The operating systems are not updating their versions of ntp to the newest one by themselves. ;( Refer to: https://weberblog.net/updating-ntp-servers/

      Cheers
      Johannes

    2. Got it… using ‘–enable-all-clocks –enable-parse-clocks’, that’s the default for the Debian ntp-package, automatically enables RAWDCF (=> no need to use ‘–enable-RAWDCF’).

  4. Okay so I am also using the Raspberry Pi 1 B, kernel 4.19.97+ and Raspbian 10.3.
    Can you please tell me is building NTP from sources is really important!
    Thanks for your help.

    1. At the time of writing, it really was mandatory to get the DCF77 support. I don’t know if this has changed in the meantime. (Using GPS as the time source is more common, hence this driver is enabled by default, while DCF77 is not.)

      Anyway, if you’re using the NTP server (aka Raspberry Pi) for the public Internet, such as the NTP Pool, you should update the software on a regular basis to not have any security issues, etc. See: https://weberblog.net/updating-ntp-servers/
      At the latest then you have to build it from the source…

Leave a Reply

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