Arduino Squarewave Generation

Yesterday I came across this: Secrets of Arduino PWM by Ken Shirriff and Paul Badger. It has a brilliant explanation of some of the different modes and functions of the Pulse Width Modulation timers on some popular ATMega / Arduino chips. I think anyone having struggled with the datasheet will appreciate this article immensely.

My main interest was in generating a variable audio-frequency square wave, for obvious reasons: to make noise! This is something I’ve not been able to figure out before. The Auduino approach is great, and makes great sounds, but uses a different approach altogether – granular synthesis with a fixed frequency PWM timer interrupt.

Ken explains how PWM frequency can be controlled by two means: the timer prescaler and the counter top limit. The prescaler divides the clock frequency by a fixed value of 1, 8, 32, 64, 128, 256, or 1024. The top limit sets a value which the counter counts up to before restarting. Anyhow, no need to restate what’s already in the article – the upshot is that we can have coarse and fine control over PWM frequency.

The above table shows the frequency (y axis, log scale) versus top limit (x axis) for different prescaler values, for Timer 2 phase-correct PWM Output A (pin 11). Output A has a fixed duty cycle of 50%. Output B (pin 3) has 2x the frequency, and has adjustable pulse width.

To try it out I hooked up an arduino to some pots and an audio jack.

The code is super simple:

/*
  Wire up pots to analog inputs 5, 4, and 3.
  Output on pins 3 (pulse width modulated)
  and 11 (1/2 frequency at 50% duty cycle).
  Wire output pins and gnd to a pot for volume control.

  Frequency calculation
  pin 11 = 16MHz / prescaler / limit / 4
  pin 3  =  16MHz / prescaler / limit / 2

  see http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM
*/

#define DIV_PIN   5
#define FREQ_PIN  4
#define DUTY_PIN  3

void setup(){
  pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20);
}

// accepts values 1-7 to set prescalers 1/8/32/64/128/256/1024
// 0 turns timer off
void setPrescaler(uint8_t divisor){
  if(divisor > 7)
    return;
  TCCR2B = _BV(WGM22) | divisor;
}

// expects a value 0.0-1.0
void setDutyCycle(float value){
  OCR2B = OCR2A * value;
}

void setTopLimit(uint8_t limit){
  OCR2A = limit;
}

void loop(){
  setPrescaler(analogRead(DIV_PIN)>>7);
  setTopLimit(analogRead(FREQ_PIN)>>2);
  setDutyCycle((float)analogRead(DUTY_PIN)/1023.0);
}

Updated!

I couldn’t help myself, I went ahead and coded up a MIDI handler which turns an unsuspecting Arduino into a squarewave hardware synthesizer. The code is available on github. You can use MidiSerial to enable a MIDI interface communicating over the Arduino serial line.

The SquareWaveSynth responds to all MIDI notes from 0-127, but has troubles rendering some of them. It would no doubt be better to use the 16 bit Timer 1 instead of Timer 2. It also responds to mod-wheel changes (cc 1) which changes the duty cycle, from 50% to 0.

Here it is playing the theme to Ghouls and Ghosts (well, one voice of it!) with the help of Ableton Live.

Share
This entry was posted in Hacking, Hardware and tagged , , , , , . Bookmark the permalink.

2 Responses to Arduino Squarewave Generation

  1. matjar says:

    Man, you are the best!
    I am trying to control a motor with variable frequency. I was searching for a couple of months and I couldn’t find a disent code to do this. And you did it in 45 lines!
    Keep the goog work :)

    • mars says:

      Glad it worked for you.
      I did some more work on the code to support both timer0 and timer1, it’s in the git repo. I left it unfinished, need to revisit at some point.