Projects

On The Air

Arduino-powered FM Transmitter

Luke Prior

Issue 52, November 2021

This article includes additional downloadable resources.
Please log in to access.

Log in

Build your own mini radio station with this Arduino Uno-based FM transmitter project.

BUILD TIME: 1 to 2 hours
DIFFICULTY RATING: Intermediate

The first radio broadcasts can be dated back to 1906 but it wasn’t until the 1920s when regular commercial stations began broadcasting. These early stations used AM (amplitude modulation) signals where the amplitude of the wave is varied proportional to the information being sent. This transmission technique was used for all radio broadcasts until the introduction of FM (frequency modulation) broadcasting in 1933.

FM broadcasting can provide higher fidelity audio with less interference and popping compared to AM transmission, which is beneficial for audio and music. An advantage of AM broadcasting, however, is that it can achieve a longer transmission range due to the lower frequency bands used. This is the main reason both technologies are still commonly used across the world.

The broad overview

For this project, we create an FM radio transmitter to broadcast audio from any media player that has an audio jack, to an FM radio.

We use the FM band instead of AM because of the higher quality audio that provides, and the availability of components.

FM also allows us to experiment with more recent additions to radio, including sending text and data to the receiver alongside the audio.

The hardware consists of just an Arduino Uno or compatible board and a Si4713 FM Radio Transmitter breakout board from Adafruit.

How it works

FM Transmitter Breakout Board

Adafruit Stereo FM Transmitter with RDS/RBDS Breakout - Si4713

The Adafruit FM radio transmitter breakout board measures just 41 x 19mm and features a best-in-class Si4713 FM radio transmitter from Silicon Labs. This board also supports RDS (Radio Data System), which we will explain in more detail below.

Adafruit claims a short-range transmission range up to 10m (30ft), which we assume is achieved once you solder on the short length of wire onto the board to act as an antenna. This range may be able to be extended by optimising the antenna length for the specific transmission frequency.

Note: Laws and regulations surrounding radio transmissions vary across the world, so we would strongly encourage you to check them before trying any of these experiments.

Audio can be connected easily using the 3.5mm stereo audio socket, and inputs on the board enable you to hardwire the audio depending on your application. There is an AC coupling capacitor onboard so it can be DC biased.

The board requires 3-5VDC power - ideally the same voltage you use for the logic levels. In our case, our Arduino Uno will provide power. Interestingly, the breakout board has an integrated regulator that can provide a nominal 3.3VDC up to 100mA to power any additional circuitry you may have.

The FM transmitter needs a microcontroller to set the transmit frequency and line-level audio from a microcontroller. Arduino is the recommended microcontroller to use, however, Adafruit also publishes MicroPython and Python libraries for the Si4713 so most computers and microcontrollers with an I2C interface, including the Raspberry Pi, should be compatible.

Interface input pins include RST (Reset), CS (Chip Select), SCL (clock), and SDA (data).

Note: The CS pin can be shorted to ground, changing the I2C address to allow for the operation of multiple devices on the same bus.

There are also two GPIO pins. You can use these to blink LEDs, for example. They are 3V output only.

Radio Data System (RDS)

The Radio Data System (RDS) is a communication protocol developed in 1984 to allow the embedding of digital information in conventional FM broadcasts. The standards include specifications for the transmission of various types of information including time, station identification, program details, and live traffic.

This protocol allows receivers to display a radio text message which can be synced with the currently playing media to provide information such as the song or program name. There are also provisions to send further information such as the artist name and song metadata.

The Build:

Parts Required:JaycarAltronicsPakronics
Arduino Uno or CompatibleZ6280XC4410ARD-A000066
Adafruit Si4713 FM Radio Transmitter--ADA1958

Parts Required:

* A breadboard and prototyping hardware is also required.

The Adafruit Si4713 board is supplied with an 11-pin header strip and some wire for the antenna. Soldering the header strip to be board can be made easier if you use a breadboard, as you see here. You will also need to strip the end off the wire before soldering that to the solder pad labelled Ant.

Wiring the project together is straightforward. Power is provided by the Arduino Uno - simply connect the Uno’s 5V output to Vin on the transmitter board and GND to GND

The I2C communication requires the SCL clock pin and SDA data pins to be connected to the A5 and A4 pins on the Arduino Uno respectively. We will also need to connect the RST to digital pin 12 on the Uno.

Software Setup

We will be using the Adafruit_Si4713 Arduino library designed specifically for this board. The Arduino IDE needs to be installed and configured for programming the Arduino Uno. The library can easily be downloaded using the integrated library manager.

The library manager can be accessed from Sketch > Include Library > Manage Libraries. The library can then be searched for, and the latest version installed. This will ensure all the relevant files are downloaded and configured so that we can program the Arduino to interface with the board.

Finding Open Channel

The Si4713 chip features integrated power measurement capabilities that allow us to check the signal strength of various FM frequencies to determine the optimal broadcast frequency. We need to find a frequency that isn’t in use to avoid any potential interference.

The Adafruit_Si4713 Arduino library includes some example code for broadcasting and scanning. We can take the scanning portion of this code to create a simple program to find the best available frequency.

To use the board, we need to establish an I2C connection by calling the radio.begin() function. This will attempt to find the device on the 0x63 I2C address and, if successful, we can instruct the chip to begin cycling through the FM frequencies.

