Posted on 52 Comments

Raspberry Pi Buster – GPS Dongle as a time source with Chrony & Timedatectl

UPDATE 17-12-21: Sean (see comments below) has noted that, when using these instructions with the latest OS, the operation fails unless you comment-out  (prefix line with #) START_DAEMON=”true” in the gpsd config file. I will run some checks here and develop modified instructions.

The latest release of Raspberry PiOS for the Pi has replaced the familiar NTP application with a lightweight solution using timedatectl. As a result, many of the online tutorials for adding  a GPS USB dongle are out of date.

After some experimenting, I have devised the following process:

For my tests, I was using the Diymall VK-172 GPS dongle that’s available from Amazon UK for £12.95. This is a ublox 7020 based dongle.

Start with a fresh download of Buster and do the usual sudo update/upgrade to get the latest patches.

1 — Install the following software:

sudo apt -y install gpsd gpsd-clients python-gps chrony python-gi-cairo

2 — Next step is to make some changes to the gpsd configuration file as follows:

sudo nano /etc/default/gpsd

3 — In the file that opens, add or amend lines to make sure the following is present:





Hit ctl-x followed by y to close and save the file.

4 — Reboot the Pi and check that the following services are active:

systemctl is-active gpsd

systemctl is-active chronyd

5 — You can use any of the following three commands to check that the GPS is visible and delivering NMEA words. NB: Most GPS dongles will show a flashing LED when they have a fix:

cgps – s   or   gpsmon -n  or   xgps

6 — Next, we need to make a change to the chrony configuration file:

sudo nano /etc/chrony/chrony.conf

Add the following line to the end of the file:

refclock SHM 0 offset 0.5 delay 0.2 refid NMEA

Hit ctl-x followed by y to close and save the file.

7 — You can now check chrony’s sources with the command:

chronyc sources -v

If you are connected to the network, you will see a list of available time servers plus the GPS source which will be shown as NMEA. If you’re not network connected, you will just see the NMEA source listed. The two punctuation characters immediately before NMEA, indicate its status and you need to see #* where # means thge GPS is recognised as a local clock and * means that it’s being used to synchronise the Pi system time.

8 — You can now use chronyc to provide a more detailed view using the command:

sudo chronyc tracking.

This will confirm that NMEA is being used as the reference and will list the time difference between the reference and the system clock. To avoid clock jitter that can cause lots of software problems, chrony slowly changes the system clock until it matches the reference. However, this makes for a very slow synchronisation.

9 — If you want to quickly synchronise the time, use the following command to make a step change to the system clock:

sudo chronyc makestep

Operational Notes

If you boot the Pi with a network connection, chrony will automatically sync to the time server with the shortest propagation delay. If you remove the network connection after boot, it will take a while for chrony to switch back from the network server to the local GPS. This is because Chrony makes repeated attempts to reach what it considers to be the best timeserver. The simplest way to overcome this delay is to reboot the Pi without a network connection. It will immediately revert to using the NMEA (GPS) data as it’s the only timing source available.

NB: Pi Pixel Clock Update Delay – Please note that the PIXEL desktop clock (top right corner) only synchronises with the system time every 5 minutes. As a result, updates to the system time can take up to 5 minutes to permeate to the desktop clock! The most reliable way to check the system time is to use: sudo timedatectl. This shows all the vital timing detail and synchronisation with GPS USB dongle is indicated when the ‘NTP Synchronized’ entry reports yes.

Here are some useful time-related commands:

sudo date -s “Aug 7 09:15” – Manually sets the system time and is useful when testing RTC and GPS units.
sudo hwclock -w – This command updates the RTC with the current system time. Use this when you are connected to a network and want to force the RTC to sync with network/system time.
sudo hwclock -r – This displays the current RTC time and is useful for checking the RTC.
sudo hwclock – s -Sets the system time from the RTC
sudo hwclock –set –date ”8/11/18 15:24:00” Manually sets the RTC time and date – useful for testing.
sudo timedatectl – Displays the status of all the Pi clock sources.
sudo chronyc makestep – Forces the system time to make a step change to the reference time, i.e. GPS. This avoids the time lag caused by chrony incrementally adjusting the clock.

Mike Richards – G4WNC

52 thoughts on “Raspberry Pi Buster – GPS Dongle as a time source with Chrony & Timedatectl

  1. Hello Mike
    Absolutely brilliant tutorial!
    Julian oh8stn

    1. Hi Julian,

      Thanks for the feedback. Glad you found the tutorial useful. Mike – G4WNC

  2. Hello Mike,
    been very helpfull, works great, thanks a lot.
    73 de Marc, ON4BBD

    1. My pleasure. Mike – G4WNC

  3. Agree great tutorial. Just followed it and got my pi synced with gps dongle in about 30 minutes with wi-fi off. Setting up a field ham radio station on a pi. Software need exact timing to communicate successfully. Thanks from Horace Hinson KI5WA

    1. Hi Horace,

      Glad you found it useful. Mike – G4WNC

    It’s great to be learning from others, Thanks for taking the time to help others with GREAT step by step instructions that WORK! I barely know how to get my Pi turned on and I followed these instructions and Bam! gps setup.. Done!

    on to Digi modes 73,

    1. Excellent – glad you found it useful. Mike -G4WNC

  5. First of all thanks for the excellent tutorial. I followed the steps on my rpi and everything went smooth on the installation. My GPS is working fine, I see the blinking light, the time update, the NMEA data and all that good stuff.

    My issue now is that when I go to JS8Call or WSJT-x it gives me the following error and is not connecting to the radio.
    “hamlib error io error while opening connection to rig”

    Writing to see if this is something any of the other members have seen before and may have any suggestions for me to try.

    some notes –
    js8call was working OK before installing the gps.
    The radio hardware and js8call settings are the same as before the gps.
    Everything works fine after un installing the gps.


    1. Hi Norbert,

      This is a bit of a mystery!

      I followed my own instructions to install the GPS and tried WSJT-X and saw the same failure. A quick investigation showed that the USB serial port used for CAT had disappeared. You can check this using the command: ls /dev/tty* This lists all the tty devices and the USB CAT port would normally show as /dev/ttyUSB0.
      I then burnt a new sd card and went through the GPS install process step-by-step. At each step, I checked to see if the ttyUSB0 device was still present. It remained present throughout the process and I couldn’t replicate the fault.
      I even tried burning another card and installing from the instructions without any checks and all was well.

      At the moment I’m a bit stuck as I can’t replicate the problem here.

      It may depend on whether the CAT and GPS dongles are plugged in during the install.

      I’ll have another go in the morning

      Mike – G4WNC

  6. Hi, I got same problem as Norbert with my CAT cable on FT-897 but now something else happening and no idea how to solve.
    GPS working fine but off network won’t synchronize NTP anymore.
    Now of course the JS8Call in itself working fine.
    Tried all again with new card and again CAT problem with GPS running.
    It doesn’t make any difference if you are running on or off network.
    ttyUSB0 still there too.
    It seems things go wrong when GPS synchronizes NTP.

    1. Hi Kees,

      Sorry to hear you’re having problems. I’ve been trying to replicate the problem here without success.
      I’ve just created a new data modes card with FLDIGI, WSJT-X and QSSTV installed. I updated the OS to make sure I had all the latest fixes and installed GPSD and Chrony as per my blog instructions and all is working ok. I have the time derived from the GPS dongle with the network disconnected and rig control is still working on all three decoders.
      Are you using the latest OS and data modes software? Also are you using the same GPS dongle as in the blog?

      It’s hard for me to fix the problem is I can’t replicate it here.


      Mike – G4WNC

      1. Found a solution for the problem.
        Maybe someone more familiar with Raspbian comes up with an easier way.
        After trying 3 cards on 2 pi 3’s and 1 pi 2 and which all gave same troublem, even without a gps actually connected I finally came to this solution which works for me.

        Switch off hotplugging by changing gpsd file to USBAUTO=”false”
        When Raspberry-Pi is running start xps and only then the system clock updates to GPS time.
        After this JS8Call working fine.

        regards, Kees

        1. Hi Kees,

          Thanks for that fix. I know it’s far from ideal, but it gives me a useful clue as to the source of the problem. I’m away at the RSGB Convention this weekend but will dig deeper when I get back.


          Mike – G4WNC

  7. Hi all,
    From reading these posts and it seems all my edit lines are Ok as far as chronyc, gpsd and such, my Ublox doesn’t blink except blue when first plugging it in. I am in an apartment so suspect poor satellite view. Is it possible that the network time overrides the gps until I’m either outside and out of range so it forces the gps for clock info? Also have the Pi Juice hat on as well…Do I simply wait for the data card I ordered and see how that plays?…

    1. Hi Jay,

      Chrony will pick the most accurate time source that it can find. In the case of using a USB GPS dongle, the network NTP servers will usually provide better accuracy due to USB processing delays. The use of a USB GPS dongle is really only intended for those situations when you’re off the grid but need to get the time. USB GPS accuracy is usually around 1/2 second. To get the benefit of very accurate GPS time, you need to use a dedicated GPS board with a 1 pulse per second output (PPS). Whilst the serial data from the GPS provides the high-level time/date data, the PPS pulse provides micro-second accuracy. There is currently a problem when using a USB GPS plus Chrony with FT8Call that causes the USB port to disappear, I’m investigating that problem at the moment. A temporary fix is to change the USBAUTO line in the GPSD config file to false (see note from Kees).
      If you have another PC handy you could try connecting your GPS to that computer. If there’s enough signal the GPS will provide a 1 second flash once it has a fix.


      Mike – G4WNC

    2. Hi Mike,

      >my Ublox doesn’t blink except blue when first plugging it in.

      When you first supply power to the GPS module (called a “cold start”), it can take many minutes for the GPS module to locate satellites and download the “GPS almanac”.

      If you suspect that your GPS receiver is not able to get sufficient signal because it is indoors, can you try moving the GPS receiver so that it is near a window? Having a view of the sky through a window is enough for a GPS receiver to receive data from satellites, download the almanac and ultimately create a fix for your position.

      Once you get the GPS receiver working, you’ll notice that if you reboot your PC without powering it off, the GPS receiver will achieve a fix much quicker. This is called a “warm start” and the GPS receiver uses info it has recently received to find the satellites in the sky.

      As Mike mentioned, a USB GPS receiver will provide “GPS time” down to the second. This can be useful if you don’t have Internet connectivity.

      >Is it possible that the network time overrides the gps until I’m either outside and out of range

      Yes, that’s exactly right. Chrony or ntp will use the time info received over the Internet before it uses the time info from the GPS receiver as the time received from Internet time servers is more accurate (millseconds or even microseconds) than the time received from the USB GPS module.

      Mike mentioned the solution to “microsecond-level time sync” in his reply to you. You would need a GPS receiver that can supply a PPS signal to your Pi in addition to supplying the “which second is it now?” time. The PPS signal is like the ticking sound from a wristwatch: The PPS signal tells the Pi “the second begins NOW”.

      I hope this info is helpful and that you’ll gotten your GPS receiver to “see the sky”.

  8. Hi Mike and thanks for the tutorial. My main aim was to test a GPS dongle, which I was attempting to use in an Ubuntu MATE / INDI server astronomy application on a RPi 3 B+ where as you point out in your other blog entry Ubuntu MATE is not (yet) officially supported. So it was great to explore your suggestions for checking the functions on the Raspian distro before discarding the dongle.

    1. Hi Ed,

      Glad you found it helpful. Mike

  9. Great tutorial, many thanks Mike!

  10. This helped me get going, thanks! I *did* have to wait overnight for the GPS dongle to DL an almanac and start green flashing indoors but now it’s OK. On the way to a 20m CRKits build for FT8 for use with a Elecraft AX1 20m loaded whip or SOTAbeams End Fed or Bandhopper, depending on loaction and space available.


  11. Hi Mike

    Fantastic tutorial, found it through Julian’s YouTube) and able to get my dongle up and running in a good half hour (taking it slow and double checking)

    One problem – running “xgps “ I get an error (multiple in fact) of “TypeError : Couldn’t find foreign structure converter for ‘cairo.Content’ “

    Using a Pi 3B+, Raspbian Buster (done the “apt get and upgrade)

    Any ideas??

    1. To Phil (and al)
      This is due to Debian (then to Raspbian, then to Raspberry Pi OS …) which forgot a dependence required by gpsd-client “xgps”. Easily corrected with :
      sudo apt update
      sudo apt install python-gi-cairo
      Shouldn’t be required if you followed the steps of this excellent tutorial

  12. I just followed your excellent tutorial on an new Pi 4 and had the following error when trying xgps:
    TypeError: Couldn’t find foreign struct converter for ‘cairo.Context’
    After some google searching I fixed it with:
    sudo apt-get install python-gi-cairo


    1. Hi Larry,

      Glad you found the tutorial useful. I’ll add the cairo addition to the instructions.



  13. Mike, interesting to read the differences on adding GPS time to a Raspberry Pi (RPi) as described in your May 2018 Practical Wireless article, your book RPi Explained for Radio Amateurs, pages 144 to 146, and the above blog. I see you have added python-gi-cairo software in the above blog, what does this do. Please also note that your book page 146 has refclock SHM0 not refclock SHM 0, i.e. no spacebetween SHM and 0. Chris

    1. Hi Chris,

      As you’ve spotted the project has evolved thanks to comments from users. The addition of python-gi-cairo is now a prerequisite of GPSD. It seems some of the GPSD source code is written in Go and python-gi-cairo provides Go support.
      Thanks for spotting the book error; i’ll add that to the erratum.



  14. I have completed the steps in this tutorial and after issuing the command “systemctl is-active gpsd” “inactive” is returned. Can anyone give me any ideas for making the gps active?


    1. Hi Tim,
      This usually works fine. First thing to try is reboot and then use the following commands in a terminal session to get a few clues as to what’s happening.

      The following will get the latest status info from gpsd:

      sudo systemctl status gpsd

      This will force a restart of the service if it was idle.

      sudo systemctl restart gpsd

      This will show any system messages related to the gpsd service.

      sudo journalctl -u gpsd.service

      If that doesn’t provide any clues, do the following:

      Open 2 terminal windows.
      In one window start monitoring all system messages related to gpsd by entering:

      sudo journalctl -u gpsd.service -f

      In the second window enter:

      sudo systemctl restart gpsd


      Mike – G4WNC

  15. Thank you for putting together such an easy to follow tutorial. I have set up a couple of RPis following this guide and they are working perfectly.
    I have run into an issue with my latest project though. Using the Official Raspberry Pi 7″ Touchscreen via the DSI interface, my GPS Dongle will not get a fix. If I swap to an HDMI display, everything works as expected.
    I have tried 2 different GPS dongles on RPi 4 and RPi 3B+ with the same results. Anyone have any ideas?

    1. Hi Ty,
      Glad you enjoyed the tutorial. I’ve not used a GPS dongle with a touchscreen so haven’t encountered the problem. You could try using a USB extension lead to move the GPS dongle away from the Pi/touchscreen in case it’s an interference issue.

      Mike – G4WNC

  16. Hi Mike,
    after spending a lot of time with ntp and GPS (never worked together) I tried your tutorial and now my Raspi get’s the correct time via GPS after boot.

    Well done!

    Regards, Mirko

    1. Hi Mirko,

      Glad to hear you found it useful.


      Mike – G4WNC

  17. Further than I’ve made it with any other tutorials!
    On the chronyc sources -v
    The NMEA is returning the # x which is telling me time may be in error.
    I did change the /lib/systemd/system/gpsd.socket ListenStream= to

    73, Greg

  18. i@raspberrypi:~ $ sudo chronyc sources -v
    210 Number of sources = 5

    .– Source mode ‘^’ = server, ‘=’ = peer, ‘#’ = local clock.
    / .- Source state ‘*’ = current synced, ‘+’ = combined , ‘-‘ = not combined,
    | / ‘?’ = unreachable, ‘x’ = time may be in error, ‘~’ = time too variable.
    || .- xxxx [ yyyy ] +/- zzzz
    || Reachability register (octal) -. | xxxx = adjusted offset,
    || Log2(Polling interval) –. | | yyyy = measured offset,
    || \ | | zzzz = estimated error.
    || | | \
    MS Name/IP address Stratum Poll Reach LastRx Last sample
    #x NMEA 0 4 3 18 -445ms[ -444ms] +/- 100ms
    ^- 1 6 76 133 -403us[ +601us] +/- 52ms
    ^* 2 6 177 10 +527us[+1755us] +/- 16ms
    ^- 2 7 122 132 -2417us[-1410us] +/- 61ms
    ^? 1 8 0 470 -220us[ +442ms] +/- 59ms
    When I disconnect my network connection the network NTP servers are obviously not seen. My RPI picks up the NMEA and uses it as the source. After I reconnect to the network and given some time my GPS Dongle no longer becomes the source but another web based timer server.

    Is there any way to explain this? Is the dongle drifting that much to have it dropped as a source?

    Help me understan.

    Kurt – W2MW

    1. Hi Kurt,
      Your installation is working correctly because a USB connected GPS dongle is only accurate to about 1/2 second. An online NTP server will always be more accurate than the dongle, so the Pi should switch back to NTP when it reappears.

      The limited accuracy of a GPS dongle is caused by USB processing delays due to Linux being a multi-talking operating system. For accurate GPS timing you need to use a GPS add-on board that includes a Pules-Per-Second (PPS) signal. Whilst the NMEA data provides the date, hour, minute and second information, the PPS signals the precise start of each second.

      Mike G4WNC

      1. Thank you Mike for your response. Now that makes a bunch of sense. One of the reasons why I wanted the GPS was to be able to use some of the digital modes like FT8 and have a good time source to operate those digital modes.
        HNY es 73;
        Kurt – W2MW

  19. Thanks. Very useful. We seemed to need reboot after editing the chrony.conf file in step 6. We are hoping to use this to provide reliable time to a Pi that is recording the night flight calls of migrating birds in a location without internet.
    Laura (N8NFE) and David (AD8Y)

  20. Hi Mike, not want to teach you how to suck eggs but just so you know, you dont need to reboot each time you change a config file.

    You can just issue a systemctl restart (service) where service name is the systemd service name of the file you have just edited, eg…
    systemctl restart chrony or systemctl restart gpsd

    Saves a hell of a lot of time if you are experimenting and making a lot of changes.

  21. Hi Mike
    Thank you for the succinct piece I wish everyone could publish in same vein.
    My plan is to get time from GNSS in to my Pi4 (Latest Raspberry Pi OS) so that I could dispense with Internet connection(s) particularly when I am out /P contesting.
    I also use Minos on the Pi and thought I had it all sorted in time for VHF Field Day BUT when I came to check the portable set up on the Friday evening I found although gpsd was running I had lost communication between the Pi and Minos.
    My lack of RaspeberryPi/Linux knowledge coupled with the time left meant that I could not “crack the code”. Having read that GPSD can cause USB issues I put this down as the cause.

    Last night I went through your set up procedure and followed suggestions here:
    and (last night)I had systemctl is-active reporting “active”
    This afternoon systemctl is-active is reporting inactive but I am able to run xgps and see satellites

    However I cannot get the system clock to update; sudo chronyc makestep returns 200 OK
    ~ $ sudo hwclock -s
    hwclock: Cannot access the Hardware Clock via any known method.
    hwclock: Use the –verbose option to see the details of our search for an access method.
    pi@raspberrypi:~ $ sudo timedatectl
    Local time: Sat 2021-07-03 01:51:22 BST
    Universal time: Sat 2021-07-03 00:51:22 UTC
    RTC time: n/a
    Time zone: Europe/London (BST, +0100)
    System clock synchronized: no
    NTP service: inactive
    RTC in local TZ: no
    Bit lost, hoping you can help

  22. Excellent thank you

    1. Glad to be of help. Mike – G4WNC

  23. Hi,
    I love this blog item because I wouldnt know hot to set up gpsd or chrony with out it. I have used your settings to set up al my Rpis and my linux computers.

    However recently something has changed on my Linux and Rpis so that gpsd and chrony no longer work.

    The problem is cured by editing /etc/default/gpsd

    # START_DAEMON=”true” ( Comment this line out )

    This works on all my RPis and Linux .

    Please keep up the great work!

    Seán Mac Suibhne

    1. Hi Sean,

      Glad to hear you find the post useful. I’ll add a comment about your findings.


      Mike G4WNC

  24. Sorry I see I introduced a typo there at the end of the third line.
    Replace the ? with a ”
    # START_DAEMON=”true” ( Comment this line out )

  25. This helped a lot! Especially the part about commenting out “START_DAEMON” and simply adding “refclock SHM 0 offset 0.5 delay 0.2 refid NMEA” to chrony’s config did the trick!

  26. Hi Mike, thanks for the tutorial! I have cgps working, chronyd and gspd active, but only as long as I don’t have the reflock line in chrony.conf. I am having an issue when I add the reflock line to the /etc/chrony/chrony.conf file. It tags the reflock line as “invalid directive”, whatever that means.
    My /run/gspd.sock file is empty, always. What is the purpose of this file? What should it contain?
    My device is a USB dongle by TSI (GM-3N) based upon the MTK MT3333 chip. It does not support PPS outputs via NMEA (firmware is too old).

    1. reflock, oh, should be refclock!!

  27. Used this with Raspi OS 64. Everything is going fine, python-gi-cairo can no longer be found, but doesn’t prevent xgps to work. Probably integrated in Debian 64 at last …
    The only little issue I met, is that after a reboot, I will first get in answer to the ‘chronyc sources -v’ command the following : ‘#? NMEA …’ repeatedly until I use a gpsd client, e.G. cgps, then I will find the so awaited for ‘#* NMEA …’
    Even interrogating ‘sudo systemctl is-active gpsd’ is enough to make everything all right.
    Most probably the source of the issue is in gpsd itself, as I had allready seen the same phenomena in OpenCPN (need to launch a gpsd client before getting any NMEA data in OpenCPN

  28. Hi Mike

    Installed GPS as per your instructions and seems to work fine. However, a direct side-effect of installing the GPS software is that Flrig is now unable to communicate with my IC7100.
    This appears to be caused by a USB conflict, but not sure how to resolve it. Have you encountered this issue and can you suggest a resolution?

    73 de Roger.

    1. I had the same issue. Rig on /dev/ttyUSB0 and GPS on /dev/ttyUSB1, the problem seems to be when gpsd starts on system boot it locks up /dev/ttyUSB0 and the radio wont work. I found restarting gpsd would fix it, or another possibility might be to let gpsd use USB0, and configure the radio on USB1.

      You can see which dev has been assigned by looking at dmsg output after connecting the device.

      1. I figured out the problem with this, this is how I solved it:

        Plug the GPS in

        sudo dmesg

        Note the /dev/ttyUSBx device name the GPS was mounted with.

        ls -l /dev/serial/by-id/

        Note the name of the link pointing to the /dev/ttyUSBx device name.

        sudo apt-get install gpsd gpsd-clients

        Edit /etc/default/gpsd to match

        GPSD_OPTIONS=”-n -G -b”

        DEVICES matches the GPS serial link name, one line.

        USBAUTO=”false” disables hot plugging. If enabled (true) gpsd will attempt to get GPS data from any serial device that is connected and prevents other applications from accessing the port, including the radio USB port!

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.