Making better noises with dual PWM

pwm_16b_sm

Although it’s technically possible to get 16 bits of resolution on a ATMega328, most implementations of PWM on everyone’s favorite ‘mega – including just about every Arduino sketch – are limited to 8 bit PWM. This means the pins can only output 256 different values, so if you’re playing around with music made on an Arduino don’t expect very high fidelity.

There is a clever way around this: use two PWMs, and use one pin for high bytes and another for low bytes. That’s what Open Music Labs did when working on a synthesizer project that needed very high quality audio.

The basic idea behind the build is that PWM pins can be used to create audio frequencies. Using two PWM pins and adding them together means it’s possible to add extra bits of resolution. This requires using different values of resistors on each pin. For example, using the same value of resistors on two PWM pins increases the resolution by one bit. Two pins with a resistor value ratio of 1:4 increases the resolution by four bits, and so on.

There’s a great tutorial for setting up these higher resolution, dual PWM outputs on an ATMega or Arduino, as well as a distortion analysis for this dual PWM setup.

Comments

  1. Bogdan says:

    The article is very good as theory explanation.
    I’ve tried this once, going for an expansio to 12 bits. I’ve found the sound of a R2R rrsisot dac with 10bits resolution better than the 12b pwm generated.
    In then end i decided to go for a low cost audio dac with a serial interface, like the CS4344 for less than 2 eur. There are others and its easiyer to solder an 8 pin ic compared to what it take to build the dac out of more pwm channels. Its probably also cheaper.
    But, if 8bit pwm is sifficoent, theres no easier way.

  2. ino says:

    That’s clever but when I need custom made PWMs, I prefer to code them myself.
    It’s not difficult at all and you learn how to use Timers and Interrupts (every micro has a 16 bits timer in it today).

  3. Bogdan says:

    Dont forget tha a 16bit timer used with a 20MHz clock will get you 300Hz max frequency. This leaves you bandwith inusable for audio.
    This is the advantage of having 2 8bit pwm, the each can run at higher frequency.

    • krylenko says:

      Only if you start the timer at 0 and wait for it to fill up and overflow.

      In every micro I’ve seen you can load the timer with any value you want whenever you want. Load that 16-bit timer with 65,535 (and reload that value in your ISR) and it’ll overflow with every clock tick.

      Of course your ISR will take some time to run, but ~305 Hz is most assuredly *not* the upper frequency limit with a 20 MHz clock and 16-bit timer.

      • Arlet says:

        But how would you get 16 bit PWM resolution that way ?

      • jimjones says:

        If you want to have 2^16 discrete PWM steps, this means a maximum frequency of 20M/2^16. If you limit what you fill with to a number lower than 2^16, you are reducing the bits of precision. If you preload the counter with 61440, you have 4096 discrete values, and can operate up to 4.9kHz but you only get 12 bits of precision….

        305Hz *IS* the limit if you want 16 bits of dynamic range on your DAC for what Bogdan is talking about.

    • krylenko says:

      Oh, my bad, I thought Bogdan was talking about using the timer to trigger an interrupt that computes the next audio output. You all are of course right about using the timer to do the actual PWM.

  4. Bill says:

    Any idea why this uses 3 inverters in parallel to drive a high impedance load?

    • Bogdan says:

      It says in the article. The output resistance of the inverter is inconsistent, so it affects the accuracy of the 1:256 ratio. To minimieze the effect they use 3 inverters in parallel to mimimize what adds to the 3.9k

  5. bunedoggle says:

    Audio clip or it didn’t happen.

    But seriously…audio clip? :)

  6. whispers says:

    There is a public library for ‘Arduino’ called SimpleSDAudio…. that can use or two pwm pins (9/10) for 16bit audio..

    http://arduino.cc/forum/index.php/topic,112745.0.html

    lib: http://hackerspace-ffm.de/wiki/index.php?title=SimpleSDAudio

    standalone is very low quality volume and static.. but does ‘work’… (this is the minimum, pin9 only approach)….

  7. xl97 says:
  8. Charles says:

    EXACTLY. WHAT. I. NEEDED. TODAY! I will totally be genning this into an attiny85! PLL’d high speed timer FTW! I can’t wait to see if it works well at 16-bits.

    • TigerUp says:

      This is a very neat hack! I was already pretty satisfied with the audio coming out of the Attiny85’s high speed PWM (8 bits at 250khz). I’m very interested to see how much this can be improved using this technique. I’m not too crazy about throwing an inverter IC into the mix, because I’d just as simply add a cheap DAC IC. But still very cool !

      Charles read Bogdan’s comment above regarding 16-bits, it won’t work out.

  9. Necromant says:

    I didn’t get that at all.
    Why do you need this masohism, when there’s a timer/counter 1 capable of delivering 16-bit PWM for 2 OC pins? Or is the datasheet for atmega328 a lie?

  10. fartface says:

    Just use a 24bit serial DAC and call it done.

  11. ultrasounder says:

    http://www.edn.com/file/15421-93004di.pdf
    This is the original idea “I guess” that appeared back in 2004.

  12. Bill Gander says:

    Interesting read and I have all of the parts sitting around to mess with it tonight. Will probably even learn a thing or two trying to get things right :) Thanks to all.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s