Patching Freetrak APRS tracker to work with modern GPS modules

10 minute read

As part of looking at typical PMR446 coverage, I want to use APRS on PMR446. I want to get a Freetrak APRS tracker to automatically key the Tx and then walk/bike around to see what sort of coverage I get.

I’d expected the hardest part was going to be interfacing to the rig, but that happened to be the easy part. I also modded the hardware design that called for a fancypants 5V rail to rail opamp to unity gain buffer the high-impedance DAC output from the PIC - a 2N3904 emitter follower with 2.2k emitter resistor is a perfectly acceptable substitute1. I did convince myself the DAC didn’t like a 10k load resistor, which was the obvious other choice for a cheapskate.

Freetrak’s output is not a thing of great refinement, but the rig filtering gets rid of all the jaggies (Persistence mode on the scope, the vertical axis mistakenly believes I used a 10x rather than 1x probe)

Freetrak is showing its age

Typical GPS serial NMEA outputs 10 years ago were once a second which was plenty back in the day, but drones became popular more recently, which need a quicker update rate. Freetrak version 2.02B was last updated in 2007, and it makes two assumptions that don’t necessarily hold nowadays:

  • the $GPRMC happens once a second.
  • GPS is the only navigation system the receiver picks up

Neither of these is true now. The anonymous Chinese clone pretending to be a Ublox GPS responds to GLONASS and a couple of other GPS-like systems, and therefore issues a $GNRMC sentence, five times a second.

The first problem was I had grief programming Freetrak from the provided hex file. It is possible my ancient PIC programmer can’t do that a fuse configuration of 0x3d22. Rather than take it to bits and try and understand it, I replaced it with what looks like a reasonable2 equivalent. I edited the .ASM file changing config to

;               3/25/07
;               10 Mhz CLOCK	Ver 2.02B
;               26 Sept 2020 RM
;               mod config to something I can program
;------------------------------------------------------------
;
        LIST    P=16F628A
	ERRORLEVEL	-302
        include <P16F628A.INC>
;       __CONFIG        h'3d22'
 __config  _HS_OSC & _LVP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_OFF  & _CP_OFF & _MCLRE_OFF
 

and recompiled. This was successful, in that I could talk to the chip and set up all this good stuff starting like so

FreeTrak v2.02B (c)2007
Enter TOCALL

This tells me I have RS232 basically working and the program running in the PIC.

Beitan BN-800 GPS module

However, having done that nothing happened when the GPS was wired up. I know RS232 worked from earlier. I used a noname GPS from China called a Beitan BN-800, which is meant to be mounted in a drone hardware stack. You power this with 5V which I use for the PIC, it supplies a 3.3V TTL signal out. I’m actually quite impressed with the performance of this - it has been in my junkbox for a couple of years, I bought it for another project. I sparked it up and it was out of the gate like a whippet - it got itself a fix from a cold start indoors within a couple of minutes.

You have to use Ublox u-center to set up the chip to output NMEA at 4800 8-N-1

Looking at the output it puts out

$GNRMC,182102.00,A,5109.2

and the software wants $GPRMC around line 130

data_table
        addwf   PCL,F                   ;add offset to pc
        dt      "GPRMC,,A,*xx",0 

so I need to fiddle with the talker ID thusly and a more expansive description with screenshots

fiddle with the TalkerID in configure->NMEA->NMEA2 drop-down to make it output $GPRMC

Now I get

$GPRMC,205346.60,A,5109.2

and I am rewarded with blinkenlights on the PIC as messages come through. The Freetrak happens to use the count of $GPRMC messages for the timing, and puts the APRSsignals out about twice as often as I asked it to. Presumably because all this Russian Glonass stuff is coming through.

I masked all but GPS, but even setting the holdoff to 90 gives me a TX rate of about 30 seconds. I wouldn’t want to set this loose on 144.800 ,something else is wrong. The TX rate is variable, too.

Investigating with the text console on Ublox I observe I get 5 $GPRMC messages per second - a quick blast of three seconds shows

