Tools for MT3339/PA6H Based GPS
It may seem slightly counter-intuitive, but in order for a GPS unit to produce an accurate fix, it has to know the time, the location of the GPS satellites, and it's own rough location. Odd, given that it's job is to tell YOU those things. Since the satellites broadcast the time and their positions, the GPS unit can get the info but it must have a strong signal (>25dBHz) from 4 satellites for about a minute. If the signal level drops a little or a satellite goes out of view in that minute, the GPS unit has to start over again. Outdoors with a clear view of the sky, this isn't usually a problem. Indoors or when the outdoor view is obstructed by trees, terrain, buildings, etc. it can be impossible to get an initial fix because you just can't get a strong signal from the same 4 satellites for enough time.
"But wait, my cell phone gets a fast fix indoors!". Yep, and there's a reason for that. Being network connected, the phone already knows the exact time and it's rough location as the cell network provides both. As for the location of the satellites at any particular time (the ephemeris data), that's public information and the GPS manufacturers thoughtfully provide files, usually updated nightly and good for 7, 14 or 30 days, that the phone can download. The whole process is called Assisted-GPS and doesn't require as strong a signal (~15dBHz) to get and maintain a fix.
If you going to use your MT3339 based unit only outdoors, no need to read further. Otherwise...
The Adafruit Ultimate GPS is based on the GlobalTop PA6H GPS unit which is in turn based on the MediaTek MT3339 chip. GlobalTop provides the ephemeris data in the form of an EPO (Extended Prediction Orbit) file available from their FTP site (see eporetrieve, below). There are other sources for EPO data, including directly from MediaTek, but there are 2 formats, EPO and EPO-II. The MT3339 in this applications needs the original EPO format and can handle only 7 or 14 day files. That's what's on the GlobalTop site.
So now what? Use the tools...
Get the EPO file:
eporetrieve: Retrieves the current EPO file from the GlobalTop FTP Server
eporetrieve [ <file_name> [ <output_file> ] ]
Example:
# eporetrieve MTK14.EPO /tmp/MTK14.EPO
This script is just a wrapper around wget. It's generally best to do this in the morning UTC to make sure the file is valid for the current time. If you pull it late in the UTC day, you may get a file that starts the next day and is not yet valid.
Inspect the EPO file:
epoinfo: Displays information about an EPO file
usage: epoinfo [-h] <EPO_File>
Prints EPO file information
positional arguments:
<EPO_File> EPO data file
optional arguments:
-h, --help show this help message and exit
You can use '@filename' to read arguments from a file.
To examine the file /tmp/MTK14.EPO...
# epoinfo /tmp/MTK14.EPO
Opening EPO Type I file
Set: 1. GPS Wk: 1832 Hr: 48 Sec: 172800 2015-02-16 23:59:46 to 2015-02-17 05:59:46 UTC
Set: 2. GPS Wk: 1832 Hr: 54 Sec: 194400 2015-02-17 05:59:46 to 2015-02-17 11:59:46 UTC
Set: 3. GPS Wk: 1832 Hr: 60 Sec: 216000 2015-02-17 11:59:46 to 2015-02-17 17:59:46 UTC
Set: 4. GPS Wk: 1832 Hr: 66 Sec: 237600 2015-02-17 17:59:46 to 2015-02-17 23:59:46 UTC
Set: 5. GPS Wk: 1832 Hr: 72 Sec: 259200 2015-02-17 23:59:46 to 2015-02-18 05:59:46 UTC
<snip>
Set: 53. GPS Wk: 1834 Hr: 24 Sec: 86400 2015-03-01 23:59:46 to 2015-03-02 05:59:46 UTC
Set: 54. GPS Wk: 1834 Hr: 30 Sec: 108000 2015-03-02 05:59:46 to 2015-03-02 11:59:46 UTC
Set: 55. GPS Wk: 1834 Hr: 36 Sec: 129600 2015-03-02 11:59:46 to 2015-03-02 17:59:46 UTC
Set: 56. GPS Wk: 1834 Hr: 42 Sec: 151200 2015-03-02 17:59:46 to 2015-03-02 23:59:46 UTC
56 EPO sets. Valid from 2015-02-16 23:59:46 to 2015-03-02 23:59:46 UTC
Each set covers a 6 hour period so for a 14 day file, there should be 56 sets in the file. For the PA6H, make sure the file is a Type I file and that the "Valid from" span includes the current time.
Load the EPO file to the GPS:
epoloader: Loads an EPO file to the GPS
usage: epoloader [-h] [-t yyyy,mm,dd,hh,mm,ss | -]
[-l lat.dddddd,lon.dddddd,alt]
[-s {4800,9600,19200,38400,57600,115200}] [-k] [-c]
<EPO_File> <gps_device>
Loads EPO data sets to MT3339 GPS
positional arguments:
<EPO_File> EPO File or '-' to just set the known parameters
<gps_device> GPS serial device such as '/dev/ttyUSB0'
optional arguments:
-h, --help show this help message and exit
-s {4800,9600,19200,38400,57600,115200}, --speed {4800,9600,19200,38400,57600,115200}
Interface speed
-k, --keep-new-speed Don't restore the old speed on exit
-c, --clear Clears the existing EPO data from the unit
-n, --no-init The unit is already in the correct state
optional known time and location parameters:
-t yyyy,mm,dd,hh,mm,ss | - , --time yyyy,mm,dd,hh,mm,ss | -
Current UTC or UTC from host
-l lat.dddddd,lon.dddddd,alt, --location lat.dddddd,lon.dddddd,alt
Current location specified in decimal degrees and
meters
You can use '@filename' to read arguments from a file.
Before you start this step, make sure you're unit is connected and that the port speed matches the GPS speed. You can use the gpsinit utility (see below) to do this. If you can 'cat' the port where the GPS is connected and get valid NMEA data, you should be OK.
# ## Set the port to raw mode first
# stty -F /dev/tty<something> raw
# cat /dev/tty<something>
$GPGGA,000221.000,3899.0037,N,10499.9070,W,1,10,1.01,1795.4,M,-20.7,M,,*6C
$GPGLL,3899.0037,N,10499.9070,W,000221.000,A,A*4E
$GPRMC,000221.000,A,3899.0037,N,10499.9070,W,0.16,224.89,180215,,,A*74
$GPVTG,224.89,T,,M,0.16,N,0.30,K,A*3C
$GPZDA,000221.000,18,02,2015,,*5A
If your unit is at factory state or it's time and last known location are off significantly, you'll need to supply your location and the time in addition to the EPO file. If you're unit already has a fix and you just need to update EPO data, you don't need to supply the location and time.
You location and altitude must be specified in decimal degrees, using negative numbers for West and South, and meters. Google Earth is a good source. The more accurate the better but the location needs to be within 30km.
For the time, just let epoloader get it from your host system using the '-t-' option, assuming it's accurate. If not, specify it as shown above in UTC.
Since you can specify options to epoloader in a file, you may want to create a file that has the location and time options in it. For instance, if you're on the lawn outside the Washington Monument...
echo "-l 38.889468,-77.352420,5 -t-" > epoloader.conf
Finally a last word on port speed. By now you've already made sure that the port speed and the unit speed match. If the unit is at factory state, it's probably at 9600 baud which is just a touch slow. By supplying the '-s' option to epoloader, you can specify the speed to use for the load and the program will take care of setting both the unit and the port to the correct speed, then resetting both to their original speed on completion. Use 115200 (the default) unless you have a flaky setup. You can also specify the '-k' option to leave the unit and port at the new speed.
NOTE: It's pretty much impossible to mess up the GPS unit with this process as it doesn't touch the unit's firmware. If you get into a bad communications state, just try again, use gpsinit, try holding the EN signal low for a second, or remove the power and battery for a few seconds to reset back to factory state.
Now you're ready. Assuming your location and time is in epoloader.conf, the EPO file is /tmp/MTK14.EPO, your device is connected to /dev/ttyUSB1 and you want to use the default 115200 speed, then...
# epoloader @epoloader.conf /tmp/MTK14.EPO /dev/ttyUSB1
Opening EPO Type I file
Current port speed: 9600
Set port speed: 115200
Setting known values: 38.889468,-77.352420,5 2015,02,17,23,15,35
Clearing existing EPO data
Setting binary mode, speed: 115200
Sending 56 EPO sets
Sending set 1. Valid from 2015-02-16 23:59:46 UTC
Sending set 2. Valid from 2015-02-17 05:59:46 UTC
Sending set 3. Valid from 2015-02-17 11:59:46 UTC
Sending set 4. Valid from 2015-02-17 17:59:46 UTC
Sending set 5. Valid from 2015-02-17 23:59:46 UTC
<snip>
Sending set 52. Valid from 2015-03-01 17:59:46 UTC
Sending set 53. Valid from 2015-03-01 23:59:46 UTC
Sending set 54. Valid from 2015-03-02 05:59:46 UTC
Sending set 55. Valid from 2015-03-02 11:59:46 UTC
Sending set 56. Valid from 2015-03-02 17:59:46 UTC
56 sets sent. Valid from 2015-02-16 23:59:46 to 2015-03-02 23:59:46 UTC
Resetting NMEA Mode
Verified EPO in NVRAM matches file
At 115200, the process should take about 17 seconds. If you didn't specify the '-k' option, the unit and the port will be returned to their previous speed.
Does it make a difference??
Oh yes... Look at the times for Factory Reset. The difference is amazing.
StartFrom:
Factory: Factory reset
Reset: After first fix, hot start or hold enable pin low for 1 sec
PowerCycle: After first fix, remove VCC for 5 seconds (with backup battery connected)
Antenna: Internal or External Active
AntLocation:
ClearSky: Outside, clear sky
Inside: First floor room with window
DeepInside: First floor interior room, no window
EPO: Y - loaded, N - not loaded
TTFF: Time to First Fix in seconds (3 tests)
StartFrom | Antenna | AntLocation | EPO | TTFF1 | TTFF2 | TTFF3 | |
---|---|---|---|---|---|---|---|
Factory | External | Clear Sky | N | ❗ | 68 | 72 | 150 |
Factory | External | Clear Sky | Y | ✅ | 2 | 2 | 2 |
Factory | External | Deep Inside | N | 420 | 335 | 504 | |
Factory | External | Deep Inside | Y | ✅ | 14 | 20 | 17 |
Factory | External | Inside | N | 590 | 367 | 283 | |
Factory | External | Inside | Y | ✅ | 10 | 6 | 14 |
Factory | Internal | Inside | N | ❌ | 2422 | 3600* | 7200* |
Factory | Internal | Inside | Y | ✅ | 14 | 33 | 15 |
PowerCycle | External | Clear Sky | N | 13 | 15 | 9 | |
PowerCycle | External | Clear Sky | Y | 1 | 8 | 2 | |
PowerCycle | External | Deep Inside | N | 2 | 6 | 2 | |
PowerCycle | External | Deep Inside | Y | 5 | 19 | 10 | |
PowerCycle | External | Inside | N | 8 | 6 | 15 | |
PowerCycle | External | Inside | Y | 13 | 10 | 7 | |
PowerCycle | Internal | Inside | N | 10 | 9 | 9 | |
PowerCycle | Internal | Inside | Y | 20 | 25 | 16 | |
Reset | External | Clear Sky | N | 8 | 10 | 12 | |
Reset | External | Clear Sky | Y | 7 | 7 | 7 | |
Reset | External | Deep Inside | N | 3 | 6 | 6 | |
Reset | External | Deep Inside | Y | 7 | 8 | 5 | |
Reset | External | Inside | N | 6 | 4 | 5 | |
Reset | External | Inside | Y | 5 | 5 | 5 | |
Reset | Internal | Inside | N | 6 | 4 | 11 | |
Reset | Internal | Inside | Y | 7 | 4 | 4 | |
* | Gave Up |
gpsinit: Initializes GPS configuration
usage: gpsinit [-h] [-s {4800,9600,19200,38400,57600,115200}]
[-i <init_command> | -f <command_file>]
<gps_device>
Initialized GPS to known state
positional arguments:
<gps_device> GPS serial device such as '/dev/ttyUSB0'
optional arguments:
-h, --help show this help message and exit
-s {4800,9600,19200,38400,57600,115200}, --speed {4800,9600,19200,38400,57600,115200}
Interface speed
-i <init_command>, --init_command <init_command>
A single initialization command such as 'PMTK101'
-f <command_file>, --command_file <command_file>
A file containing commands used to initialize the GPS
You can use '@filename' to read arguments from a file.
gpsinit can help get the GPS unit to a known state. It will attempt to get the port and GPS unit to the same speed, then send commands of your choosing to set update rate, enable/disable NMEA sentences, etc. You can specify the desired speed and a single command on the command line with the '-i' and '-s' options or the speed and a list of commands in a file specified by the '-f' option.
This is an example gpsinit_reset.conf that clears the EPO data, does a factory reset, sets some defaults, sets NMEA sentences and frequency and finally does an epo load.
# You can use the following variables in this file...
# ${SPEED}
# ${DEVICE}
#
# The following commands are recognized...
#
# sleep <seconds> Sleep for n.nnn seconds
# set_system_clock Gets the date/time from the GPS unit and sets the system clock
# setspeed <newspeed> Set new port and unit speed to <newspeed>
# epoloader <epoloader_args> Run epoloader
# factory_reset Clear system/user configurations then cold start
# The unit and port speed will be reset to 9600
# The following commands can be prefixed with '-' to not wait for an ACK.
# hot_start Restart using all available data
# warm_start Don't use Ephemeris at restart
# cold_start Don't use Time, Position, Almanacs and Ephemeris
# data at re‐start
# PMTKnnn,<args> Send the specified PMTK command
#
# Clear the EPO NVRAM
PMTK127
# Factory reset
factory_reset
# Now set to 115200
setspeed 115200
# Set DGPS mode to SBAS
PMTK301,2
# Set SBAS Enabled
PMTK313,1
# Set NMEA Sentence Output
PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0
# Set SBAS 'Integrity' Mode
PMTK319,1
# Disable Periodic Mode
PMTK225,0
# Enable AIC Mode
PMTK286,1
# Enable EASY Mode
PMTK869,1,1
# Set output rate to 1 second
PMTK220,1000
# Load the EPO.
epoloader -c -s ${SPEED} @gpsinit_loc.conf /tmp/MTK14.EPO ${DEVICE}
# You shouldn't put anything after the epolaoder.
# It can interfere with the unit getting it's initlal fix.
# gpsinit -f gpsinit_reset.conf /dev/ttyUSB0
gpssend: Sends a single command to the GPS
gpssend <command_string> <gps_device>
Example:
# ## Send a Hot Start command to the GPS unit
# gpssend PMTK101 /dev/ttyUSB0
# ## Writes '$PMTK101*32\r\n'
Sometimes you just want to send a single command to the GPS unit but having to calculate the required checksum is a pain. gpssend is a simple shell script that does the calculation for you and writes the result to the GPS device.
###gpsstatus: Continuously displays simple GPS output
gpsstatus <gps_device>
This shell script just displays the output of the GPS unit and calculates the time to first fix.