logo elektroda
logo elektroda
X
logo elektroda

Change PWM Frequency on Arduino Uno Nano Pro Mini

User question

How to change PWM frequency on Arduino

Artificial Intelligence Response

Direct answer to the question

To change PWM frequency on Arduino, you usually change the hardware timer settings that generate PWM on the selected pin.

For a classic Arduino Uno / Nano / Pro Mini (ATmega328P):

  • Pins 5, 6Timer0
  • Pins 9, 10Timer1
  • Pins 3, 11Timer2

The simplest method is to change the timer prescaler by writing to the TCCRnB register.

Example: make pins 9 and 10 run at about 31 kHz

void setup() {
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
// Timer1 prescaler = 1
TCCR1B = (TCCR1B & 0b11111000) | 0x01;
analogWrite(9, 128); // 50% duty cycle
}
void loop() {
}

That is the short answer.
The important part is choosing the correct timer and understanding the side effects.


Detailed problem analysis

1. How Arduino PWM frequency is determined

PWM frequency depends on:

  • CPU clock, typically 16 MHz
  • timer mode
  • timer prescaler
  • timer TOP value

In simplified form:

\[ f{PWM} = \frac{f{CPU}}{N \times \text{counts}} \]

where:

  • \(f_{CPU}\) = 16 MHz on a standard Uno
  • \(N\) = prescaler
  • counts depends on PWM mode and timer resolution

On the Uno, the default Arduino core uses:

  • Timer0: Fast PWM
  • Timer1: Phase-correct 8-bit PWM
  • Timer2: Phase-correct 8-bit PWM

That is why the default frequencies are approximately:

Timer Pins Default frequency
Timer0 5, 6 ~976 Hz
Timer1 9, 10 ~490 Hz
Timer2 3, 11 ~490 Hz

2. The easiest method: change only the prescaler

This is the most common approach if you only need “higher” or “lower” PWM and not an exact arbitrary frequency.

Timer1: pins 9 and 10
void setup() {
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
// Change Timer1 prescaler
TCCR1B = (TCCR1B & 0b11111000) | 0x01; // prescaler = 1
analogWrite(9, 128);
}

For Timer1 on Uno, practical frequencies are approximately:

Prescaler bits Prescaler Frequency on pins 9/10
0x01 1 ~31.37 kHz
0x02 8 ~3.92 kHz
0x03 64 ~490 Hz
0x04 256 ~122 Hz
0x05 1024 ~30.6 Hz
Timer2: pins 3 and 11
void setup() {
pinMode(3, OUTPUT);
pinMode(11, OUTPUT);
TCCR2B = (TCCR2B & 0b11111000) | 0x01; // prescaler = 1
analogWrite(3, 128);
}

Approximate Timer2 frequencies:

Prescaler bits Prescaler Frequency on pins 3/11
0x01 1 ~31.37 kHz
0x02 8 ~3.92 kHz
0x03 32 ~980 Hz
0x04 64 ~490 Hz
0x05 128 ~245 Hz
0x06 256 ~122 Hz
0x07 1024 ~30.6 Hz
Timer0: pins 5 and 6
void setup() {
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
TCCR0B = (TCCR0B & 0b11111000) | 0x01; // prescaler = 1
}

Approximate Timer0 frequencies:

Prescaler bits Prescaler Frequency on pins 5/6
0x01 1 62.5 kHz
0x02 8 7.81 kHz
0x03 64 ~976 Hz
0x04 256 ~244 Hz
0x05 1024 ~61 Hz

3. Important correction to common online examples

A frequent mistake is using the formula for 8-bit fast PWM for all timers, then claiming Timer1 or Timer2 default is several kilohertz. On the Uno, the default Arduino setup for Timer1 and Timer2 is phase-correct PWM, so the default is about 490 Hz, not 3.9 kHz.

That distinction matters when calculating expected frequency.


4. Exact frequency method: reconfigure Timer1 TOP value

If you need a specific frequency such as:

  • 25 kHz for a 4-wire PC fan
  • 20 kHz to move motor PWM above audible range
  • 50 Hz for a non-standard pulse application

then changing only the prescaler is not enough.
You should set Timer1 into a mode where TOP = ICR1.

