Rebuilding a 1995 GPS Time Server so I don't get Telstra'd

Sep 05, 2026 10:22 PM - 1 week ago 4

In June I purchased this TrueTime XL-AK clip server, truthful I could study much of the history of GPS-based time.

I received it connected June 22, and conscionable 16 days later a akin GPS clip server took down Australia's compartment work for 12 hours! I made a short video astir it but put disconnected digging into the TrueTime... until now.

TrueTime XL-AK pinch Pi wrong moving Densitron LCD

Over the past mates weeks, I've 'restomodded' this instrumentality pinch a Raspberry Pi, to build a stratum 1 NTP Time server, which I'd for illustration to yet adhd to the NTP Pool. I recovered a measurement to driblet successful a Pi 5 and GNSS HAT, show the clip and GPS position connected the built-in 16x2 LCD, show the position connected the bicolor LED, and make this container useful again.

I laic retired much of the hardware specifications successful today's YouTube video:

But successful this post, I'll show really I configured the Raspberry Pi to activity arsenic a stratum 1 NTP clip server with:

  • Jimmy Paputto's L1 GNSS HAT
  • Chrony (for clip synchronization and NTP services)
  • Time and Daytime Protocols
  • A Densitron LCD built into the TrueTime XL-AK
  • The bicolor LED built into the TrueTime AL-AK
  • My TrueTime Pi Mounting Bracket

I utilized a Raspberry Pi 5 pinch 4GB of RAM, but there's nary logic you can't usage a $44 Pi 5 pinch 1GB of RAM for this task (if each you're moving connected it are timing services for a mini network).

My contiguous request for this server is to supply clip services for VCF Midwest adjacent weekend. As pinch each my projects, I person parts gathered for months, and assembly usually waits until a week aliases 2 earlier a deadline :)

Jimmy Paputto L1 GNSS HAT

Jimmy Paputto L1 GNSS HAT outputting a 1 PPS awesome connected handheld oscilloscope

I mounted the GNSS HAT connected apical of the Pi utilizing the included GPIO riser and mounting screws. I utilized screws connected the bottommost to unafraid a Raspberry Pi Bumper underneath.

After flashing Pi OS 'Lite' (no GUI) to a microSD card, I built the Jimmy Paputto GNSS HAT package from source:

sudo apt -y instal build-essential cmake libgpiod-dev python3-dev git clone https://github.com/jimmypaputto/gnsshat.git cd gnsshat mkdir -p build && cd build cmake .. -DBUILD_PYTHON=ON -DBUILD_EXAMPLES=ON make -j$(nproc) sudo make install

This package includes a GNSS information span to transportation NMEA sentences (the clip and day information) to gpsd and chrony; you could besides plug the GNSS HAT's USB-C larboard into a USB-A larboard connected the Pi and entree the u-blox NEO-M9N directly.

After the instal was complete, I followed the guideline to group up a Raspberry Pi Time Server pinch PPS.

Chrony

When it was clip to configure Chrony, I utilized the pursuing settings wrong /etc/chrony/chrony.conf:

# GNSS + PPS clip server # GPS clip via shared representation from gpsd refclock SHM 0 offset 0.0 hold 0.05 refid NMEA noselect # PPS — precise separator timing refclock PPS /dev/pps0 refid PPS fastener NMEA for illustration spot canvass 3 select 16 # The Pi's XO is reasonably stable, but not rather TCXO-level. maxclockerror 0.5 # Hardware timestamping for much precision connected Pi 5 hwtimestamp * # Fallback net pools pool 0.pool.ntp.org iburst pool 1.pool.ntp.org iburst # Allow each LAN clients allow 10.0.0.0/16 # Allow requests routed done Twingate container. allow 172.17.0.0/16 maxupdateskew 100.0 makestep 1000 3 rtcsync # Ignore timepiece updates >100ms (fixes gpsd reporting clip 1s disconnected each ~31 min) maxchange 0.1 1 -1

I'm accessing my NTP demo setup remotely done Twingate, since I'm dealing pinch aggregate WANs while testing, and it was easier to punch done things for illustration double NAT pinch a proxying service.

Restart chrony aft updating the configuration:

sudo systemctl restart chrony

Verify everything's moving with:

chronyc sources -v chronyc tracking

After measuring chrony metrics for a fewer days, I tweaked parts of the configuration to lucifer my setup—for maxclockerror, I reduced it from the default because I was capable to stabilize the oscillator wave pinch immoderate tweaks to the Pi's settings.

Pi Timekeeping Tweaks

