Building an APRS Tracker

I’ve been running an APRS RF-to-internet gateway for a few months now. It uses javAPRSSrvr as the gateway program and soundmodem as a soundcard modem, both running on a remote Linux machine. Both programs are very reliable, running for months without a fault. I spent a bit of time trying to get the two programs to communicate over a virtual serial port, but this did not work, so I eventually switched to AX25 kernel-mode support, which worked out of the box on Ubuntu Linux.

I want to track myself using APRS, so I needed a tracker.There are several published hardware and software designs on the Internet, and I originally considered building a tracker based on one of these designs. But I eventually decided to build a tracker that is not based directly on any existing design. Mostly, I wanted to end up with a high-quality and flexible code that could be easily ported to different hardware platforms and to different uses. I’m not yet there, but I’ve got a working prototype that’s running my own code.

One thing I knew I wanted to do was to avoid a modem chip. Some APRS trackers and digipeaters use a modem chip, normally the mx614. A modem microcontroller would be able to produce and decode a 1200b/s AX25 signal in software. There are several trackers that do that already, like Gary Dion’s WhereAVR and Byonics‘ TinyTrak3 and TinyTrak4.

The prototype is running on an microcontroller development board that I use at work for teaching a course on embedded computing. It has an LPC2148 microcontroller, which has an ARM processor, and lots of on-board peripherals. The tracker currently uses almost none of the on-board peripherals except for the LCD screen. The board is connected to a GPS module and to a VHF radio. The GPS is a NEO-5Q module from ublox; it’s mounted on a board that also has a microcontroller and a bunch of other components (a prototype from an old wifi-based tracker project I participated in), but I’m only powering and using the GPS module on this board. The GPS is connected to an external active patch antenna. The radio I’m using is a Baofeng UV-3R, which I bought mainly for this purpose. It cost less than $50 including shipping, considerably cheaper than some dedicated VHF tracker transmitters. The radio is connected to the microcontroller through a little interface board that I built. Both this interface board and the GPS module are currently stuck into a breadboard, with wires connecting the microcontroller board to the breadboard.

The interface board performs 3 functions. It connects the DAC output of the microcontroller to the microphone input of the radio. This signal is routed through a trimmer resistor, to adjust modulation in the radio (it needs a much smaller amplitude than the DAC produces), and though a DC blocking capacitor. The board also routes the audio output of the radio to an ADC pin of the microcontroller, but I haven’t tested this yet. Finally, an open-collector NPN transistor switches the radio to transmit. I had some trouble with this transmit-receive switch: RF would get into the circuit and would keep the radio transmitting long after the microcontroller tried to turn the transistor off. I solved this with two 0.01μF decoupling capacitors on both the base and the collector of the switching transistor.

I used my own software drivers for the microcontroller (for it’s UARTs, DAC, etc.), but I used code from other APRS open-source projects for building up packets and for producing the audio output of the modem. I will release the software once it is more or less stable. I used three codes: Tracker2’s code by Scott Miller of Argent Data, the AX25 code in BeRTOS (a real-time operating system), and soundmodem. I have a lot of positive experience with soundmodem running on the Linux box, so hopefully it will work well on an embedded system. Fortunately, it uses fixed-point arithmetic, rather than floating point which is not supported in hardware on small microcontrollers, so it should work. But I have not tested the demodulator yet. The parts of soundmodem that I’m already using required quite a bit of hacking, unfortunately. I initially tried to keep the modem code as is, but I gave up after a while; the over structure does not work too well in an embedded setting.

I’ve been working on the tracker for a few days, and yesterday it got to the point where it was working on the bench: parsing GPS data, producing packets, and sending them to the radio. The packets were well-formed and my gateway decoded them (actually just some of them;  I’m not sure if the 2W signal from the radio was too weak, or the transmitted audio is not good for some reason). It was time to take the tracker for a ride. I took it to the car and hooked it to the cigarette-ligher’s socket. The LPC2148 board can be powered by up to 15V, and it can produces enough 3.3V power for the GPS, so I assumed everything would work. It did for a while (you can see some position spots in the map on the right), but after a few minutes the tracker started rebooting itself every second or so. I touched the regulators on the board and they were pretty warm, so I’m assuming that one of them overheated, shut down, and caused the system to reset. I guess I can’t power this unit directly from the car’s battery; I’ll need to drop the voltage with an off-board regulator first.

Next, I’m going to work on the AX25 demodulator, hopefully producing a tracker that can also decode packets.

A Microcontroller AM Transmitter (and a Lesson in EMI)

