A simple AM/FM radio
I’ve been working on building a simple AM/FM radio, operated through just a few buttons and knobs, and with decent audio quality. It has a simple display and fits in a fairly compact package, more or less the size of hardcover book.
Not long ago, I would have built a traditional receiver design using discrete components, probably a superheterodyne (used in the vast majority of inexpensive alarm clocks and portable AM/FM radios lying around in homes) or perhaps a regenerative receiver for novelty. Today, the popularity of small, digital, low-cost devices with integrated AM/FM radios has driven more parts of the radio into integrated circuits (though often keeping the superheterodyne design).
Radio hardware
I was excited to find the Silicon Labs Si473x family of radio ICs. The Si4735 includes AM/FM/SW/LW reception in a single IC that requires just a few external components and two external antennas. Essentially, the chip replaces what traditionally requires a few dozen discrete components and it eliminates manual adjustment of tuning sub-circuits.
The reduced bill of materials doesn’t simplify everything. Instead of sourcing, assembling, and tuning discrete RF/IF components, the radio IC must be interfaced over a serial, 2-wire, or 3-wire connection. Silicon Labs provides guidance through its datasheet and a few application notes, but I found some steps, such as the power-on sequence, could have been more clearly documented.
Sparkfun sells the Si4735 AM/FM IC and an Arduino shield that includes the IC, a crystal, and a few components that support the AM and FM antennas. Using the shield absolves one of any SMD soldering or source the diodes, crystals, and inductors that support the chip.
Sparkfun wrote some code to help users get started with the shield, and a few others have extended it and added some very cool features, such as querying the IC to get its current frequency and adding RDBS processing to get FM station and programming information off the air. Wagner Sartori Junior (Trunet) and Jon Carrier added quite a bit of this functionality, so it’s thanks to them and Sparkfun that getting the Si4735 up and running with these cool features is so easy.
Other hardware
I needed some other hardware besides the Si4735 shield and Arduino board. For the display I used a serial enabled white-on-black 16×2 character LCD display. A rotary encoder is used as the tuning knob and band-switching push button, and a simple 10 kΩ potentiometer controls the volume. The Si4735 support volume adjustments via software, but I chose an analog potentiometer for simplicity.
The Si4735 shield outputs a very small audio signal (I haven’t tried to measure it yet), so an off-shield audio amplifier is mandatory. I opted for a mono amplifier based on a single NE5534 op amp. It has good performance, is reasonably priced, and doesn’t require too many supporting components. I considered adding stereo support but the radio didn’t require very high quality FM output, and there is a stereo headphone jack in case it’s really desired. The circuit I used is from http://www.electronics-diy.com/
Software
Jon Carrier’s code is hosted on Github and includes example sketches. I played with them quite a bit before using bits and pieces in my own sketch. Jon put a lot of effort into making RDBS work, and while it’s quite cool to see the station and song information scroll across the screen, I don’t use it. I do like to see the station’s callsign, so I kept this part and display the callsign on the second line of the LCD display. Many stations don’t transmit RDBS data, so in case the station callsign is unknown, my LCD doesn’t display any information on the second line. I also removed the volume and seek states, since I’m handling the volume level through an analog potentiometer and I don’t care for a separate seek mode at this time (perhaps I will later).
I experienced a few of the issues that have been brought up in the comments on Jon’s page. In particular, I frequently saw the system start or very quickly jump to its initial frequency + 0.1 MHz, and I also found the LCD screen locking up when I turned the rotary encoder very quickly. I used a serial connection of 9600 baud (the default value for the serial enabled LCD) and I wasn’t able to really troubleshoot this behavior. I’ve read in a few places that these LCDs can lock up when they receive data too quickly, so my wild guess is that this was somehow happening, perhaps from other things coming unintentionally on the serial line. A few times I also reproduced the 655.3 MHz and 0.0 MHz frequency change that Jon mentioned, even though the code is supposed to restrict the frequency to the broadcast band range when using the rotary encoder for tuning. It seems some of these issues may come from the rotary encoder, debouncing (or lack thereof), and/or the rotary callback function.
There are many sample rotary encoder implementations, some using interrupts, some using the digitalRead function in the main loop, and so on. Since the tuning knob and responsiveness is so central to the radio’s operation, I wanted to make sure the rotary encoder’s data was reliably read and displayed on the LCD, even for very fast rotation rates. I made a separate sketch to prototype this part of the system and ended up using Arduino’s built-in interrupts based on the code found here. Once this was working on its own, I integrated it as the interrupt and callback in the radio sketch.
An important note about using the shield
****The Si4735 and the shield communicate through 3.3V, not the 5V that boards like the Arduino Uno, Duemilanove, and Diecimilia expect. This is documented in the comments of the Sparkfun product page and on a few forums/blogs. The two generally accepted workarounds are to:
- Insert a silicon diode between pin D12 and the GPO1 line on the shield. Trunet also documents how to do this on his wiki.
- Use a level-shifter to convert between 3.3V and 5V signals.
Both are hacks for using the shield with 5V Arduino boards and require a bit of surgery in severing a trace on the shield. Using the level-shifter is the more “robust” approach and I chose this because it gives the flexibility to send and receive SPI commands to the Si4735. Inserting the silicon diode allows reading SPI data, but not writing it. However, it takes up space on the shield and limits the possibility of adding other components on top of it. Another issue with the shield is that it connects the GND and AREF pins – meaning AREF is permanently tied to ground, unless you break that connection. This is important if you need to use the Arduino’s analog pins.
Next steps
The radio works as designed, the audio amplifier is built out on a protoboard (and is certainly loud enough), and the display and tuning are smooth, so all that’s left is to connect the power supply, mount the components inside the enclosure, which is made from Ampersand Hardbord. The tuning knobs are simple diamond knurled cylindrical knobs from Digikey.