A simplified VX-8DR GPS design

There's been a few projects to build an aftermarket GPS design for the VX-8DR APRS function. But at the end of the day, they've all been a little bulky for my liking.

This has been a product of 5v electronics being unable to be powered from the radio's 3.3v line (hence batteries) and also the physical board size of any Arduino that contains a hardware serial port.

This revised solution minimizes the hardware required to a CT-M11 cable, a 3.3v-capable GPS module, and a Seeeduino Xiao with no additional componentry. 

The Yaesu Problem

The VX-8DR has built in APRS, but no GPS. An external GPS was produced, however it was eye-wateringly expensive, slow to gain a GPS fix, consumed a large amount of current, and was itself somewhat bulky.

While the Yaesu GPS did output NMEA format GPS over a plain serial link, you can't attach any other GPS module to the VX-8DR, because
  1. The Yaesu GPS has a unique output format with regards to the width of certain fields
  2. The VX-8DR parses NMEA as fixed width rather than comma delimited
This would result in garbled output in the Radio.

The Yaesu GPS output format was so unique, and the radio's parsing so simplistic, the radio won't correctly parse any commonly available GPS unit's output.

The solution as devised by Taylor J. Meek was to add a microcontroller to interface to his Garmin unit and translate the format (and change the baud rate).

Newer hardware

Thanks in a large part to the Arduino ecosystem, hobbyist electronics have taken forever to leave behind the 5v era. Even modern Arduino and ESP 3.3v cores come on modules that have difficulty being powered south of the 3.3v regulator to take advantage of the radio's 3.3v output.

While the Xiao has an onboard regulator for 5v supply, it's happy enough taking power on the 3.3v pin for operation, and it has a small footprint board that reduces overall bulk.

The Xiao has many times more clock cycles and memory for the roughly the same power budget (~19ma) as an unoptimized Arduino module. This allows the luxury of reimplementing the code for more complete text parsing. Rather than pad fields for a specific GPS module's output, here we check the leading and decimal precision of each field and pad or contract it accordingly. We also convert Beidou/Glonass/Galileo/GNSS NMEA prefixes to $GPxxx format so that position data from any constellation can be used. In theory, any GPS or GNSS module that supports 9600 bps operation should operate correctly.

Building the GPS

Choose a GPS module

The GPS module I bought is a Pixhawk compatible enclosed module with 5v supply, 3.3v IO, a counterfeit uBlox NEO-M8N GPS chip, antenna, and digital compass chip on board. These sorts of modules built for DIY drones are the typically the easiest, cheapest, and smallest ready to use modules. Unfortunately, drones use 5v supply and you do need to either research or test whether such modules work with 3.3v supply. Mine had no problem running off 3.3v supply, and drew about 54ma. On the oscilloscope the serial TX signal was around 3.1v as a consequence. 

uBlox receivers are excellent. They're multi-constellation receivers that gain fix fast. The U-Center software makes it easy to preconfigure the GPS module as well.  While my module is a counterfeit M8N, it probably is just a cheaper, M8Q module that has had the top-label replaced.


  • Modules designed for pixhawk and other flight controllers tend to be small, have pcb mount antennas fitted, and have nice, compact enclosures.
  • Most modules are 5v. Buy one that explicitly allows 3.3v or take your chances that the onboard regulator is low-dropout
  • uBlox has really nice software for preconfiguring the module, so uBlox chipsets are great. However counterfeit uBlox chips are common.
  •  Flight controller GPS modules have an SPI connection for a digital compass chip. This is unfortunate overhead, as the GPS module isn't connected to the SPI interface.
  • If your GPS module sends GGA and RMC strings at 9600bps by default, it won't need any preconfiguration
  • A USB-uart adapter is handy to have on hand to connect the GPS module to a PC for configuration. Get one that has 3.3v logic and a 3.3v power supply pin to make life easier

The Cable

There's no choice here. Only the Yaesu CT-M11 cable works.

The Microcontroller

I've used the Seeduino Xiao, although I think most Arduino studio compatible 3.3v modules with a hardware serial port should work. For most other modules, a find-replace on the code should be used to change Serial1. to Serial..This is because the serial device on the Xiao is USB-Serial, while the TX/RX pins are serial1. Most other MCUs use serial for their TX/RX pins.

A USB C cable is required to upload the code to the Xiao.

Configuring a uBlox GPS

U-Center for PC can be downloaded from https://www.ublox.com, and allows configuration of a uBlox GPS module connected via a USB-UART adaptor.  Other chipsets may have similar software available from their vendors. 

  • Select the COM port under Receiver=>Connection, and the GPS's default baud rate under Receiver=>Baud
  • Check you're receiving NMEA data under View=>Text Console (F8). If you're not getting NMEA messages, check the port/baud settings.
  • Open the View=>Messages window (F9). Check that the GxGGA and GxRMC messages are enabled. If they are greyed out, right click them and choose enable. Either the GPGGA/GPRMC or the GNGGA/GNRMC submessages can be enabled. The software works for both. Optionally enable GxZDA, and disable any other messages to reduce the load on the MCU.
  • Under View=>Configuration View (Ctrl-F9) you can set the following
    • Baud rate of 9600 (if not set already) on the PRT screen
    • Measurement period of 1000ms and Navigation rate of 1, resulting in 1Hz position output from the GPS module
    • Hit save at the bottom of the window for each change made. Note changing the baud rate will require reconnection in the receiver menu
  • On the CFG tab, save these changes by clicking Save current configuration then Send