It turns out that my post on the PLL of the LPC1768 was a bit too harsh. It is true that it can’t generate too many high frequencies when the reference frequency is in the kHz range. But it can generate quite a bit of frequencies with a 1MHz reference. Around 1MHz, it can synthesize frequencies spaces 2kHz apart. Around 10MHz, the frequencies are 20kHz apart, and so on. You get the idea.

When I realized that I can do this, I decided to test this by generating a signal that an AM radio can pick up. I succeeded. But let’s talk about the PLL first.

The idea is simple. We will divide the 12MHz clock signal of the mbed board by 12, to generate a 1MHz reference. Now we multiply it by an integer between 275 and 550 to generate the PLL output frequency. To generate a clock signal that is slow enough to drive the microcontroller (100MHz or less), we need to divide by at least 6. I will assume that we divide by 5 and that we don’t multiply by 500, to keep the math simple. We have a CPU Clock frequency between 55MHz and 100MHz; the possible frequencies are 200kHz apart (the 1MHz spacing of the output of the PLL divided by 5). This clock signal will drive a timer or PWM module (I used PWM1), which will divide it again to obtain the output frequency and drive one of the pins.

I tried this first with a very slow output frequency of 1Hz to make sure the PLL works as I think it should and to test everything. The PWM module drove pin PWM1.2, which is connected to one of the mbed on-board LEDs.

Next, I upped the frequency to 1MHz and tested it on a scope; the signal was a nice 1MHz square wave. By connecting and disconnecting this signal from a pin using an interrupt-service routine driven by a another timer (I used the systick timer), I modulated the 1MHz signal. I used a modulation frequency of 1kHz. Connecting the pin of the mbed to a 30cm piece of wire generated a signal strong enough to be easily picked up by an AM radio at a distance of up to a meter or so. Turn on the mbed and you hear the 1kHz signal on the AM radio, turn it off and you don’t.

There are obviously better ways to modulate the RF signal. One is to vary the width of the pulse, like Michael Kleinigger did with an AVR microcontroller. This works reasonably at low RF frequencies, when the divisor you use to generate the RF signal from the CPU frequency is high (a large divisor gives you many pulse widths). It does not work well at higher frequencies. On the LPC1768 another option is to use the digital-to-analog converter to drive an analog modulator.

Also, the signal emitted by my 30cm wire is not a 1MHz modulated signal; it is a modulated square wave, which also contain large amount of energy in harmonics of 1MHz. To eliminate them, you need a filter; Michael’s article shows a very simple one. For regular use (where legal), a more sophisticated filter is necessary, and a small power amplifier also won’t hurt, at least to isolate the microcontroller from the antenna.

This little experiment is also an interesting lesson in how easy it is to generate electromagnetic interference (EMI). All I did was to connect a 1MHz digital signal to a 30cm piece of wire. This generated enough electromagnetic energy to be easily received by a radio. I did this intentionally, but it’s very easy to do that unintentionally, with long wires on a PCB or in a box. If it’s not shielded (or driven differentially to cancel out the field), it will emit.

A PLL Mystery

In a previous post I built a phase-locked loop (PLL) in which parts of the loop was implemented by a microcontroller. Some microcontrollers (MCUs) have an on-board PLL for generating their CPU clock. In particular, can we generate frequencies that are spaced fairly closely, say 8kHz apart? Many MCUs have PLLs that can generate frequencies that are about 1MHz apart. But how about closer spacing?

When I received an mbed kit with an LPC1768 MCU, I discovered something interesting in the user manual of the ‘1768. It has a PLL that generates the CPU clock. The reference clock for the PLL can be either a high-frequency crystal oscillator (12MHz on the mbed), or a 32kHz crystal oscillator. In principle, this might allow the generation of closely-spaced frequencies. You can even divide the 32kHz clock down first, to generate frequencies that are, say, 8192Hz apart.

Reading the manual more carefully revealed that the PLL effectively has two modes. In both modes, the PLL output frequency is

Fout = (2 × M × Fin) / N

The output must be between 275 and 550MHz. It must be then divided to produce a CPU frequency of 100MHz or less. The value N is an integer between 1 and 32. The value M is also an integer. It can assume any value between 6 and 512, plus 65 specific values between 4272 and 24170. When Fin=32kHz, only the 65 large M’s are relevant; smaller M do not allow Fout to reach the minimum value of 275MHz.

