You need both the
NMEA 0183 data and
PPS for accurate
timekeeping.
Only the Garmin GPS 18 LVC and GPS 18 LVC-5m produce a PPS signal. The GPS 18-5
Hz produces 5 pulses per second.
These receivers appear to be no longer available. The GPS 18x LVC 5m
appears to be similar.
The transmitted data from the Garmin is connected to the received data from the
PC and vv. The PPS output is connected to the DCD pin.
Some people power the Garmin from the
USB port. The USB data wires
(green and white) are not used.
The black wires are connected to the
RS232 ground pin.
Garmin | Cable | RS232 | 9P | 25P | USB | Cable |
---|---|---|---|---|---|---|
+5V | Red | 1 | Red | |||
GND | Black | GND | 5 | 7 | 4 | Black |
GND | Black | GND | 5 | 7 | 4 | |
TXD | White | RXD | 2 | 3 | ||
RXD | Green | TXD | 3 | 2 | ||
PPS | Yellow | DCD | 1 | 8 |
Garmin 9P 25P USB Red --------- Red Black ----*---- Black | Black ----*---- 5 7 White --------- 2 3 Green --------- 3 2 Yellow --------- 1 8
Inside the cable there is a 3rd black wire and a shield. They seem to be
connected to the other black wires. I did not connect the 3rd black wire,
but I did connect the shield to the RS232 shield via a 47 nF capacitor. The
USB shield is directly connected to the RS232 shield.
I used a 25 pins connector connected to a RS232 tester.
The Garmin output voltage swings between 0 and +5 Volts, so the CD and RD LED's
will flash red but not green.
If connected directly to Minicom, the Garmin appears to be online once per
second. This is because the PPS is tied to DCD.
The circuit below can be used to avoid line status confusion;
Garmin Minicom Male Female 9P 25P RXD-----RXD 2 3 TXD-----TXD 3 2 GND-----GND 5 7 +-DCD 1 8 | *-DTR 4 20 | +-DSR 6 6 +-CTS 7 5 | +-RTS 8 4 SH------SH
Start Minicom with '-o' to avoid sending an init string. Exit Minicom with 'Ctrl-A,Z,Q' instead of 'X' to avoid a reset.
According to the
Garmin documentation
(687 kB) these sentences are enabled by default;
Sentence | Output by Default? | Maximum Characters |
---|---|---|
GPRMC | Y | 74 |
GPGGA | Y | 82 |
GPGSA | Y | 66 |
GPGSV | Y (PC and LVC only) | 70 |
PGRME | Y (PC and LVC only) | 35 |
GPGLL | N | 44 |
GPVTG | Y (18-5Hz only) | 42 |
PGRMV | N | 32 |
PGRMF | N | 82 |
PGRMB | Y (PC and LVC only) | 40 |
PGRMT | N Once per minute | 50 |
Sending the following string will restore these defaults;
$PGRMO,,4
In order to avoid typos I send this string as a
file (Ctrl-A,Z,Y).
As it turns out, the PGRMT IS enabled by default.
It takes about 0.8 seconds to send these sentences at 4800 bps.
With all sentences enabled it takes longer than one second. Which means that
the time is available only once per TWO seconds.
The entry for a refclock in ntp.conf is;
server 127.127.Type.Unit_Number
Type | Description | Ident |
---|---|---|
20 | Generic NMEA GPS Receiver | GPS_NMEA |
22 | PPS Clock Discipline | PPS |
28 | Shared Memory Driver | SHM |
PPS only works with a PPS enabled kernel. This applies to both the GPS_NMEA and
PPS driver; If your kernel supports PPS, the GPS_NMEA driver can take care of
PPS to. Furthermore, the desired clock has to be compiled into NTPD.
If you want to use PPS with a kernel without PPS support, you need to use a
Shared Memory Driver.
The setup below uses a shared memory driver for PPS and a GPS_NMEA driver for
the time. This means that you have to split the cable in two; one port gets all
signals, the other just PPS and GND.
The Garmin is a bit late, so I added a 185 ms time1 fudge;
server 127.127.20.0 fudge 127.127.20.0 time1 0.185 server 127.127.28.0 minpoll 4 prefer fudge 127.127.28.0 refid PPS
The GPS_NMEA driver wants a symlink in /dev/ telling it which is the source of the time. EG ttyS1;
gps0 -> ttyS1
I created a file '77-local.rules' in '/etc/udev/rules.d/' for this purpose. It contains the following line;
KERNEL=="ttyS1" SYMLINK+="gps0"
Replace 'ttyS1' with the tty you use.
A remote source, such as a remote GPSD, can also be used;
gps0 -> 192.168.1.5:2947
David J. Schwartz's SHM driver (shm_linux_clock.c) reads data from ttyS0 and feeds it to the NTPD's shared memory. There is also a version (shm_splc.c) modified by Steven Bjork which supports parallel ports. And a newer version (shmpps.tar) by Philip M. White. You need to start this driver when the clock within 25 ms accurate.
Use of GPS_NMEA is problematic with Debian Wheezy, so I disabled it in ntp.conf.
Alternatively you can use GPSD as a time source for NTPD. This only works properly
with a 0.2 s PPS. GPSD however resets this to 0.1 s. To avoid this tell GPSD not
to send anything to the Garmin with the '-b' option;
/etc/default/gpsd;
START_DAEMON="true" DAEMON_OPTS="-b -n" DEVICES="/dev/ttyS0" USBAUTO="false"
The following lines in ntp.conf tell NTPD to use GPSD as a time source;
server 127.127.28.0 minpoll 4 fudge 127.127.28.0 time1 0.178 refid GPSa server 127.127.28.1 minpoll 4 prefer fudge 127.127.28.1 refid PPSa
My Garmin works just fine. If you have any problems, have a look here.
I added 'low_latency' to /var/lib/setserial/autoserial.conf to make things more accurate (ttyS0 is used for PPS);
setserial /dev/ttyS0 uart 16550A port 0x03f8 irq 4 baud_base 115200 spd_normal skip_test low_latency
If you run an accurate timeserver on your LAN, you may want to reduce the poll interval on the clients a bit;
server ntp.example.org iburst minpoll 6 maxpoll 7
'iburst' makes NTPD start with a poll interval of one second.
'minpoll 6 maxpoll 7': Start with one poll per 64 seconds and the gradually
move to one poll per 128 seconds.
When your Garmin doesn't have a clear view of the sky it will loose NMEA
sync every now and then. When there is no NMEA sync for a longer period of
time, the PPS will start to drift. The Garmin may also crash.
I wrote a script to take care of both. It runs from
cron every five minutes;
#!/bin/bash # Check PPS and if GPS NMEA is Acquired # Files; # Acquired status count file ACNTFILE="/var/local/lib/gps-chk/acqrd-cnt" # Previous acquired status file ASTATFILE="/var/local/lib/gps-chk/acqrd-stat" # PPS count file PCNTFILE="/var/local/lib/gps-chk/pps-cnt" # Current acquired status CURASTAT=$( /usr/local/sbin/chk-gps-acqrd.sh ) # Previous status PREVASTAT=$( /bin/cat "${ASTATFILE}" ) # Not acquired status count ASTATCNT=$( /bin/cat "${ACNTFILE}" ) # Max not acquired count MAXACNT=2 # Current sync quality CURSYNC=$( /usr/local/sbin/ntpeval ) # PPS count PPSCNT=$( /bin/cat "${PCNTFILE}" ) # PPS Reset delay. RSTDLY=8 # Check PPS; REACH=$( /usr/bin/ntpq -p | egrep "^[ *+](SHM|127[.]127[.]28[.])" | awk '{print $7}' ) # Force REACH 0 if not spresent if [ ! $REACH ] then REACH=0 fi # Convert to decimal REACH=$(( 8#$REACH )) # Check PPS reach if [ $(($REACH%2)) -eq 0 ] then # Bits xxxx xxx0; even => Missing logger "chk-gps: PPS Failed" if [ $PPSCNT -gt 0 ] && [ $(( $PPSCNT%$RSTDLY )) -eq 0 ] then # Garmin may have crashed: Reset Garmin sleep 10 echo $REACH | mail -s "Garmin PPS Reser" Your_Email_Address logger "chk-gps: PPS Reset" /usr/local/sbin/sndnul -d /dev/Your_TtySx -t 2 sleep 5 fi let PPSCNT+=1 echo $PPSCNT > "${PCNTFILE}" # Exit script exit 0 else # Bits xxxx xxx1; odd => OK if [ $PPSCNT -ne 0 ] then # Was missing logger "chk-gps: PPS OK" echo 0 > "${PCNTFILE}" fi fi # Check NMEA if [ $CURASTAT -eq 0 ] then # Not acquired let ASTATCNT+=1 echo $ASTATCNT > "${ACNTFILE}" if [ $ASTATCNT -gt $MAXACNT ] && [ $CURSYNC -eq 0 ] && [ $PREVASTAT -ne 0 ] then # Reset Garmin logger "chk-gps: NMEA Failed" /usr/local/sbin/sndnul -d /dev/Your_TtySx -t 2 sleep 5 echo 0 > "${ASTATFILE}" fi else # Acquired if [ $ASTATCNT -ne 0 ] then # Was not acquired echo 0 > "${ACNTFILE}" fi if [ $PREVASTAT -ne 1 ] then logger "chk-gps: NMEA OK" echo 1 > "${ASTATFILE}" fi fi
The first part checks PPS. If there is no PPS for a longer period of time
it will assume that the Garmin crashed.
The second part checks the NMEA sync. It uses a smal program
'ntpeval.c' to evaluate the time
sync. If either of these checks fail it will power toggle the Garmin using a
relay controlled by a serial port.
The serial port is controlled by a small program
'sndnul.c' called from the
script.