The program will loop through the frequencies from 87.5 to 108 MHz, as defined by the International Telecommunication Union. This frequency range is standard across Australia, New Zealand, Europe, and Africa. The code will check each frequency in this band with a stepping rate of 0.1 MHz.

#include <Wire.h>
#include <Adafruit_Si4713.h>
#define RESETPIN 12
Adafruit_Si4713 radio = Adafruit_Si4713(RESETPIN);
void setup() {
  Serial.begin(9600);
  Serial.println("Simple FM Frequency Scan");
  if (! radio.begin()) {
    Serial.println("Radio not found");
    while (1);
  }
  Serial.println("Scan start");
  for (uint16_t f  = 8750; f<10800; f+=10) {
    radio.readTuneMeasure(f);
    Serial.print("Measuring "); 
    Serial.print(f); Serial.print("...");
    radio.readTuneStatus();
    Serial.println(radio.currNoiseLevel);
  }
  Serial.println("Scan done");
}
void loop() {
}

The returned signal strength values for each frequency represent the strength of existing broadcasts on that frequency. The highest values indicate the strongest signal so we will look for an area of low values and choose a frequency there. We found that the best frequency to use in our area was 89.2 MHz, but be sure to check this yourself as broadcasters will vary.

Simple Broadcast

To set up the code for our first transmission, we selected the relevant components from the example to create a simple program. We need to establish an I2C connection with the board the same way we did for the frequency scan on address 0x63.

The frequency we found earlier needs to be entered into the program FMSTATION variable in the format 8920, which corresponds to 89.2 MHz. This value is passed to the library during setup so that the board will broadcast correctly.

The program then sets the broadcast power to the maximum value of 115 dBuV, however, any value between 88 and 115 can be used.

The final step required to begin broadcasting is to set the frequency. To do this we use the tuneFM command.

This code was uploaded to our Uno and the output was monitored through a serial connection, which is where the program connects and configures the board before beginning the transmission on our specified channel. We could then attach our audio source to the 3.5mm jack, and listen to the broadcast on an FM radio receiver (In our case, set to 89.2MHz).

#include <Wire.h>
#include <Adafruit_Si4713.h>
#define RESETPIN 12
#define FMSTATION 8920
Adafruit_Si4713 radio = 
Adafruit_Si4713(RESETPIN);
void setup() {
  Serial.begin(9600);
  Serial.println("Simple FM Broadcast");
  if (! radio.begin()) {
    Serial.println("Radio not
found");
    while (1);
  }
  Serial.println("Power set");
  radio.setTXpower(115);
  Serial.println("Tuning to: ");
  Serial.print(FMSTATION/100); 
  Serial.print("."); 
  Serial.print(FMSTATION % 100);
  Serial.println(" MHz");
  radio.tuneFM(FMSTATION);
  Serial.println("Live!");
}
void loop() {
}

Set station name and track info

The Adafruit_Si4713 library contains three commands relating to Radio Data Broadcast that we can use to initialise and send station/track information to receivers. The RDS subsystem first needs to be enabled by calling beginRDS(), which will then allow us to start transmitting the information.

The station name can be set with the setRDSstation() command, where the input must be 8 characters or less. We can set our station name to DiyodeFM using setRDSstation(“DiyodeFM”). This will be visible on compatible receivers.

The RDB standard also allows for track information to be sent which typically includes information such as name or artist. The implementation available with our board allows a 32 character message. This message can be changed using setRDSbuffer(). We need to allow a few seconds between updates to ensure the data gets transmitted.

We modified our previous simple FM broadcast program to include these commands which would cycle through RDB messages. The program will begin RDS transmission once it has been configured for the right frequency and power. The station name will be set at this time before the main loop begins where the RDS secondary message will be cycled every 5 seconds.

The program (available on our website) could be uploaded to our Arduino and the output monitored. The transmission can be listened to the same as previously with any FM radio receiver, but to receive the RDS messages, we will need a compatible device. While most receivers can support this, including car stereos, we will be using a Software-Defined Radio (SDR) dongle to check.

Checking broadcast with SDR

We can listen to our FM broadcast using an RTL2832U SDR dongle as explored in Issue 41. The Airspy SDR# software includes support for FM broadcasts and decoding of the simple RDS we will be transmitting. The antenna used will not be important for this specific application due to the small range.

We installed SDR# and the relevant Windows drivers for our SDR dongle before configuring the RF gain. We set the SDR# mode to Wideband FM (WFM), begun decoding, and selected the frequency of our transmission. The audio fed into the 3.5mm jack was audible, confirming that the transmission and reception were both working correctly.

To view the RDS information we can enable FM Stereo mode in SDR#. This will cause the program to begin listening for RDS packets, which it will then display. This information will arrive in chunks with the entire message, not necessarily being available immediately. The board will continuously transmit these packets so that receivers can get the information, regardless of when they started listening.

Where to from here?

The Adafruit Si4713 library includes further functions that we didn’t explore in this project, including the ability to determine the volume of incoming audio through the 3.5mm jack, and the ability to control devices directly from the board using the two GPIO pins. This functionality could be used to create an audio volume visualiser that could accompany the device.

The core functionality could also be extended to increase the versatility of the device by switching to a lower power mainboard and introducing a solar power circuit. This would allow for portable off-grid operations that could serve as a music broadcaster when camping, for example.