08:06:46  $GPRMC,080645.60,A,5109.2...
08:06:46  $GPRMC,080645.80,A,5109.2...
08:06:46  $GPRMC,080646.00,A,5109.2...
08:06:46  $GPRMC,080646.20,A,5109.2...
08:06:46  $GPRMC,080646.40,A,5109.2...
08:06:47  $GPRMC,080646.60,A,5109.2...
08:06:47  $GPRMC,080646.80,A,5109.2...
08:06:47  $GPRMC,080647.00,A,5109.2...
08:06:47  $GPRMC,080647.20,A,5109.2...
08:06:47  $GPRMC,080647.40,A,5109.2...
08:06:48  $GPRMC,080647.60,A,5109.2...
08:06:48  $GPRMC,080647.80,A,5109.2...
08:06:48  $GPRMC,080648.00,A,5109.2...
08:06:48  $GPRMC,080648.20,A,5109.2...
08:06:48  $GPRMC,080648.40,A,5109.2...

I would need to hack the code to fix this. N0QBH worked hard to limit entry, but in his code the tens digit is used to increment the holdoff counter by 10 in a loop decrementing tens to 0. That gives a maximum of 90 (+9 for the units) but I could hack this by changing the loop increment from 10 to 27. Entering 99 would then give me a delay of 9*27 + 9 = 252, about 2.5 times the duration, about 1¼ minutes, which is a little bit more civilised. The section of code is about line 1260ff

	movwf	loop_count		;
	movlw	.10
	addwf	temp,F			;add 10 each loop
	decfsz	loop_count,F
	goto	$-2			;

This is messy, so I investigated if Ublox would let me ease off on the rate of update. The quadcopter guys probably need as much update as they can, whereas freetrak just doesn’t need that firehose of data. The processor inside Ublox is much more advanced than the PIC is, as steam gives way to sail, it is the job of the more powerful processor to change to work with the simpler one.

I eased the rate back to 1000ms (once a second) from the 200ms it was set at before. As usual send, save config, Receiver Action Save config
08:42:59  $GPGST,084259.00,43,,,,4.9,3.8,11*7A
08:43:00  $GPRMC,084300.00,A,5109.2...
08:43:01  $GPRMC,084301.00,A,5109.2...
08:43:02  $GPRMC,084302.00,A,5109.2...
08:43:03  $GPRMC,084303.00,A,5109.2...
08:43:04  $GPRMC,084304.00,A,5109.2...
08:43:05  $GPRMC,084305.00,A,5109.2...
08:43:06  $GPRMC,084306.00,A,5109.2...
08:43:07  $GPRMC,084307.00,A,5109.2...
08:43:08  $GPRMC,084308.00,A,5109.2...
08:43:09  $GPRMC,084309.00,A,5109.2...
08:43:10  $GPRMC,084310.00,A,5109.2...
08:43:11  $GPRMC,084311.00,A,5109.2...

A delay of 90 now gives me a Tx interval of about a minute and a half, which is civilised, at least on a handheld device. It is also what I would expect. I re-enabled Glonass, which should improve my ability to get a fix, now that I have worked out where the update rate is set. I don’t need to butcher N0QBH’s hard work, which is gratifying. There is now a steady 1Hz flash on the LED from freetrak rather than the manic 5Hz shimmering, and a long pulse every 90 seconds. Win. What was probably happening before was the data was probably overrunning the PIC’s ability to cope, it could get about every other message out and skipped the others, which might explain the slightly random intervals I observed. It is stable now.

Monitoring the output of the emitter follower with UZ7HO’s soundmodem shows the Freetrak basically kicks out the entire $GPRMC messages along these lines (C0RVID is the callsign I will use for PMR446, you have to give it something, and some jackdaws kicked off as I was looking for something to use)

1:Fm C0RVID To APRS Via WIDE2-2 [09:58:51R] [++-] $GPRMC,085850.00,A,5109.2,N,00242.8,W,0.040,,280920,,,A*61

Every ninth message it appends Freetrak after the GPRMC CRC. The instructions tell me I can use compressed mode, which requires

  • Compressed mode requires the GPS send RMC type sentences configured to DDMM.mm (minutes in hundredths) format.

which appears to be the case. However, it didn’t work. Perhaps they really mean hundredths, my GPRMC messages are DDMM.nnnnn format.

Getting this on PMR446

I used the test program from Freetrak to send alternating 1200/2200 tones, I had the same trouble programming the test tone HEX file as the main program, and had to recompile it with the same mod to the _config options. Doing that resulted in a successful deedle-deedle-deedle signal.

signal as received via PMR at correct drive level

