Changing the Arduino PWM Frequency

The default PWM frequency for PWM 3, 9, 10, & 11, at least for the Diecimila running at 16 MHz, is 488 Hz. That’s OK for dimming LEDs where you’re depending on persistence of vision, but it’s much too low when you must filter it down to DC.

The relevant file is hardware/cores/arduino/wiring.c, which is buried wherever your installation put it.

Turns out that the Arduino runtime setup configures the timer clock prescalers to 64, so the timers tick at 16 MHz / 64 = 250 kHz.

You can fix that by setting the Clock Select bits in the appropriate Timer Control Register B to 0×01, which gets you no prescaling and a 62.5 ns tick period:

TCCR0B = 0x01;   // Timer 0: PWM 5 &  6 @ 16 kHz
TCCR1B = 0x01;   // Timer 1: PWM 9 & 10 @ 32 kHz
TCCR2B = 0x01;   // Timer 2: PWM 3 & 11 @ 32 kHz

If you’re finicky, you’ll bit-bash the values rather than do broadside loads. However, it probably doesn’t matter, because Timer 0 runs in Fast PWM mode and Timers 1 & 2 run in Phase-Correct PWM mode, so WGMx2 = 0 in all cases.

Fast PWM mode means Timer 0 produces PWM at 250 kHz / 256 = 976 Hz. However, the Arduino runtime runs the millis() function from the Timer 0 interrupt, so changing the Timer 0 prescaler pooches millis(), delay(), and any routines that depend on them.

Phase-correct PWM mode means that Timers 1 & 2 count up to 0xff and down to 0×00 in each PWM cycle, so they run at 250 kHz / 512 = 488 Hz.

Adroit TCCRxB setting can prescale by 1, 8, 64, 256, or 1024. Or stop the Timer stone cold dead, if you’re not careful.

Before you fiddle with this stuff, you really should read the timer doc in the ATmega168 datasheet there.

Memo to Self: don’t mess with Timer 0.

About these ads

,

  1. #1 by Clint on 17-September-2009 - 00:22

    I was able to halve the multiplier on TCCR0B to x32 but found that millis() was multiplied by eight. As long as I took that into account, I was ok. Haven’t tried it with delay(), but I suspect it will work the same.

    I had deduced it from this table I found:

    // PWM FREQ. where the value is the number 1 to 7 from the following table:
    // 31372.5 Hz -> 1
    // 3921.57 Hz -> 2
    // 980.392 Hz -> 3
    // 490.196 Hz -> 4 (default)
    // 245.098 Hz -> 5
    // 122.549 Hz -> 6
    // 30.6373 Hz -> 7

    • #2 by Ed on 17-September-2009 - 11:47

      The actual PWM frequency depends on the hardware crystal oscillator frequency and the Arduino firmware. It has varied over the years, so it’s best to actually measure what your board produces and confirm it by checking the firmware.

      The three hardware timers use different PWM modes, so the same numeric value produces different PWM periods in different timers.

      Timers 0 and 1 share a prescaler, while Timer 2 is separate. The PWM frequencies in the table refer to Timer 2, not Timer 0!

      Unless you’ve got a compelling reason to mess with Timer 0, it’s better to leave it alone. All the library routines depend on millis() having the proper value, so you can introduce all sorts of weird behavior that can’t be attributed to anything in your own software!

      Pages 105 and 139 of the ATmega168 datasheet show you the choices for Timer 0. It’s dense reading, but well worth the effort.

  2. #3 by Joshua on 11-November-2011 - 01:53

    I need 40 kHz exactly for my ultrasonic transducer speakers. How do I get this desired frequency?

    • #4 by Ed on 11-November-2011 - 08:10

      need 40 kHz exactly for my ultrasonic transducer speakers

      Take the reciprocal of your desired frequency to get the period: 1 / 40 kHz = 25 us. Divide that by the clock tick, which will be 62.5 ns after you set TCCR1B (actually, just the CS bits) to 0×01: 25 us / 62.5 ns = 400. So you must count 400 ticks for each full period or 200 ticks for each half period.

      Timer1 runs in phase-correct mode by default, but runs from 0×00 through 0xff on each half-cycle. Set Mode 11 (WGM bits 1011 binary, be careful: WG13 and WGM12 are in TCCR1B) to use the limit in OCR1A, set OCR1A to 199 (0x00c7), and it will count 0 to 199, then 199 to 0. The OC1A pin will toggle each time it hits OCR1A and 0×0000, so you get a perfect square wave at 40 kHz.

      I haven’t actually done that in a while, so I probably have an off-by-one error in there somewhere, but it’ll get you close.

      Given that the transducers act as narrow bandpass filters, any frequency near 40 kHz should work fine. In this case you can get spot on, but if you have a transducer with an oddball frequency, get as close as you can.

  3. #5 by fye on 12-December-2011 - 11:11

    I need an exact input of; below 1.5kHz, 1.5kHz, 2kHz and 3kHz.

    how do I get the frequency? and how the coding looks like?

    • #6 by Ed on 12-December-2011 - 12:24

      Comment 4 for this post has all the details you need: knowing the exact period of your signal, find the number of clock cycles, then load that into the timer.

      You can probably adapt the code shown in that post to your needs, even though you have a much lower output frequency.

  1. Arduino Fast PWM: Faster « The Smell of Molten Projects in the Morning
  2. Arduino Mega 1280: PWM-to-Timer Assignment « The Smell of Molten Projects in the Morning
  3. DIY Electronic boost controller. - SRT Forums - SRT4, SRT6, SRT8, SRT10 & Dodge Forum
  4. Peltier Module PWM Frequency « The Smell of Molten Projects in the Morning
  5. Arduino Snippets: LED Stroboscopic Tachometer « The Smell of Molten Projects in the Morning
  6. Hall Effect LED Current Control: First Light | The Smell of Molten Projects in the Morning