Natalie's Nonsense Nook

Quad Serial PPPS Hat

Published on

A while back I got a pair of these BG7TBL GPSDO clocks off ebay:

BG7TBL GPSDO Picture If you’re not familiar, it’s an inexpensive GPS disciplined oscillator - essentially using GPS sats to correct a local less-stable oscillator. I was looking for a cheap portable 10MHz source. But one thing caught my eye, which was the serial port. If you look, the pinout is below the DE-9 port, and you can see the normal Rx and Tx lines as well as a PPS (pulse-per-second) line. This is somewhat common, as a lot of clocks use various flow control lines (often RI) to signal to the host when a second pulse occurs. The host is able to attach an interrupt to the RI pin and use that for very accurate timekeeping on the host (which often uses that time as a network time source).

If you recall the release of the Raspberry Pi CM4, you may remember the onboard network controller has a neat feature up its sleeve: IEEE1588 aka Precision Time Protocol support. The regular Pi 5 followed in the footsteps of the CM4 and also has PTP support. Immediately I wanted to make a PTP server for kicks and giggles since I am a giant time nerd. I did some initial testing with a horrible amalgamation of a screw terminal RS-232 to TTL level shifter and a cut up RJ45 cable and some breadboard jumpers. I am so ashamed, there will not be a picture attached here. Despite the horrible cabling, it did in fact work - after some software setup, a /dev/pps0 device appeared and was reporting ticks via ppstest. This post is not really meant to go over the intracacies of setting up a time server (especially a PTP one) but rather the custom hardware I whipped up to solve the shoddy wiring.

Finished Pi hat PCB stackup

Initially, I was just going to put a single RJ45 and associated level shifters on the board, but ended up with a few more goodies. First, I bumped the port count to 4, utilizing UARTs uart0, uart2, uart3, and uart4 (apparently uart1 is the host console on the Pi5, and not for peripherals). As you can see fitting it all was quite tight and pretty much perfect. I tracked the board, and send it to the PCB house to get printed. I don’t want to name them, but the PCB house I use has a new thing where you can get your boards serialized with a unique datamatrix code. I hadn’t tried it out before, and it was sort of a surprise to me, but it ended up well enough. I definitely like it, but next time I would definitely plan out a bit better where the code goes.

Finished Pi hat rear, with the datamatrix code applied by the PCB house

Additionally, I added a couple quality of life features: selectable null-modem crossover and PPS pin selection. The selectable crossover is huge, since you don’t have to make custom cables for a downstream device - if you can get it into a Cisco-pinned RJ45 plug, you can get data in and out. No matter if your connected device is DTE or DCE you can get it connected. This is handled by a switch next to the port, and the PPS pin select is handled by a small jumper next to the port. This allows you to pick which pin is driving the PPS signal, again without having to make a custom cable. Honestly, I added these because I was lazy, and didn’t want to figure out which way the clock was; but this actually ended up benefitting me more since it adds a ton of flexibility. And, as per the pHAT spec, there is an EEPROM, but I need to make a dtoverlay and push it upstream for the EEPROM to really do anything. The final board came out pretty nice though, and worked the first time, which was a welcome surprise. Shark even approves:

Finished Pi hat front

Getting the serial lines to work on the Pi requires a simple addition to the config.txt file on the SD card, along with the pps-gpio overlay which adds a driver for a PPS-via-GPIO device on pin 18:

[all]
enable_uart=1
dtoverlay=uart0
dtoverlay=uart2
dtoverlay=uart3
dtoverlay=uart4
dtoverlay=pps-gpio,gpiopin=18

Currently, I have this in use at home running one of the BG7TBL clocks into the Pi for a local NTP server, plus out-of-band serial access to my router and two switches. I used ser2net for the serial console server bit, and it works a treat. I need to tinker with it a bit to make it work better in my workflow, but it works well enough now. Which is part of the point, this isn’t just a time-keeping hat, it’s also an easy to use serial console hat where you don’t need crossover cables to plug into different devices. And what would a post about time be without an error measurement:

natalie@time:~ $ chronyc sources -v

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- 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   377    19   +474ms[ +474ms] +/-  175ms
#* PPS                           0   4   377    17   -126ns[ +504ns] +/-  181ns
^- time-a-b.nist.gov             1  10   377   738  -2680us[-2673us] +/-   16ms
^- time-d-b.nist.gov             1  10   377   295  -2623us[-2619us] +/-   16ms
^- india.colorado.edu            1  10   377   526  +1939us[+1944us] +/-   11ms
natalie@time:~ $ 

Hundreds of ns isn’t all that bad for the realistically low accuracy I need at home.

Overall, I am very happy with how this turned out. I still have a dozen or so from the run, and if you are interested in one please email (see the home page) or otherwise get in contact and we can chat. I think if I were to do it again I would probably add some sort of digital mux chip so that the Pi could control the crossover function without user input, and making a smaller connector for the serial ports with some sort of intermediate [unnamed connector] -> RJ45 adapter to add more space on the board. That said I am still extremely happy with this design, and it was a good exercise in quickly turning around a PCB.