When Serial Isn't RS-232, and Geocaching with the Garmin GPS 95
Recently I picked up a box of early 1990s Garmin GPS receivers along with an array of accessories. I cleaned up one receiver, a GPS 95, installed 4 new AA batteries, and positioned it with a clear view of the sky. After an agonizing long time searching for satellites it eventually received a full almanac and made a GPS lock. It was pretty cool that it still works!
However there were two problems discovered while using the receiver. First, while the longitude and latitude were accurate, the altitude was completely wrong. Second, the receiver still thought it was in the 1990s. While the first problem is inherent to GPS, we can fix the second issue!
The receiver has no control for changing the date or time: it relies almost entirely on the GPS signal. Surely, the date being sent by GPS wasn’t wrong. The GPSJAM map did not show any interference anywhere near the Netherlands.
The “legacy” LNAV signal transmitted by GPS doesn’t actually contain the date. That is instead computed by the receiver based on two other signals transmitted: a 10-bit week counter that is incremented once a week, and a 19-bit time of week signal incremented every 1.5 seconds. This week counter rolls over every 1024 weeks (or approximately 19.6 years).12 So a GPS receiver requires some other way to know which week counter epoch to use.
The first GPS rollover occurred at midnight between 21-22 August 1999. This was at the tail end of support for the GPS 95 receivers. Fortunately, Garmin released a tool at the time “GPS EOW”3 that existed entirely to adjust the time of the reciver’s clock. This would allow the built-in logic to track the date afterwards. The GPS 95 has now joined us in the 21st century.4
I started my Windows 98SE virtual machine5 and attached /dev/ttyUSB0
as COM1
and started “GPS EOW”. Except it complained that it couldn’t communicate with
the receiver.
After some fiddling, I switched to a different USB adapter and that worked successfully.
Later, I wanted to try out GPS for Flipper Zero, an application for the Flipper Zero that decodes NMEA 0183 messages, with the GPS 95. I connected the serial connection from the GPS receiver to the Flipper Zero as described, but the application never saw any data.
Since I knew NMEA 0183 messages are ASCII, I switched to the UART Terminal application. Instead of the expected NMEA, I saw complete gibberish.
Those that have been around serial for a while are undoubtedly rushing to a comment section to complain about the bone-headed move I just described. I may have just destroyed the pins on my Flipper Zero. As we’ll see in a bit, I lucked out and did not.
The serial port on the PC platform uses RS-232, a loose standard going back to the 1960s describing the electrical and timing of the signals, but not the encoding of data. This is a bipolar signal ±25V where the data signal are “inverted”, that is a signal ≤-3V is a logical “1” and a signal ≥3V is a logical “0”. The range between -3V and 3V is undefined. The pins of a Flipper Zero are at 3.3V, but is tolerant of signals up to 5V. If the GPS 95 was indeed sending RS-232 levels that could have gone very wrong.
To better understand what was going on, I used the oscilloscope at the Technologia Incognita hackerspace. Fortunately, the GPS 95’s serial was only going up to 5V, but also not using negative voltages at all. This reminded me of “TTL serial”, the type of serial we use with microcontrollers and what the original USB serial adapter and the Flipper Zero expect. However, like the UART Terminal app, the UART decoder on the oscilloscope was also having difficulties decoding something useful from what should be NMEA.
Besides the voltages used, there is another major difference between RS-232 and “TTL serial”. The latter signal is not inverted. Instead a zero level is a logical “0”, which a high level is a logical “1”.
If you search online these are the two types of serial you’ll see described again and again. You might find the occasional reference to a third type that was popular in the early 1990s. This serial type operates between 0-5V like “TTL serial”, but with inverted data lines like RS-232, allowing it to be connected directly to a PC’s serial port.6
While I’m not aware of a name used at the time for this type of serial, this is the type of serial used by the GPS 95. It is my understanding that portable device manufacturers did not want to add an extra voltage rail just for the serial port, but RS-232 drivers with integrated charge pumps weren’t yet cheap enough.
To be able to receive the NMEA data on my Flipper Zero I’d need to convert this to “TTL serial”; that is invert the signal again so that a zero voltage is a logical “0” and a positive voltage is a logical “1”. I choose to use an SN74HC04N inverter, a “jelly bean” part I already had on my bench from another project.
With the circuit put together on a prototyping board, both the UART Terminal and GPS for Flipper Zero applications worked correctly! Now I can connect the GPS 95 to any device expecting “TTL serial” without problems, which opens up some cool ideas for future projects.
Today I set out to find the oldest hidden Geocache in the Netherlands, Amsterdam Urban 1. While the Garmin GPS 95 is primarily for aviation, complete with a database of airports, navigation waypoints, and frequencies last updated in 1999, adding custom waypoints is well supported.
As the image at the top of this post shows, I was able to find the cache. Since user waypoints can be synchronized with a PC, it would be interesting in the future to write a program that can push a list of geocaches to the Garmin GPS 95. I’ll be typing them in manually in the meantime!
The week counter was expanded to 13-bits when using the newer CNAV signal, rolling over every 157 years. ↩︎
The most common version seems to be v1.20 (local archive) (Internet Archive) ↩︎
I’ve noticed the altitude is more accurate after the date was corrected, but I’m not sure why. ↩︎
The application should also work under WINE. ↩︎
While undefined in the RS-232 standard, most recievers on the PC platform considered zero voltage to be a logical “1”, allowing this to work. ↩︎