Arduino Project Hub
Project tutorial

FM radio © GPL3+

Build a great sounding FM radio with a cool display using an Arduino Nano and the Sparkfun Si4703 FM tuner breakout

  • 7,187 views
  • 1 comment
  • 33 respects

Components and supplies

About this project

As a kid, I used to build AM radios but never quite managed to build FM radios. They were just too complicated. Nowadays, you can get a complete FM radio tuner on a chip but these chips are surface-mount components and difficult for a hobbyist to work with. Fortunately, Sparkfun makes a breakout for the Silicon Laboratories Si4703 FM radio tuner chip (datasheet), which breaks out all pins. I will show you how you can build a complete FM radio around this breakout and use an Arduino to control the tuner functions over the built-in two-wire control interface. Sparkfun provides a complete library making this easy to program.

At the same time, I added a cool little OLED display to the project with very high contrast and very low power consumption. Last but not least, I will show you how you can build a great-sounding mono audio amplifier from a minimum of parts. The finished radio runs on three AA-batteries for many, many hours.

Sparkfun FM Tuner Basic Breakout and I2C serial bus

The basic breakout is easy to work with. First solder on the male header to be able to use the breakout with a breadboard. See pin layout below. Solder on one meter of thin wire works as antenna to ANT for now.

  • LOUT and ROUT are the left and right output channels that we will connect to our amplifier.

