http://www.talkunafraid.co.uk/2012/12/the-ntpi-accurate-time-with-a-raspberry-pi-and-venus638flpx/
Includes building the source to reconfigure the use of the Pi serial port, besides building a time server with the pi.
The ntpi: accurate time with a Raspberry Pi and Venus638FLPx
One of the things I’ve always loved to tinker with is time sources
and synchronization. Typically this has been tied to sensible things
like the Network Time Protocol and designing and maintaining time
distribution systems for broadcast networks. Lately though I’ve been
toying with ‘real’ time sources – GPS and MSF broadcasts. This is a
quick tutorial on how to set up a Raspberry Pi, which at only a few
watts makes for an economical time server, to talk to a Venus 638FLPx
GPS receiver (available from Sparkfun on a suitable breakout board here).
It’s worth noting that the GPS chip in question is not really ideal for timing applications. There are nicer boards for this purpose. But the great thing is that because most of these things are pretty standard, almost all this guide will still work. Venus do make an IC, the 638LPx-T, which is a variant of this chip designed for timing with an accuracy of plus/minus 30us, but I can’t find that on a breakout board and I had the FLPx board spare from a UAS platform.
The basic requirements for a GPS time source/server are:
The tricky bit comes with the software. Let’s talk about how GPS time sourcing works.
The GPS satellites rely on highly accurate timing, and broadcast UTC time information as part of their signals. The difference in the timestamps is what, largely, allows your receiver to figure out where you are. If you know where you are, though, you can use those timestamps to come up with a very accurate fix for time.
The NMEA strings that come off the GPS describe all sorts of things. They look a bit like this:
Sadly this won’t get us a very accurate reference. Let’s look at what the PPS looks like, for starters, with an oscilloscope:
We can see quite clearly these are small, 5ms pulses exactly once a second. Great! So how about those NMEA strings being sent over serial?
We can see in the top half of this trace a full NMEA transmission occurring just after (1.18ms) the PPS pulse – but the NMEA transmission is huge! And if we follow it, we see it move around, too.
This is a zoomed in view of a PPS pulse against the NMEA transmission (1.6ms after the pulse, this time – plenty of variance). This was taken with the GPS in ‘send NMEA in sync with PPS’ mode!
So if we want to get our device accurate we need to use PPS. But if we just use PPS, we don’t know which second we’re in! So we have to use both. Fortunately, ntpd will manage this for us.
Diving back to the software, then – we need a kernel that can deal with the PPS pulses on our GPI port. Let’s install one:
Next up: telling ntp about this shiny new local clock!
We need to do one thing first – if your local network has a DHCP server that announces time servers, you want to use your local NTP config despite this. You need to edit /etc/init.d/ntp and comment the following lines out:
Restart ntpd, wait a few minutes for it all to settle down, and verify things are working:
You really, really want to make sure your system is using the PPS, is what I’m getting at.
Another thing I ran into was the GPS reporting the wrong time or not reporting its timing offset – just ensure you have enabled the GPZDA statement to avoid this. Symptoms of this can include huge offsets and being marked as a falseticker (x) in peer lists of other peers. Just make sure your module is configured properly. This is what I did to configure my module:
It’s worth noting that the GPS chip in question is not really ideal for timing applications. There are nicer boards for this purpose. But the great thing is that because most of these things are pretty standard, almost all this guide will still work. Venus do make an IC, the 638LPx-T, which is a variant of this chip designed for timing with an accuracy of plus/minus 30us, but I can’t find that on a breakout board and I had the FLPx board spare from a UAS platform.
The basic requirements for a GPS time source/server are:
- GPS module which outputs NMEA strings on serial and has a 1PPS output
- Computer with GPI pin for 1PPS and serial connectivity running Linux
- GPS antenna in a place that can see a good chunk of sky with a feed back to the module
The tricky bit comes with the software. Let’s talk about how GPS time sourcing works.
The GPS satellites rely on highly accurate timing, and broadcast UTC time information as part of their signals. The difference in the timestamps is what, largely, allows your receiver to figure out where you are. If you know where you are, though, you can use those timestamps to come up with a very accurate fix for time.
The NMEA strings that come off the GPS describe all sorts of things. They look a bit like this:
pi@ntpi ~ $ cat /dev/gps0 $GPGGA,201705.000,5644.4848,N,00142.3529,W,1,10,0.9,64.4,M,49.0,M,,0000*75 $GPGLL,5644.4848,N,00142.3529,W,201705.000,A,A*43 $GPGSA,A,3,07,26,08,19,15,05,09,21,18,24,,,1.5,0.9,1.2*3B $GPZDA,201705.000,29,12,2012,00,00*5EThey’re a bit obscure but they have the time encoded into them along with things like how many satellites are used in the solution, velocity/heading, and so on. The first chunk, $GPGGA for instance, is a preamble for each string – the last three characters are used to refer to a string of that type, eg GGA.
Sadly this won’t get us a very accurate reference. Let’s look at what the PPS looks like, for starters, with an oscilloscope:
We can see quite clearly these are small, 5ms pulses exactly once a second. Great! So how about those NMEA strings being sent over serial?
We can see in the top half of this trace a full NMEA transmission occurring just after (1.18ms) the PPS pulse – but the NMEA transmission is huge! And if we follow it, we see it move around, too.
This is a zoomed in view of a PPS pulse against the NMEA transmission (1.6ms after the pulse, this time – plenty of variance). This was taken with the GPS in ‘send NMEA in sync with PPS’ mode!
So if we want to get our device accurate we need to use PPS. But if we just use PPS, we don’t know which second we’re in! So we have to use both. Fortunately, ntpd will manage this for us.
Diving back to the software, then – we need a kernel that can deal with the PPS pulses on our GPI port. Let’s install one:
git clone https://github.com/davidk/adafruit-raspberrypi-linux-pps.git cd adafruit-raspberrypi-linux-pps/ sudo mv /boot/kernel.img /boot/kernel.img.orig sudo cp kernel.img /boot sudo mv modules/* /lib/modules sudo sh -c "echo 'pps-gpio' >> /etc/modules"We need to disable the default usage of the Pi’s serial, which is to provide a tty. Open /boot/cmdline.txt and remove all elements referring to ttyAMA0. Mine looks like this:
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwaitNext, open /etc/inittab and comment this line out:
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100We also want to configure udev to put our GPS module and PPS where ntpd will expect it to be:
sudo nano /etc/udev/rules.d/80-gps-to-ntp.rules # Change MODE of ttyAMA0 so it is readable by NTP and provide a symlink to # /dev/gps0 KERNEL=="ttyAMA0", SUBSYSTEM=="tty", DRIVER=="", SYMLINK+="gps0", MODE="0666" # Symlink /dev/pps0 to /dev/gpspps0 KERNEL=="pps0", SUBSYSTEM=="pps", DRIVER=="", SYMLINK+="gpspps0", MODE="0666"Next we’re going to install then remove ntpd – we’ll be back with an updated version.
sudo apt-get install ntp sudo apt-get remove ntp sudo apt-get install libcap-devTime to install and compile a PPS-enabled ntpd.
wget http://www.eecis.udel.edu/~ntp/ntp_spool/ntp4/ntp-dev/ntp-dev-4.2.7p340.tar.gz tar zxf ntp-dev-4.2.7p340.tar.gz cd ntp-dev-4.2.7p340/ ./configure --prefix=/usr --enable-all-clocks --enable-parse-clocks --enable-SHM --enable-debugging --sysconfdir=/var/lib/ntp --with-sntp=no --with-lineeditlibs=edit --without-ntpsnmpd --disable-local-libopts --disable-dependency-tracking --enable-ipv6 && make && sudo make installNow we’ve got all this we need to reboot to load the new kernel:
sudo rebootFirst, we can verify that we can see the NMEA sentences:
cat /dev/gps0You should see NMEA strings! Ctrl+C to kill it. Next, let’s test the PPS.
pi@ntpi ~ $ dmesg | grep pps [ 0.000000] Linux version 3.1.9adafruit-pps+ (davidk@bender) (gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #21 PREEMPT Sun Sep 2 10:57:58 PDT 2012 [ 1.148909] usb usb1: Manufacturer: Linux 3.1.9adafruit-pps+ dwc_otg_hcd [ 14.707851] pps_core: LinuxPPS API ver. 1 registered [ 14.712724] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it> [ 14.728437] pps pps0: new PPS source pps-gpio.-1 [ 14.731832] pps pps0: Registered IRQ 108 as PPS sourceLooks like we’re good to go. Check the pps-utils package if you need to verify more completely.
Next up: telling ntp about this shiny new local clock!
We need to do one thing first – if your local network has a DHCP server that announces time servers, you want to use your local NTP config despite this. You need to edit /etc/init.d/ntp and comment the following lines out:
#if [ -e /var/lib/ntp/ntp.conf.dhcp ]; then # NTPD_OPTS="$NTPD_OPTS -c /var/lib/ntp/ntp.conf.dhcp" #fiOpen up /etc/ntp.conf and adjust it to taste. The following stanza should get you up and running:
server 127.127.20.0 mode 24 minpoll 3 maxpoll 4 iburst true prefer fudge 127.127.20.0 flag1 1 flag2 0 flag3 1 flag4 1 time2 0.093The settings here are documented here and can be configured to suit your module. The time2 value may need to be larger (0.4 or so), and you may want to keep or remove the existing servers configured in ntp.conf – or just reconfigure them to be geographically local. You can get an idea of the time2 offset by adding 128 to whatever mode value you’re using, then looking at the timings in /var/log/ntpstats/clockstats after a ntpd restart. Pick the time offset for the first NMEA string seen and there’s your number.
Restart ntpd, wait a few minutes for it all to settle down, and verify things are working:
pi@ntpi ~ $ ntptime ntp_gettime() returns code 0 (OK) time d489d596.2b0cfe14 Sat, Dec 29 2012 20:48:22.168, (.168167784), maximum error 2000 us, estimated error 1 us, TAI offset 0 ntp_adjtime() returns code 0 (OK) modes 0x0 (), offset 2.518 us, frequency 79.473 ppm, interval 1 s, maximum error 2000 us, estimated error 1 us, status 0x2007 (PLL,PPSFREQ,PPSTIME,NANO), time constant 3, precision 0.001 us, tolerance 500 ppm, pi@ntpi ~ $ ntpq -p remote refid st t when poll reach delay offset jitter ============================================================================== oGPS_NMEA(0) .GPS. 0 l 8 8 377 0.000 0.002 0.004 +ns0.luns.net.uk 157.44.176.4 2 u 63 64 17 44.161 3.389 0.709 -ntp.oceanmediag 192.93.2.20 2 u 5 64 37 34.806 2.048 0.585 +dns1.rmplc.co.u 193.62.22.74 2 u 63 64 17 36.375 2.488 0.282 *mail1.itdojo.or 10.10.120.2 2 u 56 64 17 51.280 3.977 0.270 pi@ntpi ~ $ ntptrace localhost: stratum 1, offset 0.000001, synch distance 0.001090, refid 'GPS'Note the o before GPS_NMEA(0) in ntpq -p – this indicates the PPS is being used. If you don’t have the PPS enabled your time will kinda suck, as we saw a bit with the scope traces. To illustrate this, here’s a comparison of system performance between NMEA-only and PPS.
You really, really want to make sure your system is using the PPS, is what I’m getting at.
Another thing I ran into was the GPS reporting the wrong time or not reporting its timing offset – just ensure you have enabled the GPZDA statement to avoid this. Symptoms of this can include huge offsets and being marked as a falseticker (x) in peer lists of other peers. Just make sure your module is configured properly. This is what I did to configure my module:
- Enabled position pinning
- Disabled all NMEA strings except for GGA, GSA, GLL and ZDA
- Set update rate to 1Hz and output sync to UTC
- Set baud rate to 9600 (higher is not better!)