Programming the Seeeduino

  • Download the Arduino IDE
  • Connect the Xiao via USB-C cable
  • Configure the Seeeduino libraries in the IDE (Steps 3 and 4 here)
  • Paste in the code from the section below
  • Save the project (Ctrl-S), compile it (Ctrl-R), and upload it (Ctrl-U)

Connect it all together

There really is nothing to the circuit. At its simplest, you can connect it all together per the circuit diagram with flying leads and enclose the pieces in suitably sized heatshrink.

I cabled my GPS module into a modified hand-mic and sat the Xiao inside the hand-mic. I don't recommend it, as RF-noise from the Xiao is audible when transmitting using the hand mic. However, I may diagnose the exact mechanism and fix it later.

Hand-mic cabling is mildly painful. I had to remove most of the PCB and replace it with flying-leads to create the space for the Xiao inside a cheap generic hand-mic enclosure, but overall it's doable.


The Code

Download the .ino file here, or copy-paste the code into your Arduino IDE. It's one file.

Implementation notes

  • All NMEA messages from the GPS are dropped except $GPGGA, $GPRMC, and $GPZDA. However $GPZDA appears to perform no function whatsoever.
  • Various debug messages are output on serial using the $GPTXT tag. The radio ignores these.
  • NMEA messages are processed in a cutthrough manner - the program doesn't wait to receive the whole sentence before sending. Each tag within the sentence is parsed and queued for transmit as it is received.
  • Checksums are calculated, but not verified by the radio
  • From powerup until position fix is acquired, $GPGGA, $GPRMC, and $GPZDA tags are swapped for $PDBG tags. This is so that incomplete sentences don't set the time incorrectly. This is probably now unnecessary as is necessary despite suitable padding and fix quality/fix invalid fields have been added to the parsing, hence the radio is probably smart enough to ignore them because the radio will take an empty date field and set the calendar to Jan 1 2000. The tag replacement was a kludge based on some difficulties presented by the cutthrough processing of messages. A better kludge is possibly to only swap the RMC tag and to set it to $GNRMC.
  • The code should be constellation-agnostic and will convert $GxGGA etc messages to $GPGGA for the radio.
  • Negative altitude works :) The radio left-justifies the minus sign though...

New things learned about the VX-8DR GPS operation

I won't go over all the things in Dmitry's and Taylor's analysis of the NMEA parsing of the radio (both are well worth reading), but I'll highlight some points I did not find in either of their writeups-

The radio uses different NMEA sentences for different data fields - 

$GPGGA - Time, Latitude, Longitude, Altitude, Number of satellites
$GPRMC - Date, Speed, Direction
While $GPZDA time/date field is said to be used, in testing, it appears that time and date come from $GPGGA and $GPRMC respectively. For completeness the code base will parse the ZDA message to the Yaesu format anyway.

The radio respects the fix quality and validity fields in the GGA and RMC messages

As long as they appear at the appropriate point in the NMEA string (19th character), a validity of 'V' flags the RMC string as invalid. The radio responds by hiding the compass needle. This might also inhibit date setting. For this to work, it's critical that the time field is padded to 10 characters, regardless of gps fix-state. Values other than 'V' (not necessarily just 'A') seem to cause the message to be regarded as valid. Only RMC messages with an 'A' are regarded as valid. Invalid RMC messages cause the compass needle to be hidden, and the speed to read as 0. However, invalid RMC messages will be used for setting the date.

If the GGA quality field has a '0' (as the 44th character of the string), the GGA field is recognized as invalid, although the Lat/Long data is displayed. The altitude however is displayed as single a hyphen sign. This also might does inhibit the time setting but invalid dates from the RMC field are used.

I'd like to do a bit more analysis to see if automatic beacons are disabled by either quality '0' or validity 'V'  statuses. Update- Manual beacons are disabled when quality is '0', validity is 'V', or if the number of satellites is below 3. While the FGPS-2 reports a Lat/Long of 0N 0E when there is no fix, I'd prefer not to be sending null-island beacons. Currently the Xiao code just sends blank space characters in the Lat/Long fields, but I'm preparing to update the code to send last-known position when the fix is lost.

Time/date updates happen together despite separate sources

The time and date appear to only be set once after power-up. The date won't update until the time has been received and vice versa.

The day of week doesn't get set by GPS

The radio cannot calculate the day of the week from the date. Since day of week isn't provided by the GPS receiver, it's simply not updated.

Refinements for the future

The code works well enough, but the reliability is as of yet untested. Gaining some usage data is probably the first step in improving the code base.

That said, I have these points in mind
  • Power usage on the Xiao might be able to be reduced by calling a sleep method when the RX and TX buffers are empty, then waiting for a serial port interrupt.
  • Similarly, the uBlox GPS power save features might be able to be set in uBlox u-Center.
  • Most of the String object reserve() calls are probably unnecessary. I didn't spot any good documentation on String to make an informed decision. This would reduce the memory overhead and potentially enable the use of MCUs with less memory.
  • Function entry burns quite a few CPU cycles, and the number of function calls could be reduced substantially.
  • More code comments and documentation in github.