Why 65 specific values rather than any 15-bit value? I could not think of a reason. If arbitrary values work, then I would be able to generate closely-spaced CPU frequencies. For example, by using Fin=32kHz and N=1, values of M between 4197 and 8390 generate valid output frequencies, spaced 64kHz apart. Division by 6 to bring the PLL’s output frequencies below 100Mhz leads to CPU frequencies of 46MHz and 92MHz, spaced 11kHz apart. To obtain lower CPU frequencies we can divide by more than 6, say by 12, which will lead to even finer spacing.

Does it work? No. I wrote a program to test this. What I discovered is that the PLL works fine with the 65 values of M that are specified in the user manual, but not with other values. I am really stumped by this. The user manual indeed says that other values won’t work, but I can’t figure out why. The 65 valid values don’t have a common divisor; they seem to be arbitrary. Too bad. If somebody knows what’s the PLL structure that allows only these 65 values to work, let me know; I’m curious.

A few words about the mbed kit. It is an interesting concept, designed to make it as easy as possible to get started with embedded programming. The kit is a printed-circuit board that is designed to plug into a breadboard. The board contains a microcontroller, some associated components (a 32kHz crystal and a 12MHz oscillator, for example), and a custom interface chip. The interface chip has a USB interface and is programmed to appear to the USB host as a storage device. You copy a binary file containing an LPC1768 program to the storage device. The next time you press the reset button, the interface chip downloads the program to the ‘1768 though a JTAG interface. This setup allows this to download programs to the microcontroller without installing any driver on your PC; this is pretty cool. The mbed website contains an on-line compiler. You author your program in a web browser. When you are done, you click on a button and the web site compiles the program and the browser downloads the binary program. So you don’t even need to install a compiler on your PC. Again, pretty cool.

Thanks to Pete Cooper who ported some of the mbed support code to gcc, I was also able to compile programs for the mbed on my laptop (using Code Sourcery’s free G++ Lite Edition build of gcc and it’s tools).

A Microcontroller-Based Phase-Locked Loop

The arrival of a MSP430 LaunchPad microcontroller kit motivated me to try out something that I’ve been thinking about for a while.

If you look at recent homebrew and kit radios, you find that many of them use an Si570 synthesizer chip as a local oscillator. The Si570 is really something of a wonder chip, so there is no wonder it took over so completely. It is small, very easy to integrate into a circuit, generates a stable square wave (which is what the switching mixers in many recent radios need), and can be quickly tuned by a microcontroller down to a single Hertz. It comes in several versions, but even the simplest one generates frequencies up to 160MHz, which is handy given that most radios divide the frequency by 4 before it is applied to the mixer.

For many applications, including software-defined radios, the Si570 is better than the digital direct synthesizer (DDS) chips that were widely used before the Si570 was introduced.

The only problem with the Si570 is that it is a little expensive. It currently costs around $25 in single quantities, dropping to $17 in quantities of 25 (and getting a bit cheaper at large quantities). Not terribly expensive, but not cheap. I was therefore wondering whether there is a lower cost solution that would still be reasonably simple (it’s hard to beat the Si570 for simplicity).

Trying to stick to the specifications of the Si570 is useless; you need a design just like the Si570, so it is bound to end up more complicated and probably more expensive. You must be less greedy. Two features of the Si570 that software-defined radios for amateur use do not need are the high frequency resolution (something like a single Hertz in the Si570) and rapid frequency switching (10ms for large frequency changes, 0.1ms for small changes). We do not need these features because in a software-defined radio (SDR), you can use coarse tuning of the center frequency and still receive any narrow-band signal within at least 24kHz of the center frequency using DSP. Also, because the fine tuning is down in DSP, the convenience we would loose if the center frequency switches slowly (say in a second or two) is not that terrible. Achieving fast frequency switching and high frequency resolution is difficult; a major part of the solution in the Si570 is an internal oscillator that runs in the 5GHz range. Without going to such high frequency and then dividing down, it is difficult to achieve these goals.

So here is the strategy: for a Softrock-class radio, we will use a phase-locked loop (PLL) that tunes using a resolution of 8kHz, say, and which might lock onto the frequency a little slowly. We will do this by dividing a crystal oscillator down to 8kHz, dividing a variable frequency oscillator by some integer so that it produces 8kHz when tuned to a desired frequency, and lock them. For example, to generate 8.008MHz, we will divide the variable oscillator by 1001.

What I wanted to try is to generate the 8kHz reference and to divide the high-frequency output using a microcontroller. Most microcontrollers have one or more timer-counters that can be used for these purposes. When the LauncPad arrived, I decided to see if I can make this work.

