This post is part of [tj]’s blog more in June challenge. You should join us and take part - just make 4 posts in June!


As part of the general move to do more radio / do radio in a field, I’m configuring a raspberry pi to be a permanent companion to my radio.

One challenge of the pi is the lack of an RTC, and this isn’t something I’m particularly fussy about fixing with dedicated hardware - typically it’s quite expensive.

I have a portable USB GPS dongle that I’d like to use for APRS/other position data (cgps displays your Maidenhead locator!), so I might as well make that a permanent fixture and derive system time from GPS. I can’t trust ntp pools, as I probably won’t have internet where I’m using it.

On the surface, this is quite an easy task:

apt install gpsd gpsd-clients ntp and edit some config files.

Unfortunately, it wasn’t quite so easy.

I ran into two stumbling blocks:

Shared Memory

gpsd seems to share time data with ntp via shared memory. Raspberry Pi OS’s default configuration has apparmor enabled, which was preventing ntp from accessing this.

I had to edit /etc/apparmor.d/tunables/ntp to contain my GPS device - it now reads:

@{NTPD_DEVICE}="/dev/ttyACM0

I checked that there were entries in the shared memory using ntpshmmon as root, and I could see slot NTP0 populated. That’s my GPS’ time coming through.

NTP Driver Flags

Following the documentation, I commented out the pool timeservers in the /etc/ntp.conf and after too much experimentation added the following:

# GPS Serial
server 127.127.28.0
fudge 127.127.27.0 refid GPS flag1 1

I had to go hunting to learn what flag1 1 did - up until I added that, nothing worked at all. According to the manpage, the ntp flag1-4 are controls for different drivers for ntp.

As I’m using the SHM driver, the documentation for that tells me that the default mode of operation is to discard the new time if it’s +/- 4 hours from the current system time.flag1 1 disables this check. Given the pi can be off for days at a time, this seems like a sensible default for me.

Everything works and has survived reboot. It takes a few minutes for the time to be set by GPS, but it always catches up.

During this I went down a few false rabbit holes, the most useful lesson from that being: changing the ntp user in /usr/lib/ntp/ntp-systemd/wrapper to root didn’t fix anything and is probably unwise for system hardening.