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 0x01, 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 0x00 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.