(If you don't want to build your own amplifier, you can buy the Evaluation board instead, which you can use directly with your headphones).

  • The supply voltage Vcc is +3.3 Volt.
  • GND is ground or 0 Volt.

The Si4703 has a two-wire interface, which is a serial bus that allows controlling the tuner from an Arduino over serial communication. More accurately, the bus is called I2C (Inter-integrated circuit; pronounced I-squared-C or I-two-C) and uses only two bidirectional lines:

  • Serial Data Line (SDA) and
  • Serial Clock Line (SCL).
  • In addition comes the Reset line (RST).

In the Si4703, SDA is called SDIO and SCL is called SCLK. All Arduinos have built-in I2C. If you want to learn more about the I2C bus, Tom Igoe and Jeff Feddersen have made a great video. On our I2C bus, the Arduino acts as master while both the Si4703 and the OLED display act as slaves.

I2C bus voltages and choice of Arduino

Voltages used of the Si4703 and the OLED display on the I2C bus are 3.3 Volt. For that reason, Sparkfun advise in their hookup guide to use a 3.3 Volt Arduino. This means using an Arduino Pro Mini which is a little more difficult to program as it lacks a USB connector and has to programmed with an FTDI breakout. But there is another problem: the Arduino Pro Mini runs at 8 MHz, half the speed of an Arduino Uno or Nano. My testing showed that this is too slow to drive the OLED display. As I really wanted to keep the display, I decided to use an Arduino Nano (16 MHz) which has 5 Volt signal level on the I2C bus and use bidirectional I2C Logic Level Converters (I2C-shifters) to connect to the 3.3 Volt bus signals of the display and radio chip. I had some I2C-shifters lying around with two signals each that I used in the project. We need to level-shift a total of three signals: SDA, SCL and RST. I had to use two I2C-shifters. (I linked in the description above to a I2C-shifter with 4 signals which can help you to save some cabling).

The Nano is almost identical to the Uno but on a much smaller footprint. If you want, you can use the Uno instead. I did that for the first testing. Both have USB connectors and are easy to use with the Arduino IDE.

Schematics Arduino connections to radio and display

Next, let's look at the wiring around the Nano and the details of the I2C bus connections. (If there is no dot, wires just cross).

As you can see, the project is powered by three AA-batteries (4.5 Volt). The batteries are connected directly to the 5 Volt pin of the Arduino Nano, bypassing the voltage regulator. This way, a Nano will happily run from 3 AA-batteries. WARNING! Always disconnect the batteries before you connect the Nano via USB to your computer! Otherwise the 5 Volt from your computer will be short-circuited with your batteries. During the first testing phase, run the circuit from the USB power supply without batteries! If you want to play it safe, use six AA batteries (9 Volt) and connect the plus pole to the VIN pin (instead of the 5 Volt pin) of the Nano. That way, the power management of the Nano will automatically switch off the batteries when you connect the USB cable. (You can use a 9 Volt block battery instead but it might only last a few hours).

Arduino SDA (A4) and SCL (A5) are connected to the 5 Volt side of the I2C-shifter. In addition, we use D2 as RST signal. On the 3.3 Volt side of the I2C-shifter, we connect to SDIO, SCLK and RST of the Si4703. For the OLED display, it is sufficient to connect to SDA and SCL. (I bought mine on banggood.com because it was two-coloured: yellow (top rows) and blue and there was no RST pin).

Connect all components to the 3.3 Volt output of the Nano and to Ground. The I2C-shifter further needs 5 Volts on the high-voltage side.

The IO-pins D5-D12 are connected to the two keypads. Pressing a button connects the input to Ground.

Low Voltage Audio Amplifier LM386

I used the LM386 chip to build a mono amplifier. The LM386 has been around since the seventies. It is a power amplifier designed for use in low voltage consumer applications (datasheet). The gain is internally set to 20 to keep external part count low, but the addition of an external resistor and capacitor between pins 1 and 8 will increase the gain to any value from 20 to 200. We will work with the lowest gain of 20, which is more than high enough if you use a 8 Ohm speaker.

The schematics for the audio amplifier part of the project are given next:

Let's look at the Si4703 first. On the left-hand side, the I2C signal connections to the Arduino are indicated. The audio output channels are to be connected as follows: the resistor R4 is to be connected to LOUT and R5 to ROUT. The two signals are then combined to a MONO signal. There are capacitors on the outputs on the breakout board, so we don't need to add one. R2 and R3 define a voltage divider to decrease the input signal level into the amplifier. You could of course replace R2 and R3 with a potentiometer and use it to regulate the volume. But we want to control the volume digitally. The Si4703 output level can be increased over I2C stepwise from 1 to 15. With R2 / R3, you can match this to the amplifier by experimenting with different resistances. For example, if you increase R3, the volume increases.

The circuit is taken straight from the datasheet. C2 has to be at least 220 µF. Smaller values will dampen bass response. If you want to boost bass, have a look at the datasheet. Build the circuit on a breadboard and experiment with adding/removing components: C3 has to be placed close to the chip. C3 and C1 are optional.

There is a lot of videos on youtube about LM386 projects and many complain about bad sound. Most of them probably lack proper ground layout. If you look at the schematics, you see how I kept the input ground separate from the output ground, which is very important. They meet at pin 4, the ground pin of the chip. If you want to learn more about this, watch this video from JohnAudioTech (and this one for a complete LM386 project).

The LM386N-1 needs a minimum of 4 Volt and delivers a few hundred mWatt. I run this with 3 AA-batteries (4.5 Volt) and can vary the volume between 1 and 10 and it sounds really good. However, for such low supply voltage, it is quite important to use a 8 Ohm (not 4 Ohm) speaker. If I increase the volume to 15, it starts to sound distorted. If you want to play your radio really loud, increase the supply voltage to 9 Volt.

Prototyping

I would strongly advise that you first build the whole project up on two breadboards. Keep the Arduino, I2C-shifter and OLED-display together on one breadbord, while you have the Si4703 breakout and the audio amplifier close together on the other breadboard to keep acoustic distortions to a minimum. In my first prototype, I had the Si4703 close to the Arduino with long signal cables to the audio part (see picture) and this caused distortions.

Power the Arduino from USB with the regulated 3.3 Volt output from the Arduino powering the display and the radio chip. Power the LM386 from batteries (4.5 - 9 Volt).

The program code

The following libraries have to be included:

#include <SparkFunSi4703.h> 
#include <SPI.h> 
#include <Wire.h> 
#include <Adafruit_GFX.h> 
#include <Adafruit_SSD1306.h> 

If you don't how to install libraries, have a look at the following guide. The Sparkfun library is found here and provides high-level functions to talk to the Si4703 without having to care about all the tiny details. The Adafruit display libraries with tutorial are found here.

Next, we need to make some definitions:

// Input buttons on radio 
#define volDown 9              
#define volUp 10 
#define channelDown 11 
#define channelUp 12 
// Si4703 radio chip 
#define resetPin 2 
#define SDIO A4 
#define SCLK A5 
Si4703_Breakout radio(resetPin, SDIO, SCLK); 
#define SI4703Address 0x10      // Si4703 I2C Address. 

The use of #define is a way to make the source code more readable. After you have once and for all defined that volDown refers to the pin 9, you write volDown each time you mean D9.

Next, we look at the setup section:

// Variables definition  
int channel; 
int volume; 
void setup() 
{ 
 // Set internal pull up resistors on inputs  
 pinMode(volDown, INPUT_PULLUP);         
 pinMode(volUp, INPUT_PULLUP); 
 pinMode(channelUp, INPUT_PULLUP); 
 pinMode(channelDown, INPUT_PULLUP);  
 // Initialise radio 
 radio.powerOn(); 
 channel = 882; 
 radio.setChannel(channel); 
 volume = 4; 
 radio.setVolume(volume); 
} 

Pins 9-12 are defined as input pins. The parameter INPUT_PULLUP connects an internal pullup resistor (inside the ATmega chip) from +5V to the input pin. In consequence, the pin's signal level will be HIGH unless you press the button (pressed button = LOW).

The Sparkfun-library makes it easy to control the radio over I2C with the main functions powerOn(), setChannel() and setVolume().

The main loop listens for a button to be pressed and then takes action accordingly:

void loop() 
{ 
 // Volume down 
 if (digitalRead(volDown) == LOW)  
  { 
    if (volume > 0) volume--; 
    radio.setVolume(volume); 
    UpdateDisplay(); 
    delay(100); 
  }   
 // Volume up  
 if (digitalRead(volUp) == LOW)  
  { 
    if (volume < 15) volume++; 
    radio.setVolume(volume); 
    UpdateDisplay(); 
    delay(100); 
  }  
 // Channel down 
 if (digitalRead(channelDown) == LOW)  
  { 
    channel = radio.seekDown(); 
    UpdateDisplay(); 
    delay(100); 
  }   
 // Channel up 
 if (digitalRead(channelUp) == LOW)  
  { 
    channel = radio.seekUp(); 
    UpdateDisplay(); 
    delay(100); 
  }   
} 

Have a look at the complete source code below. It includes four buttons for pre-set stations (where you can put in your favorite stations) and all the code needed to update the OLED-display, which uses up almost all available RAM. I refer you to the excellent Adafruit tutorial, if you want to learn about the SSD1306-library. Be aware that the library cannot determine the screen size of your display via software. You have to specify it after having installed Adafruit_SSD1306.h. Open the library file, read the instruction in the comments and edit the file accordingly.

There is one "advanced" function in the source code to measure the battery level by comparing it to an internal 1.1 Volt referance inside the AVR chip. As we are running on batteries, we have no constant 5 Volt referance voltage to measure battery voltage against. If you want to learn more, I refer you to the following articles: Secret Arduino Voltmeter and the Gammon forum.

From breadboard prototype to finished radio

If you have come this far, you have a fully functional prototype on two breadboards. Let's transfer the circuit to two perfboards and get the whole radio inside a nice project box. If you haven't done this before, don't be afraid to try. There is nothing you can really do wrong and you learn the neccessary skills as you move along. Collin from Adafruit has made two nice introductory videos you can watch: Breadboards&perfboards and Perfboard prototyping.

I decided to put the Nano together with the I2C-shifters (I had to use two shifters, see above) on one perfboard:

To make this prototype perfboard, I followed a tutorial, which I recommend to study in detail: How to Prototype without using printed circuit boards. Especially important is Step 3: make your wiring plan! Planning is the most important step and the difference between failure and success. Some further tips: I used black 22 AWG wire, which was too thick and difficult to work with as you can see on the picture. Get some thin "Wire Wrapping Wire" (30 AWG) in different colours instead. And use a larger perfboard! I made pin headers and used Dupont jumper wires to connect the different parts together.

Place the Si4703 and the audio amplifier together on a second perfboard. Here is a little tutorial for a LM386 amplifier, that you can use as inspiration: From Schematics to Veroboard. I would however suggest that you use an IC-socket for the LM386! Alternatively, JohnAudioTech has made a nice video for a complete LM386 amplifier project with a good layout included, that has the power grounds separated from the signal grounds.

Next, you need a nice project enclosure for your radio. Again, Collin shows in this video how to do it. I liked especially the idea with the masking tape for marking where to drill. I bought Painter's tape which isn't too sticky. Apart from masking tape and a drill, use a hot-glue gun. Just glue speaker, perfboards, battery pack etc. into the enclosure and then connect the parts with Dupont jumper wires. The final product looks like this:

I was too optimistic and bought a rather small project box as you can see. To make a square opening for the display in the front panel, I cut with a Stanley blade from the inside (to avoid ugly marks on the outside). Not very elegant, but it worked just fine. Then I glued the display into the opening with hot glue. I marked the size of the speaker on the front panel, drilled lots of 3 mm holes for the sound and glued the speaker on from the back.

In the picture, you can still see the antenna wire. Next, I bought a panel-mount F type connector and a telescopic FM antenna. Altough the antenna is just 50 cm long, the reception is very good and the little speaker sounds surprisingly good. Most amazing though is the fact that I haven't changed the batteries once yet although I have been listening to my little radio for many days.

Other radio projects

I was initially inspired to do this project when I saw the video of Great Scott, who also built a nice wooden project box for his radio in a later video. Much closer in details to my radio is however the Si4703 Pocket FM Radio by John Owen, as he uses the Sparkfun breakout and you should have a close look at his project description. I have used his source code for the Mono function and for the measurement of battery voltage.

Schematics

Fritzing diagrams FM radio
Both original Fritzing files and pictures / PDF

Code

FM-radio
Github repository with source code for Arduino Nano

Comments

Similar projects you might like

Arduino 101 BLE App

Project in progress by Alexis Santiago Allende

  • 1,689 views
  • 10 comments
  • 21 respects

Aquariumatic

Project in progress by Craig Hissett

  • 6,964 views
  • 2 comments
  • 17 respects

Avoid Injuries with Smart Backpack

Project tutorial by Chathuranga Liyanage

  • 941 views
  • 2 comments
  • 12 respects

Arduino Digital Clock Version 2

Project showcase by John Wafik William

  • 425 views
  • 0 comments
  • 6 respects

Arduino Temperature Control

Project tutorial by Team pandhoit

  • 913 views
  • 3 comments
  • 9 respects

Italian Word Clock

Project tutorial by Tittiamo

  • 1,167 views
  • 2 comments
  • 8 respects
Add projectSign up / Login