Arduino (ATmega) PWM audio DAC
About PWM on the Arduino (ATmega)
This page describes all the nitty gritty of getting your Arduino set up to output decent audio on its PWM via Timer1. For more in-depth information on what the settings mean, and what values are right for your application, please check out our PWM Tutorial on the main site.
Timer1 outputs its data on pins 9 and 10 on the Arduino (pin 9/10 are OC1A/B and PORTB1/2 on the ATmega328p). For all of the following, it will be assumed that pin 9 is used for Single PWM, and is the high byte for Dual PWM. Pin 10 is not used for Single PWM, and is the low byte for Dual PWM. You can also set up for Dual PWM, and output 2 different signals, one on each output.
Other timers can be similarly setup to run PWM, but we use Timer1 because it is a 16 bit timer, so it can do greater bit depth at lower frequencies (if desired). The register settings for other timers is similar, but check the ATmega328p data sheet to be make sure its all correct. Also, be careful when using Timer0 on the Arduino, as it is already in use for the delay() and millis() functions, and its overflow interrupt can not be reused.
The following charts all assume a microcontroller clock frequency of 16MHz (standard on the Arduino). If you are using a different oscillator, just multiply the frequencies listed by Fcpu/16MHz, where Fcpu is your oscillator frequency. For example, if you were running at 8MHz, you would multiply by 1/2, and if you were running at 20MHz, you would multiply by 5/4. Everything else stays the same.
Example Arduino Sketch
This skecth uses the above charts to set the Arduino PWM to 31.25kHz, Dual PWM, Phase Correct, at 16 bit depth. It takes in audio on ADC0, and plays it out the PWM, so you can hear the sort of quality you can expect from 10 bit data (10 bits is the depth of the ADC). The following low-pass filter and summing circuit should be used, along with a the bias circuit for the ADC.