Unexpected Results when Attempting to Change PWM Frequency

Hello, all!
I'd like to change my Arduino's PWM frequency to something a bit higher. I intend to use a passive low-pass inductive-capacitive filter to filter the PWM to something a bit more linear after passing it through a buffer, so I'd like my frequency to be relatively high so that my inductors and capacitors may be relatively small. (I'm driving an ATX fan and want the RPM sensor to work) However, I've hit a slight snag.

So far, I've relied on these two documents for guidance:

https://sites.google.com/site/qeewiki/books/avr-guide/pwm-on-the-atmega328

Using them, I've written the following code:

void setup()
{
pinMode(11, OUTPUT);
OCR2A = 128; // ~50% duty cycle
OCR2B = 64; // ~25% duty cycle
TCCR2A |= _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); // Fast PWM on both ports.
TCCR2B |= _BV(CS20); // No prescaling
}

With this code, I'm expecting to see a 62.5 kHz square wave with a duty cycle of 50% on Pin 11 of the Arduino Uno, and the same frequency with a 25% duty cycle on Pin 3. However, according to an oscilloscope, the signal's frequency is 488 Hz, much lower than my expected frequency! This is also the pin's default frequency, isn't it?

I'm a bit at a loss as to why I'm getting these results. Does anyone understand why I'm getting these results? Have I misinterpreted the information in my resources? Can anyone offer any suggestions as to how to proceed? While I am considering purchasing a dedicated PWM controller, I'd like to see how well fixing this little mystery, or at least understanding it, goes.

Thank you!

You have not cleared the default prescaler (64 with _BV(CS22)) from TCCR2B before setting _BV(CS20). You are winding up with a prescaler of 128 (8us per tick) for a period a little over 2 ms for the fast pwm count up to 255.
That's why you see the 488 hz. Normally timer 2 pwm is prescaler 64 with pwm to 255, for a total count of 512 x 4 us = for the same 2048 us = 488 Hz.

Clear the control registers before setting up your parameters.

void setup()
{
pinMode(11, OUTPUT);
pinMode(3, OUTPUT);

TCCR2B = 0; //initialize Control register B which contains the prescaler settings
TCCR2A = 0; //initialize Control register A

OCR2A = 128; // ~50% duty cycle
OCR2B = 64; // ~25% duty cycle
TCCR2A |= _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); // Fast PWM on both ports.
TCCR2B |= _BV(CS20); // No prescaling
}

Thanks for the reply! I’ll test that tomorrow when I can get access to my oscilloscope again, and I’ll report back then. :slight_smile:

Success! Clearing the registers before setting my own prescaler value worked perfectly. Thank you for your help!