Today we are going to see how to change the frequency of an analog output pin on Arduino, which will require us to configure the registers that control the Timers associated with the PWM pins. But don’t worry, we’ll make it easy with a single function.
Using timers is common in processors. However, you may have often seen us recommend avoiding their manipulation in Arduino because it can have unexpected effects, especially with third-party libraries. So, if we usually recommend avoiding manipulating Timers in Arduino, why would we want to change their frequency now? Well, basically because this allows us to improve the behavior of certain devices when they are controlled by a PWM signal.
Remember that when controlling a device with a PWM signal, we are actually turning the device completely on and off multiple times per second. That is not the same as applying a true analog signal, and as a general rule, many actuators do not handle PWM control well.
Increasing the PWM frequency can improve the operation of certain devices because they have less time to “notice” that we have turned them off. If the device’s inertia is sufficient, and its natural frequency is higher than the PWM frequency, the behavior will be (almost) identical to supplying an analog voltage.
The most frequent practical case is when controlling the speed of a motor, where using PWM we turn the motor on and off multiple times per second. The motor is an inductive load, and each start-up results in a significant inrush current spike. This leads to a situation where, when applying a speed reduction, the motor consumes more power, heats up more, makes more noise… when, a priori, one might think it should be the opposite because it is running at a lower speed.
That also doesn’t mean we can increase the frequency indefinitely like crazy. Not all drivers we are using will support the frequency, and if they don’t… boom! Each particular case must be examined, but in general, raising the PWM control frequency to 4-10 kHz is quite reasonable.
So here is a cheat sheet with the frequency, prescalers, default values, and consequences for each of the PWM pins for Atmega328p and Atmega 32u2 processors, as well as a function to modify it easily.
Atmega 328p (Arduino Uno, Nano)
Frequency
| Pins | Timer | Frequency |
|---|---|---|
| 5, 6 | Timer0 | 62500 Hz |
| 9, 10 | Timer1 | 31250 Hz |
| 3, 11 | Timer2 | 31250 Hz |
Default Values
| Pins | Timer | Prescalers | Frequency |
|---|---|---|---|
| 5, 6 | Timer0 | 64 | 977Hz |
| 9, 10 | Timer1 | 64 | 490Hz |
| 3, 11 | Timer3 | 64 | 490Hz |
Prescalers
| Pins | Timer | Prescalers |
|---|---|---|
| 5, 6 | Timer0 | 1 8 64 256 1024 |
| 9, 10 | Timer1 | 1 8 64 256 1024 |
| 3, 11 | Timer2 | 1 8 32 64 128 256 1024 |
Consequences and Effects
| Pins | Timer | Effect |
|---|---|---|
| 5, 6 | Timer0 | delay() and millis() |
| 9, 10 | Timer1 | Servo library |
| 3, 11 | Timer2 |
Code
//Atmega 328p (Arduino Uno, Nano)
// Frequencies
// 5, 6 Timer0 62500 Hz
// 9, 10 Timer1 31250 Hz
// 3, 11 Timer2 31250 Hz
// Prescalers
// 5, 6 Timer0 1 8 64 256 1024
// 9, 10 Timer1 1 8 64 256 1024
// 3, 11 Timer2 1 8 32 64 128 256 1024
// Default values
// 5, 6 Timer0 64 977Hz
// 9, 10 Timer1 64 490Hz
// 3, 11 Timer2 64 490Hz
// Consequences
// 5, 6 Timer0 delay() and millis()
// 9, 10 Timer1 Servo library
// 3, 11 Timer2
void setPWMPrescaler(uint8_t pin, uint16_t prescale) {
byte mode;
if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
switch(prescale) {
case 1: mode = 0b001; break;
case 8: mode = 0b010; break;
case 64: mode = 0b011; break;
case 256: mode = 0b100; break;
case 1024: mode = 0b101; break;
default: return;
}
} else if(pin == 3 || pin == 11) {
switch(prescale) {
case 1: mode = 0b001; break;
case 8: mode = 0b010; break;
case 32: mode = 0b011; break;
case 64: mode = 0b100; break;
case 128: mode = 0b101; break;
case 256: mode = 0b110; break;
case 1024: mode = 0b111; break;
default: return;
}
}
if(pin==5 || pin==6) {
TCCR0B = TCCR0B & 0b11111000 | mode;
} else if (pin==9 || pin==10) {
TCCR1B = TCCR1B & 0b11111000 | mode;
} else if (pin==3 || pin==11) {
TCCR2B = TCCR2B & 0b11111000 | mode;
}
}
Atmega 32U (Micro and Leonardo)
Frequencies
| Pins | Timer | Frequency |
|---|---|---|
| 3, 11 | Timer0 | 64500Hz |
| 9, 10 | Timer1 | 31250Hz |
| 5 | Timer3 | 31250Hz |
| 6, 13 | Timer4 | 31250Hz |
Default Values
| Pins | Timer | Prescalers | Frequency |
|---|---|---|---|
| 3, 11 | Timer0 | 64 | 977Hz |
| 9, 10 | Timer1 | 64 | 490Hz |
| 5 | Timer3 | 64 | 490Hz |
| 6, 13 | Timer4 | 64 | 490Hz |
Prescalers
| Pins | Timer | Prescalers |
|---|---|---|
| 3, 11 | Timer0 | 1 8 64 256 1024 |
| 9, 10 | Timer1 | 1 8 64 256 1024 |
| 5 | Timer3 | 1 8 64 256 1024 |
| 6, 13 | Timer4 | 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 |
Consequences
| Pins | Timer | Effect |
|---|---|---|
| 3, 11 | Timer0 | delay() and millis() |
| 9, 10 | Timer1 | |
| 5 | Timer3 | |
| 6, 13 | Timer4 |
Code
// Atmega 32U
// Frequencies
// 3, 11 Timer0 64500Hz
// 9, 10 Timer1 31250Hz
// 5 Timer3 31250Hz
// 6, 13 Timer4 31250Hz
// Prescalers
// 3, 11 Timer0 64 1 8 64 256 1024
// 9, 10 Timer1 64 1 8 64 256 1024
// 5 Timer3 64 1 8 64 256 1024
// 6, 13 Timer4 64 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384
// Default values
// 3, 11 Timer0 64 977Hz
// 9, 10 Timer1 64 490Hz
// 5 Timer3 64 490Hz
// 6, 13 Timer4 64 490Hz
// Consequences
// 3, 11 millis(), delay()
// 9, 10
// 5
// 6, 13
void setPWMPrescaler(uint8_t pin, uint16_t prescale)
{
byte mode;
if(pin==3 || pin==5 || pin==9 || pin==10 || pin==11) {
switch(prescale) {
case 1: mode = 0b001; break;
case 8: mode = 0b010; break;
case 64: mode = 0b011; break;
case 256: mode = 0b100; break;
case 1024: mode = 0b101; break;
default: return;
}
} else if(pin==6 || pin==13) {
switch(prescale) {
case 1: mode = 0b0001; break;
case 2: mode = 0b0010; break;
case 4: mode = 0b0011; break;
case 8: mode = 0b0100; break;
case 16: mode = 0b0101; break;
case 32: mode = 0b0110; break;
case 64: mode = 0b0111; break;
case 128: mode = 0b1000; break;
case 256: mode = 0b1001; break;
case 512: mode = 0b1010; break;
case 1024: mode = 0b1011; break;
case 2048: mode = 0b1100; break;
case 4096: mode = 0b1101; break;
case 8192: mode = 0b1110; break;
case 16384: mode = 0b1111; break;
default: return;
}
}
if(pin==3 || pin==11) {
TCCR0B = TCCR1B & 0b11111000 | mode;
} else if (pin==9 || pin==10) {
TCCR1B = TCCR1B & 0b11111000 | mode;
} else if (pin==5) {
TCCR3B = TCCR3B & 0b11111000 | mode;
} else if (pin==6 || pin==13) {
TCCR4B = TCCR4B & 0b11110000 | mode;
}
}
Download the Code
All the code from this post is available for download on Github.