Example: exact PWM frequency on pin 9
void setup() {
pinMode(9, OUTPUT);
// Fast PWM, mode 14: TOP = ICR1
TCCR1A = _BV(COM1A1) | _BV(WGM11);
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // prescaler = 1
ICR1 = 639; // 25 kHz: 16e6 / (1 * (1 + 639)) = 25 kHz
OCR1A = 320; // ~50% duty cycle
}
void loop() {
}

Formula:

\[ TOP = \frac{F{CPU}}{N \cdot f{PWM}} - 1 \]

Duty cycle is set by OCR1A or OCR1B:

\[ D = \frac{OCR1x}{TOP+1} \]

This method gives:

  • much more precise frequency control
  • access to frequencies not possible by prescaler-only changes

But:

  • it takes over that timer
  • analogWrite() on that timer’s pins is no longer the normal Arduino behavior

Current information and trends

For Arduino-class embedded work, the practical direction is:

  • AVR boards such as Uno/Nano: direct register programming remains the standard way
  • newer boards such as SAMD, ESP32, RP2040: PWM is configured differently and often more flexibly
  • for motor control, designers increasingly use 20 kHz to 30 kHz PWM to avoid audible noise
  • for LED dimming, common frequencies are from a few hundred hertz to several kilohertz depending on flicker requirements and camera compatibility

If you are using something other than an ATmega328P-based board, the register names and method will be different.


Supporting explanations and details

Which method should you use?

Use prescaler-only change if:
  • you want a quick solution
  • an approximate frequency is acceptable
  • you still want to use analogWrite()
Use Timer1 custom TOP if:
  • you need an exact frequency
  • you need frequencies like 20 kHz or 25 kHz precisely
  • you are comfortable working directly with timer registers

Typical application frequencies

Application Typical PWM frequency
LED dimming 200 Hz to 2 kHz
DC motor control 4 kHz to 25 kHz
Silent motor drive >20 kHz
PC 4-wire fan control 25 kHz
Servo-style control usually not standard PWM duty control; often 50 Hz pulse timing

Note that servo control is not the same as generic PWM dimming. Servos expect pulse timing, not merely duty-cycle modulation.


Practical guidelines

Best timer choices on Uno

  • Safest general choice: Timer2 on pins 3 or 11
    • because it does not break millis() / delay()
  • Best for precise custom frequency: Timer1 on pins 9 or 10
    • because it is 16-bit
  • Avoid changing Timer0 unless necessary
    • it affects core timing functions

Side effects by timer

  • Timer0
    • affects millis(), micros(), delay()
  • Timer1
    • can interfere with the Servo library
  • Timer2
    • can interfere with tone()

Also remember

  • changing one timer affects both PWM pins on that timer
  • higher PWM frequency often means reduced duty-cycle resolution
  • if a library also uses that timer, conflicts are likely

Possible disclaimers or additional notes

  • The code above is for classic AVR Arduino boards, especially Uno/Nano/Pro Mini with ATmega328P.
  • It is not directly valid for:
    • ESP32
    • RP2040
    • SAMD21/SAMD51
    • Mega2560 without adapting timer selection
  • Some example code found online mixes Fast PWM and Phase Correct PWM formulas incorrectly. That leads to wrong expected frequencies.

Suggestions for further research

If you want to go deeper, the next topics to study are:

  • AVR timer modes: Fast PWM vs Phase Correct PWM
  • TCCRnA, TCCRnB, OCRnx, ICR1
  • timer interrupt usage
  • how PWM frequency affects:
    • motor losses
    • MOSFET switching losses
    • acoustic noise
    • LED flicker
    • EMC behavior

Brief summary

To change PWM frequency on Arduino:

  1. identify which timer controls your PWM pin
  2. change that timer’s prescaler for a quick frequency change
  3. use Timer1 with ICR1 as TOP if you need an exact frequency

For a standard Uno:

  • pins 9/10: edit TCCR1B
  • pins 3/11: edit TCCR2B
  • pins 5/6: edit TCCR0B, but this affects timing functions

If you want, I can give you a ready-to-use snippet for your exact board, pin, and target frequency.

Ask additional question

Wait...(2min)
Disclaimer: The responses provided by artificial intelligence (language model) may be inaccurate and misleading. Elektroda is not responsible for the accuracy, reliability, or completeness of the presented information. All responses should be verified by the user.