I was reading the Thinkgeek catalog a while back and an interesting gadget caught my eye: “Wi-Spy”, a 2.4GHz spectrum analyzer on a USB stick. Coming from the world where “spectrum analyzer” refers to a big benchtop box with a name like
Le Croyright, we can’t afford those Agilent on it, my first thought was, “A good spectrum analyzer in the GHz range is like a gazillion bucks; what’s really inside this thing?”
Not much, it turns out. After seeing the guts I would not use this device for anything remotely demanding accuracy, but on the bright side, it would be pretty straightforward to make your own that works just as well! Possibly with parts that are already on your board (*cough*XBee).
According to this review and a couple other tech sites, the innards of the original are nothing more than a Cypress WirelessUSB SoC (CYWUSB6934) and USB interface. According to this updated review, the latest version switches to TI/Chipcon’s CC2500 radio ($2.15 USD in quantity) and retails for $399.
The “WirelessUSB” and CC2500 radios are inexpensive 2.4GHz radio chips used in devices such as cordless mice, game controllers and remote controls. What it has in common with many other digital radios is an RSSI (Received Signal Strength Indication) register, which can be read out to provide a measure of how much signal (i.e. interference) is present on any given channel. Wireless gadgets normally use such a mechanism to find the cleanest channel to broadcast on. Most any radio chip with an RSSI readout should work here: XBee, TI/Chipcon’s CC25xx parts, Nordic, etc. I have a big nut going right now for Nordic’s nRF24L01, but unfortunately this does not have an RSSI measurement to speak of (there is a 1-bit “collision detect” flag that warns if the RF energy on the current channel is above a set threshold).
So essentially, the firmware running on the dongle consists of:
for (channel=0; channel<255; channel++)
Hell, why didn’t I think of selling $2 of chip and 4 lines of code for $400? ;-) (I’ve even used those old Cypress radios before on a work project – Unigen’s ready-made JUNO module shown here is about 7 bucks.)
As proof of concept (and a cool toy for anyone who has one of these lying around), I have implemented a working Wi-Fi spectrum analyzer on TI’s ez430-RF2500 development kit ($50), a 2-part USB dongle which consists essentially of a CC2500 radio strapped to an MSP430 low-power microcontroller (detachable bottom half) and a USB interface which enumerates as a virtual serial port (top half). The top half doubles as a standalone MSP430 programmer, so this kit is a great cheap way to get started playing with them.
lazy efficient person that I am, I grabbed mspgcc and an existing ez430 RF demo program (JM Kikori’s RF2500 test application – raw transceiver) and just tossed the infinite RSSI loop into the middle of it.
Here is the main addition (simple & sweet). Forgive WordPress’ complete mangling of the formatting.
static void dump_rssi()
for(i=0; i<256; i++)
hal_spi_radio_writeReg( MRFI_CC2500_SPI_REG_CHANNR, i); // Channel number. Default spacing is ~200KHz/channel
hal_spi_radio_cmdStrobe( 0x34 ); // enter Rx mode (not needed except to start autocal)
rssi = (hal_spi_radio_readReg(MRFI_CC2500_SPI_REG_RSSI));
uart0_polled_putc((rssi&0xFE) | (i==0)); // Cheap speed hack: write upper 7 bits of RSSI value (throw away LSB). Use LSB to signal start of 256-channel RSSI byte list
hal_spi_radio_cmdStrobe( 0x36 ); // enter IDLE mode (not needed except for autocal)
The only real divergence of this from the pseudocode loop above is that the CC2500 requires periodic (or frequent, depending who you ask) recalibration, which can be set to be performed automatically on certain conditions (such as entering Rx mode). This setting is enabled, and the code above toggles between Rx and Idle modes between each channel change to trigger auto-calibration. To make things faster (for me as well as the gadget ;-), rather than perform any kind of real serial handshaking to keep the dongle and the graphing script in sync, I just truncate the least significant bit of the RSSI reading (1/2dBm) and use it to flag the start of the 256-channel sweep.
A more efficient approach would be to perform such calibration once per channel and cache the results (writing them back along with each channel change), which would in theory allow for much faster channel changes. But it’s really a moot point since here the 9600-baud connection to the virtual COM port (MSP430 <–> USB controller) is the limiter of maximum speed.
Most of the time in this project went into tweaking around with the CC2500’s fifty billion or so configuration register bits, not all of which are really documented. In the end I just installed their win32 configuration wizard for the undocumented voodoo (e.g. correct IF setting) and annoying math, and hand-tweaked the remaining settings. For this I set the base frequency to 2400MHz, and the channel spacing to ~ 405KHz, providing the frequency range 2400MHz to 2505MHz across the 256 channel settings. This corresponds to the 2.4GHz ISM band and a little extra. All automatic gain control features are disabled.
I’ve actually been sitting on this project now for a couple months, since I wasn’t getting the results I expected initially (sitting close to my WiFi access point) and had no good way to test it. Luckily, as it turns out I was tasked with developing some RF gadgets (nRF24L01-based) at work, which could easily be set up to output a raw carrier wave at a programmable frequency. Sure enough, testing revealed some bugs in my initial CC2500 register settings, now corrected.
The video above shows the resulting spectrum output as the nRF’s naked carrier is swept through a handful of frequencies. As it progresses, it should also become evident where my WiFi access point is broadcasting. The green lines show instantaneous signal, the red shows the peak value at each frequency, and the blue shows a running average. The display script is written in Processing.
Fairly undocumented; use at your own risk.
diyspy.zip – Source code and .elf binary for ez430 kit (use mspgcc to build from source), .inf file for virtual COM port (win32 only), and Processing script for display.