A few words about the LaunchPad: it is a very inexpensive ($4.30) development kit intended to introduce people to Texas Instruments’ MSP430 microcontroller family (it seems to me that TI is selling it below cost). It includes a board that contains both a programming/debugging interface, a microcontroller in a socket, two LEDs and one switch, and pads for connecting other circuits to the microcontroller. In terms of features it is similar to TI’s earlier introductory kit, the ez430, which I have used before, but it is easier to use (because it is physically bigger and has more features) and much cheaper. The LaunchPad comes with two 14-pin microcontrollers from the MSP430 16-bit family. Both are low-end devices with small memories and without many peripherals (one has a ADC and the other does not).

To generate accurate frequencies, I need a crystal oscillator, so I soldered into the LauchPad the 32768Hz crystal that comes in the box. The MCU uses this crystal to generate an on-chip 32kHz signal that can drive the different peripherals on the chip. How do I generate an 8kHz output clock from the 32kHz clock? We can use the MCU’s timer to generate the 8kHz signal, but this would use up the single counter-timer on the MCU, which we need for the PLL’s programmable divider. I decided to use the MCU’s interval timer instead. It can’t generate an ouput signal directly, but it can invoke an interrupt service routine ISR. It can’t invoke the ISR on every tick of the 32kHz clock, only every 64 (or less often). So the ISR runs 512 times per second. The ISR flips the state of an output pin, so the signal we see on that pin is a 256Hz square wave. Not the 8kHz I wanted, but still usable.

Because I used an ISR to generate the reference clock for the PLL, I can’t use interrupts for anything else. Otherwise, the 512Hz interrupt might get a little delayed, if another ISR runs while it needs to be invoked. This will cause jitter in the reference clock, which will cause jitter in the output. We don’t want that, so we won’t use interrupts for anything else.

The programmable divider is easy. We feed the high frequency signal to the TACLK pin of the microcontoller, program the counter-timer to use this external signal as its driving clock, and we program the same counter-timer to output a PWM signal on an output pin. The timer can count up to 65535, so in theory we can handle signals of up to 16.7MHz. The data sheet says that the MCU can only handle input clocks of 16MHz or less, so this sets the limit, not the divider.

To complete the PLL, we need a voltage-controlled oscillator (VCO), a phase comparator, and a loop filter and/or amplifier. I used a 74HC4046 for the first two, and an RC filter for the third. The 74HC4046’s VCO can go up to about 40MHz (depending on the manufacturer; I used a chip from Philips). It has three different phase comparators, PC1, PC2, and PC3. I used PC2, which does not lock on harmonics of the reference signal. The diagram below shows the overall structure of the loop. Resistors R1, R2 and capacitor C1 set the center frequency and range of the VCO. There are three connections between the MSP430 and the ‘4046, which you can also see in the picture above (using the white, yellow, and brown clips).

I programmed the MSP430 to divide TACLK by 40,000 and the loop locked at 5.12MHz. Changing the divider to 20,000 produced a 10.48MHz signal. The frequency was correct, but was not stable; I basically used a random loop filter, so that’s probably the reason. Another possible problem is that the frequency-setting components I used in the VCO resulted in very wide tuning range, which does not promote stability. But the basic scheme works.

A few comments on the design and where it might go next:

  • The main constraint on the frequency that this design can attain is the 74HC4046; the one from Philips can go only up to 40MHz, and devices from some other manufacturers have even lower frequency limits. Since Softrock-style radios divide their clocks by 4, a ‘4046 can only be for RF frequencies of up to 10MHz or so. I am not aware of replacements that would go up to, say, 100MHz or 200MHz.
  • MSP430 MCUs from the x2 series can only divide frequencies of up to 16MHz. PICs and dsPICs can go much higher, up to 80MHz in dsPIC33s. However, I think that the asynchronous timer of PICs can’t drive a PWM signal, which means that the divided clock will need to be produced by an ISR; but on PICs it should be possible to generate the reference signal using PWM.
  • Slightly larger MSP430s, in particular the MSP430F2274 (which I have mounted on a prototyping board somewhere), have two timer-counters and on-chip opamps. The extra timer should permit an 8kHz reference to be produced, and without using ISRs. It should be possible to use the opamps as loop amplifiers.
  • An interesting improvement would be to try to implement the phase comparator in software. Software phase comparators are used in some recent huff-and-puff stabilizers (Hans Summer’s web site contains a fantastic collection of articles on this technique, including some clever designs by Hans himself).  My sense is that it would be difficult to respond correctly in software to small phase differences, but perhaps I’m wrong.