Using this I set up the drive level to the PMR446 rig, by increasing drive until the twist started to creep up, then backing off. Twist is the difference between the high tone and low tone. Because the higher audio frequencies are emphasised in most NBFM systems, the higher tone hits the clipper earlier than the lower tone as levels increase. If you adjust for max level the lower tone is just clipped and the higher tone is greatly clipped. When this signal with roughly the same level of high and low tone is de-emphasised, the higher tone is seriously attenuated. Twist makes it harder to decode the signal, particularly in hardware. Thirty years after packet radio was invented hardly anyone uses hardware modem chips to decode the signal, it’s done in DSP, however, the tones should still be about the same strength on decode for optimum performance against noise, though DSP decoding like Direwolf or UZ7HO’s soundmodem doesn’t fall over as early as the XR-2211 in the 1990s packet TNCs.

using Freetrak on PMR446

I replaced the setup chip with the main Freetrak chip. The PMR rig keys up and I can hear the APRS bzzzrt go out, though it seems incredibly short. However, I had managed to decode the signal as sent, so I put it over PMR on channel 10 no CTCSS. UZ7HO’s soundmodem would decode the odd transmission, but it was very fussy about audio drive level. Inspecting the received signal showed a DC shift that somewhat dominated the signal

DC shift, the lower trace shows this through a 500Hz Butterworth order 2 HPF

In the end I made a compromise, and terminated the receiving PMR rig’s output in 47Ω. Some of the massive DC heave-ho was because this is designed for a 32 ohm earpiece at a guess, and I was feeding it into 47k of the line input of a soundcard.

terminating the rig audio output in 47Ω makes the input transient a lot better

I was still only decoding about one transmission out of 20, even with the rigs about 10m apart. Looking at the start of what I am receiving I see only about 2½ 0x7e AX.25 preambles, so I am guessing these PMR rigs are slow to start transmitting and/or to unsquelch. In theory 40 preambles give about ¼ second before data, but that is the time for the transmitting rig to get sorted and for the receiver to unsquelch. I guess that process is marginal.

only about 2½ 0x7e AX.25 preambles - the code says 40 were transmitted

I hacked the code

transmit_set_up
        clrf    TMR2                    ;
        bcf     PIR1,TMR2IF             ;clear flag
;
        movlw   b'10000000'             ;
        movwf   RCSTA                   ;serial rx off
	movlw	b'00000100'		;
	movwf	T2CON			;TMR2 on
;
        movlw   0xff
        movwf   AX25_crc_hi             ;reset CRC calc
        movwf   AX25_crc_lo
        bsf     PTT_OUT                 ;key radio
        movlw   0x28
        movwf   flag_count              ;40 flag delay

changing this to send out 80 0x7e preamble frames

        bsf     PTT_OUT                 ;key radio
        movlw   0x50
        movwf   flag_count              ;80 flag delay

and now I get 100% decode on PMR446, when using a Baofeng UV-B6 with open squelch. I never worked out how to tell the Floureon to leave the squelch open, perhaps it can’t be done. This was a longer journey than I expected.

coverage map

I tried this on the same route as the previous PMR446 coverage experiment and results were very similar.

APRS gives me a lot more data points than the manual method and the regular spacing in time translating to regular spacing in distance due to the steady walking pace shows areas of patchy reception better. And it’s a lot less work to get the map representation, which draws itself. It confirms the viability of APRS on PMR446, I had to make sure I took APRSIS32 off the APRS-IS servers and use RF only, to avoid injecting funky PMR446 callsigns into APRS-IS.

The distance the signal penetrated into the built up part on a later walk into town reconfirmed that Wikipedia seems to be roughly right when they say

Most of the time the maximum range that a user in a city can expect is a few hundred metres or less.

I got more range across the open moorland than in the urban area, nearly 1.5 km across the moors compared with about 700m in town. In practice you’d get less performance handheld to handheld. Although I did use a Baofeng UV-B6 handheld with the stock antenna for receive it was in a clearer position than a typical handheld would be used, and my feeling is that the squelch on these rigs is set quite aggressively, which is why I used a non-PMR446 rig for receive.

  1. After some experimenting, in practice I follow this with 150k via a capacitor into a 2k2 resistor pulled to ground for PTT so I would probably have got away with driving the 150k resistor straight from the DAC. 

  2. Perhaps there’s a case to be made for enabling the WDT, I don’t know what value N0QBH had for that