The changes I recovered particularly helpful:

  1. Running the instrumentality astatine a changeless work cycle
  2. Forcing the Pi's SoC to tally afloat velocity pinch force_turbo
  3. Pinning the kernel PPS interrupts to CPU halfway 4 (after isolating that core)
  4. Insulating the bottommost of the Pi truthful the oscillator is successful a much unchangeable thermal environment
  5. Insulating the remainder of the Pi by enclosing it successful the TrueTime enclosure

Some different things I tried didn't look to person a measurable impact, astatine slightest complete 6-12 hr testing periods.

I highly urge reference this Austin's Nerdy Things blog post if you're willing successful this stuff.

Stable Pi Clock

To unit the Pi to enactment astatine 2.4 GHz for a much unchangeable thermal situation (since the oscillator is adjacent the SoC, and it is impacted importantly by bursty CPU activity), you tin group the force_turbo option. This burns possibly 1W much powerfulness continuously, but is worthy it if you want a unchangeable oscillator wave (important for timing).

Add the pursuing wrong /boot/firmware/config.txt and reboot the Pi:

# Force capacity politician truthful CPU maintains a much unchangeable temperature. force_turbo=1

Consistent Fan Speed

I spent a while testing things for illustration NTPheat to stabilize the Pi's SoC temperature. Tools for illustration that work, particularly if you insulate your Pi. Airflow, particularly that from HVAC systems, makes the Pi's oscillator spell wild—stable clocks for illustration accordant drift, because it's measurable.

