By

Fast PWM and Electromagnetic Interference

fun with ATMega328 and rtl-sdr

Yesterday came to my attention a project that turns the Raspberry Pi into a FM transmitter. It is totally awesome and you should check it out.

While reading an article about it, I thought to check ATMega328 and its fast PWM mode I showed you in the previous article for electromagnetic interference (EMI). The process is extremely easy and it shows how far the the hobbyist electronics have come. I loaded the code of the previous article to an Arduino Pro Mini, connected a wire on pin 5 to act as an antenna, fired up gqrx and that was about it.

Below is a screenshot from gqrx, with automatic gain control (AGC) turned off, showing the 9th harmonic of the signal.

SDR, GNURadio, harmonics and other funny words.

I am not the best person to explain these, so I'll keep it short and let you do more research on your own.

Every signal can be approximated by sums of trigonometric functions (sines and cosines). What this means in our case, is that a pulse (the PWM output) is essentially the sum of many sine waves. These sine waves come at frequencies (called harmonics) that are integer multiples of our main frequency. In our case the PWM runs at 8MHz, so we expect to see harmonics at 8MHz (1st), 16MHz (2nd), 24MHz (3rd), ..., 80MHz (10th), etc. A perfect square wave would have only odd-integer harmonics, but if you watch our PWM in an oscilloscope, calling it square —or rectangle— is a bit of a stretch.

