Hello everyone!
In advance, sorry for all this text. I want to make a tutorial out of this...
I got an Arduino for Christmas with the hopes of making a subtractive synth out of it. In a perfect world I would like to have at least 2 oscillators (perhaps using PWM on outputs 9 and 10 on the board?) and be able to select each oscillator's wave form individually from a choice of a square, a triangle, a sawtooth or a sine wave.
I was able to make some progress using the piezo speaker example but that method is really only capable of producing square waves. I could of course convert the outputted square wave to whatever form I wanted externally (along with the phasing and stereo effect I was able to get working) but that's not really not clean enough for me. Along with requiring external signal processing, I couldn't get the square wave frequency range wide enough for the application.
So I want to move onto using Pulse Width Modulation to create the oscillators. I tried starting with a triangle wave. (it's hard to program a sine wave without a sin function.... anyone know how math.h is ever supposed to fit in ram?? or maybe even create a useable sine table??? ... anyways). I looked around and couldn't find any clear tutorials of how to do this so I figured I'd put what I figured out here... sorry if this info's repeated or if it's not exactly how it should be done.
The REAL problem is that I need to filter out the PWM's carrier signal to leave me with a clean analog waveform. This means I need a low-pass filter with a cutoff frequency above (hopefully) 20k Hz but below the PWM's carrier frequency. As stated on the analogWrite reference page, "The frequency of the PWM signal is approximately 30769 Hz".
After a few google searches I found this page that discusses how to make a low-pass filter that will be sufficient:
It mentions that a good cut off frequency for the filter should be at least 2 times greater then the highest frequency that you want to output. In (hi-fi?) audio applications, 20k Hz is usually the highest you ever need to pass.
20k Hz * 2 = 40k Hz > 30.769k Hz
By calculating this out, it seems, at first glance, that we are out of luck. The cut off frequency will still leave the carrier signal in the line. Not good. Maybe we won't have the Fundamental harmonic in there (higher then 30.769... calculate it out if you want...) but the carrier signal (though out of the audible range) is still going to be there.
But we can get around this. We are able to change the carrier frequencies of Arduino's PWM outputs. Looking around on the forums I found a post hinting at how we change it. (tell me if the link doesn't work...):
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1152547089/2
I've copied the relevant code snippet into this post to put it all in one place:
#define TIMER_CLK_STOP 0x00 ///< Timer Stopped
#define TIMER_CLK_DIV1 0x01 ///< Timer clocked at F_CPU
#define TIMER_CLK_DIV8 0x02 ///< Timer clocked at F_CPU/8
#define TIMER_CLK_DIV64 0x03 ///< Timer clocked at F_CPU/64
#define TIMER_CLK_DIV256 0x04 ///< Timer clocked at F_CPU/256
#define TIMER_CLK_DIV1024 0x05 ///< Timer clocked at F_CPU/1024
void Setup()
{
[...]
TCCR1B = (TCCR1B & ~TIMER_PRESCALE_MASK) | TIMER_CLK_DIV8);
[...]
}
Really we can set the frequency by using:
void Setup()
{
[...]
TCCR1B = 0x03; //or whatever setting we want to use...
[...]
}
We want the PWM carrier frequency to be higher then the default. The default I found (after trying all the options listed) seems to be 0x03.
This is where I start to get a bit confused. If 0x03 is the default value of TCCR1B and this value corresponds to "Timer clocked at F_CPU/64" AND if this means the PWM's carrier signal is at around 30.769 kHz then, (unless I'm reading it wrong... and doing my math wrong... which I probably did...):
F_CPU = 30.769 kHz *64 = 1969.216 kHz = 1.969 MHz != 16 mHz ATMega8 clock
What is going on here? Shouldn't it equal out? What does F_CPU really stand for?....
And thus my final question is this: What value of TCCR1B should I use to get the PWM's carrier frequency above 40 kHz? Or is it there already and I'm just not calculating this right?
I'd love to see a table in the reference page about the corresponding frequencies...
Thanks a lot for the help,
Sorry for all the text, I really couldn't find any real audio tutorials for Arduino and would love to get some synth tutorials out there.
~jamis