But aft a batch of testing, I recovered having the bottommost of the Pi insulated (that's wherever the crystal lives, physically), enclosing the remainder of the Pi, and moving pinch a accordant instrumentality velocity and ample heatsink, made for a much unchangeable frequency, astatine slightest successful a fewer 6-12 hr cycles truthful far1.

I commited the small fan-control inferior I'm utilizing successful my Time Pi repository, successful lawsuit you want to usage it. A 75% work rhythm really performed a small better... but the instrumentality was conscionable noisy capable to annoy maine astatine that level erstwhile I was testing this astatine my desk... truthful 50% it is.

Onboard RTC Battery Charging

Assuming you person the charismatic ML2020 Raspberry Pi RTC battery installed, configure the onboard RTC's artillery charging circuit:

  • Plug successful a Pi 5 RTC Battery to the due header
  • Add dtparam=rtc_bbat_vchg=3000000 to /boot/firmware/config.txt and reboot
  • (Read the artillery voltage pinch vcgencmd pmic_read_adc BATT_V)

The RTC artillery won't thief the Pi's timekeeping stability, but it does thief support the Pi wrong a 2nd aliases 2 of real-time if you unopen it down for immoderate play of time. (As agelong arsenic you don't support it disconnected for months astatine a time!)

Isolating PPS interrupts connected a azygous CPU core

I wanted to spot if dedicating 1 CPU halfway wholly to handling PPS interrupts would help, and it did. One logic superior timing cogwheel runs connected FPGAs (or uses PHCs for illustration successful timing-specific web cards) is deterministic PPS handling. If you usage the Linux kernel's PPS functionality, moreover successful the champion lawsuit you're dealing pinch hundreds of nanoseconds of delays waiting for the interrupt to beryllium dealt with!

To thief springiness PPS a fighting chance, you tin delegate PPS handling to a azygous dedicated CPU core. In my case, I wanted to put each PPS handling connected CPU3 (the 4th core).

  1. Edit /boot/firmware/cmdline.txt and adhd isolcpus=3 to the options
  2. Reboot: sudo reboot
  3. Create /usr/local/sbin/pin-pps-irq.sh (chmod +x it) pinch the contents:
#!/bin/sh irq=$(awk '/pps@/ {sub(":","",$1); people $1}' /proc/interrupts) [ -n "$irq" ] && echo 3 > /proc/irq/$irq/smp_affinity_list
  1. Create /etc/systemd/system/pin-pps-irq.service pinch the contents:
[Unit] Description=Pin PPS GPIO IRQ to isolated CPU3 After=multi-user.target [Service] Type=oneshot ExecStart=/usr/local/sbin/pin-pps-irq.sh [Install] WantedBy=multi-user.target
  1. Start the work and alteration it connected boot: systemctl alteration --now pin-pps-irq.service.

Confirm it's working:

$ watch grep pps /proc/interrupts # You should spot the 4th file incrementing erstwhile per second: 166: 860 0 0 34 pinctrl-rp1 5 Edge [email protected]

Monitor your chrony statistic for a play of 1-6 hours and spot really overmuch effect it makes. In my case, it was noticeable, but not game-changing.

Monitoring and Physical Time Display

To show the capacity of my Pi (which by this constituent I was calling 'TrueTime Pi' successful grant of the chassis wrong which it was installed), I built chrony-dashboard, pinch assistance from Claude.

TrueTime Pi Chrony Monitoring Dashboard

Whipping up speedy dashboards is an easy triumph for AI tooling. I ne'er enjoyed moving pinch frontend graphing libraries, and building a book to parse information retired of a ammunition bid and jam it into a SQLite database periodically is not thing that excites me.

Let AI do that, and I tin attraction connected the nosy parts for illustration position and performance!

A web UI is 1 thing, I besides utilized Claude to thief maine representation GPIO pins to the vintage Densitron LCD connected the beforehand of the TrueTime, and I coiled up pinch this project: densitron-lcd

Wire Wrapping connected pins connected a perfboard

The photograph astatine the apical of this station shows the LCD moving pinch a coagulated GPS fix. For wiring, I really utilized a method I'd ne'er tried before—wire wrapping.

With the Pi and the GNSS HAT, location wasn't capable vertical clearance wrong the TrueTime chassis for dupont connections—not that I bask those connectors anyway! I was considering soldering wires consecutive to GPIO pins but recovered retired astir ligament wrapping while researching different low-profile methods to link to modular quadrate pins.

Apparently the process forms a weld astir the corners of the post, and results successful a gas-tight electrical relationship pinch little guidance than solder! If the joints past the travel up to Chicago, I mightiness usage this method a small much often for prototyping.

I utilized this ligament wrap tool and this 30 AWG ligament wrapping wire.

Time and Daytime Protocols

As an easter egg, since I'll beryllium utilizing this TrueTime Pi server astatine VCF Midwest, I thought I'd besides proviso RFC 867/868 Time and Daytime services connected the network.

Setting that up is arsenic easy as:

sudo apt instal xinetd sudo systemctl alteration xinetd sudo nano /etc/xinetd.d/time -> work clip tcp group disable to "no" -> work clip udp group disable to "no" sudo nano /etc/xinetd.d/daytime -> work daytime tcp group disable to "no" -> work daytime udp group disable to "no" sudo systemctl restart xinetd

My erstwhile blog station goes into the history of these 2 pre-NTP protocols.

AppleTalk / netatalk for Timelord Server

Another nosy demo is aged Macs getting clip via AppleTalk! This is courtesy of timelord, which is easy to tally arsenic portion of netatalk, alongside different services for illustration moving an AppleShare work for record serving to vintage Macs.

On my Pi moving Pi OS, setup was simple. First alteration AppleTalk services successful the Linux kernel:

# Enable AppleTalk protocol and guarantee it's loaded. sudo modprobe appletalk && lsmod | grep appletalk # Add AppleTalk protocol to footwear modules. echo appletalk | sudo tee /etc/modules-load.d/appletalk.conf # Create a files for netatalk. mkdir -p ~/netatalk/afpshare

Then, assuming you person Docker installed, create a Docker Compose record (nano ~/netatalk/compose.yml) pinch the pursuing contents:

services: netatalk: image: netatalk/netatalk:latest container_name: netatalk restart: unless-stopped network_mode: host cap_add: - NET_ADMIN volumes: - ./afpshare:/mnt/afpshare - /var/run/dbus:/var/run/dbus environment: AFP_USER: myname AFP_PASS: mypass AFP_GROUP: afpusers ATALKD_INTERFACE: eth0 INSECURE_AUTH: "1" AFP_EXTMAP: "1" DISABLE_TIMEMACHINE: "1" SERVER_NAME: "TrueTime Pi" TZ: America/Chicago

Go into the netatalk directory you created, and commencement the container:

cd ~/netatalk && docker constitute up -d

Any different Classic Mac connected the web should beryllium capable to usage Tardis for clip services (it's a Chooser plugin and runs erstwhile astatine boot) aliases AppleShare to link to the TrueTime Pi server.

You tin corroborate it's moving pinch docker exec [container name] nbplkup. This should return a database of services including AFPServer and TimeLord.

Conclusion

In the end, I'm happy pinch really this each turned out. I person the Pi securely mounted successful a measurement I tin easy switch backmost to the original TrueTime hardware, conscionable by re-plugging 2 connectors inside.

TrueTime Pi equine vanished pinch GPS jumper connected

If you'd for illustration to replicate this build... beryllium my guest. I for illustration this capable I whitethorn return it moreover further—two much things I'd for illustration to do:

  1. Design a PCB pinch an SMT GPIO Header truthful I tin still person a low-profile setup, but pinch moreover easier swappability (wire wrapping is fun, but besides tedious to re-do).
  2. Get the TrueTime keypad working, truthful I tin rhythm done displays for Time, GPS, Chrony, and web information.
More