…kind of. Temper your expectations. :)

Another task we can use this fast DAC for is generating AM radio waveforms, which can be heard on a regular AM receiver tuned to the right frequency and held very close by (power is limited and an ideal antenna is impractically long, but it’s a fun proof of concept).

This too requires a library:

After the Adafruit_AMRadio library is installed, there are a couple of example sketches. One plays the Jeopardy theme song over the AM 540 KHz frequency, the other plays a Godzilla roar sound.

Clip a test lead or connect a length of wire to pin A0 as a makeshift antenna. Just one end…the other is left unconnected. This is far from an optimal antenna, but we need something there.

An ideal antenna would be something like 450 feet long…clearly that’s not gonna happen. The test lead will do fine.

Creating New Radio Projects

To use the library, add this line at the top of your code:

#include <Adafruit_AMRadio.h>

Before the setup() function, declare a global object of type Adafruit_AMRadio:

Adafruit_AMRadio radio;

Then, inside your setup() function, call the object’s begin() function to start it running. By default this will transmit at 540 KHz, but you can optionally pass an integer argument, the desired frequency in Hertz:

radio.begin(530000); // Transmit at 530 KHz instead

Try to keep this as low as possible, but still within the AM band (530 to 1700 KHz).

It won’t run at precisely this frequency…the DMA clock has to run at some integer divisor of the 48 MHz CPU clock…so it will pick the closest thing it can muster, which may be a few megahertz to either side. If your AM radio has analog tuning you can dial it in for the best reception, like the old days.

The tone() function can be used for playing notes — similar to the normal Arduino tone() function — which accepts a frequency in Hertz and a duration in milliseconds (unlike Arduino’s tone(), the duration is required here). For example, to play middle C (262 Hertz) for one half second (500 milliseconds):

radio.tone(262, 500);

If you need more granular control over the audio waveform, use the radio.write() function to control the wave directly, passing a value from 0 to 1023 (the library’s equivalent of Arduino’s 10-bit analogWrite() function). For example, a neutral level:

radio.write(512);

This alone does not generate a sound. You then need to call write() repeatedly and quickly to generate an audio waveform. This can be seen in the “zilla” example sketch, which reads from a digitized audio sample stored in program memory and calls the write() function roughly 11,025 times a second.

Any existing code that uses analogWrite(A0) to generate sound through the Circuit Playground speaker can be easily modified to use the radio library instead.

How It Works

Amplitude modulation (AM) — the earliest method of sound transmission over radio — conveys a relatively low-frequency variable audio wave (such as voice or music, up to a few kilohertz) into a much higher fixed-frequency radio wave (500 KHz or more), called the carrier wave, by…you guessed it…modulating the amplitude of the carrier wave in direct proportion to the sound wave’s shape.

Image credit: Wikimedia Commons contributor Berserkerus, CC-SA

The DAC is barely fast enough to generate a reasonable carrier wave for the lower end of the AM radio band. Our library simply adjusts the peaks and troughs of this wave in response to the Arduino sketch code.

Actually the DAC isn’t fast enough for this. We’re cheating! Generating a 540 KHz square wave requires 1,080 kilosamples per second from the DAC, but it’s really only rated for 350 Ksps. We simply feed it at the faster rate. This is not harmful in any way to the DAC, the output just isn’t numerically precise until it’s fully “settled” (the 350K rate), and we’re interrupting it before it gets all the way there. It’s reasonably close though. The video library does something similar, but not quite as fast, as that one does require a little more precision.

This is also why it only works toward the lower end of the AM band. As the frequency increases, the DAC output precision decreases.

Zooming way in with an oscilloscope, the 540 KHz carrier wave is visible. Though we’re feeding the DAC a square wave, the slow “settling time” produces this truncated triangle wave. This works to our benefit, as the carrier should ideally be a sine wave, and this is a coarse but acceptable facsimile.

Zooming out a bit, you can see the carrier wave amplitude (height) being modulated by the lower-frequency sound wave.

Zooming out still further, the individual audio samples from a digitized Godzilla roar — 11,050 per second — can be seen. The high-frequency carrier wave is so much smaller by comparison, it appears solid on the scope.

Limitations

  • Circuit Playground Express speaker is disabled; tone() and other audio code will not work in combination with this
  • Range is extremely limited, just a few inches — this is “science project” fun and not a serious radio transmitter!
  • Limited to lower AM band; example code uses 540 KHz

Adafruit_CompositeVideo (on the prior page) and Adafruit_AMRadio both use the DAC peripheral and the same timer/counter; the two libraries can not be used at the same time.

Isn’t broadcasting without a license illegal? Even with an amateur license, isn’t broadcasting in this frequency band illegal? Will the FCC haul me away?

Maybe in some ultra-pedantic interpretation, but the range is so limited (less than a foot) it can’t possibly interfere with other receivers or devices, so this shouldn’t be a problem. It’s only “broadcasting” if targeting a wider audience. This is “low-grade noise.”

But hey, if the experiment piques your interest, why not study for an amateur radio license?

This guide was first published on Jun 06, 2017. It was last updated on Mar 08, 2024.

This page (Transmitting AM Radio) was last updated on May 19, 2017.

Text editor powered by tinymce.