Anyway, these frequencies belong to the radio part of the electromagnetic spectrum, so in order to capture and visualize them we need a radio tuner/receiver and an antenna. Enter the world of software defined radio (SDR), GNURadio and rtl-sdr. Usually radio processing happens in hardware because it is a better fit due to processing power needed but, when you transfer the radio processing to software (hence SDR), you get all this tremendous potential since you can do anything you want. Hardware processing is mostly firmware locked and may only include the necessary functions for its given task, or use a difficult language (i.e DSP's assembly).

GNURadio is a free software toolkit to help you implement SDRs. Few years ago, some people discovered that certain, cheap USB TV tuners could get into debug mode, where they could tune to a wide range of frequencies and transfer the captured signal to the user's PC. These tuners use Realtek's RTL2832U chip. The rtlsdr project was created to implement SDR drivers for these tuners as well as a source block for GNURadio, hence cheap SDR receivers for everyone. Woo—hoo!

Gqrx uses GNURadio's libraries to implement a radio receiver, spectrum analyzer, FFT plotting, demodulator, etc.

Screenshots continued

Back to ATMega328, we use a TV Tuner and gqrx as a spectrum analyzer, to see the EMI caused by our little monster.

The first screenshot didn't use AGC, in order to show you how the raw signal looks like. If we turn on AGC, the fast fourier transform (FFT) plot will be adjusted automatically to pronounce the differences in our signal. In general blue means little to no signal, yellow is medium intensity signal and red is high intensity signal (compared to the rest in AGC mode). Before I turn on Arduino, everything is yellow. This means that everything is about the same level and AGC sets that as a middle value, hence everything is in the middle and yellow.

When we turn on Arduino and our 8MHz signal starts to emit, we have frequencies with much more power than other ones, so we can see as red the really strong frequencies, like the 9th harmonic, in yellow some less significant frequencies and in blue the part of the spectrum that our microcontroller doesn't soil.

Our antenna is a dupont line, a 20 cm simple wire. Even a LED would be enough or the rails of your PCB. The nice thing with SDR is that you can actually play with your transmitter's configuration and see how changing the length or the properties of your antenna, you can get all type of effects on the signal. Gqrx turns the signal audible, where you can perceive changes better.

Below is a photo of “the lab”. The main components, TV tuner and Arduino Pro Mini, cost about €15 from eBay. Truly a great time to be a nerd.

72MHz seems awfully near to FM

Indeed they are. We have a nice radio station here at about 96MHz, FM. When our fast PWM works near our radio receiver, the station is completely over-powered. A radio receiver uses AGC to detect each station signal's power. Now AGC detects the more powerful signal of the Arduino and the legit signal looks like noise compared to it. In the screenshot below you can see how the FFT plot changes after we turn on the uC.

The station's signal was red before our EMI. Afterwards it is pale yellow and the EMI is a strong red. Both cases, courtesy of AGC.

Time to have some fun

The obvious question is whether we can manipulate our EMI to transmit some kind of information —of course we can! How about audible information? Human hearing detects sounds between 20-20000Hz. Telephony traditionally used frequencies lower than 3000Hz since there is the main spectrum for human voice. Our fast PWM is in the order of MHz, surely we can modulate it at a couple hundred hertz.

I decided I wanted a quick challenge, prone to a dirty implementation. Thus the code below:

/* A sketch that creates a 4MHz fast PWM and then modulates
 * upon it a simplistic version of the infamous riff from smoke on the water.
 * The signal can be heard as AM modulation in many frequencies up to 1.76 or
 * more gigahertz. Just connect a wire to the output pin and fire up your SDR.
 *
 * Marios Andreopoulos
 * GPL v3 License
 */

#include <avr/io.h>
#include <util/delay.h>
#define DELAY 30000 // pause after each chord, usec

// Some basic chord frequencies. Think of the as ratio guides.
//    E4 = 330Hz
//    G4 = 392Hz
//    A4 = 440Hz
//    Bb4 = 466Hz

int main(void)
{
  pinMode(3, OUTPUT); // output pin for OCR2B

  // Set fast PWM
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(WGM22) | _BV(CS20);
  OCR2A = 3;
  OCR2B = 0;

  while (1) {
    // The riff is E G A / E G Bb A / E G A / G E

    E(); G(); A();
    _delay_us(DELAY);
    E(); G(); Bb(); A();
    _delay_us(DELAY);
    E(); G(); A();
    _delay_us(DELAY);
    G(); E();
    _delay_us(500000);

  }
}

void E()
{
  // A note's duration should be about 1 sec.
  // Freq * Period = 1, thus 1515usec = 1/330Hz.
  // Accordingly we calculate the other chords' periods as well. The code
  // below seems like it will give a duration  of 1 sec but instead gives
  // a duration of about 0.6sec which is nice too. What happens is that my
  // _delay_us() function is faster normal for some reason.
  for (int duration = 0; duration <= 330; duration++)
    {
      _delay_us(1515);
      if ( OCR2B < 3 )
        OCR2B += 1;
      else
        OCR2B = 0;
    }
  _delay_us(DELAY);
}

void G()
{
  for (int duration = 0; duration <= 392; duration++)
    {
      _delay_us(1275);
      if ( OCR2B < 3 )
        OCR2B += 1;
      else
        OCR2B = 0;
    }
  _delay_us(DELAY);
}

void A()
{
  for (int duration = 0; duration <= 440; duration++)
    {
      _delay_us(1136);
      if ( OCR2B < 3 )
        OCR2B += 1;
      else
        OCR2B = 0;
    }
  _delay_us(DELAY);
}
void Bb()
{
  for (int duration = 0; duration <= 466; duration++)
    {
      _delay_us(1072);
      if ( OCR2B < 3 )
        OCR2B += 1;
      else
        OCR2B = 0;
    }
  _delay_us(DELAY);
}

I know it looks bad and probably is, but it took me a few minutes to research and implement. I decided to transfer the classic riff of the infamous smoke on the water. I know almost nothing about music. I searched for the notes of the riff and their frequencies for a certain scale, then proceed to calculate their periods. For example, A4 chord is a sine wave at $440\text{Hz}$. Its period is $\frac{1}{440\text{Hz}} \approx 2272\mu\text{sec}$.

The code from the previous article was utilized to create a 4MHz fast PWM signal. If you recall, this means that I had 2-bit resolution for the duty cycle, thus I had 4 steps (25%, 50%, 75%, 100%) to recreate a crude sine wave.

Failed failing

Here starts the funny part. As I was in a hurry, I accidentally implemented a crude sawtooth wave instead of a sine and on top of that, I used wrong steps' duration. Since I had 4 steps I should have used one fourth of each period for each step's duration. Instead I used a whole period! But as it occasionally is, luck has nothing to do with mental clarity and thus it turned out that (a) for some reason my _delay_us() function is off about 50% —takes 0.5 usec for 1 usec— and (b) a sawtooth wave is a good way to imitate string instruments with strong integer harmonics, the second of which —due to (a)— was of course the desired main frequency of the chord. Somehow I was correct even when I was wrong.

I don't know why _delay_us() is so off. I'll have to look upon it at some point. If you suspect something, please leave a quick comment.

Below is a screenshot of the signal's harmonic at 28MHz. Have a look at the audio spectrum in the lower right panel. Does it remind you of something? Yes, it is the same as the spectrum in wikipedia's article above.

The dongle used has a Rafael Micro tuner which is a fancy way of saying that it can tune up to 1.85GHz. The actual top frequency for this implementation is 1766MHz and even up there it could detect the harmonics of our EMI and playback the riff! Of course the signal was weakened by tens of decibels, but it was so simple that AGC was able to salvage it.

Everybody loves videos

For last, a video with the harmonics at various frequencies.

comments powered by Disqus