The ATmega328P Timer/Counter0 can generate PWM signals in two main modes: Fast PWM and Phase Correct PWM. Fast PWM is the preferred choice for power regulation, rectification, and DAC applications because its single-slope counting operation allows for higher output frequencies. This tutorial explains Fast PWM mode for Timer/Counter0 and walks through six complete example programs.
For other ATmega328P timer modes, see:
- ATmega328P Timer Programming Examples — Normal Mode
- Programming ATmega328P in CTC Mode
- Phase Correct PWM with ATmega328P
How Fast PWM Works
In Fast PWM mode, the timer counts upward from 0 to a TOP value in a single slope, then immediately resets to 0 and repeats. The output pin is set or cleared when the counter matches the value in the Output Compare Register (OCR0A or OCR0B), producing a PWM signal. Because the counter only counts in one direction, Fast PWM achieves a higher frequency than Phase Correct PWM for the same clock and prescaler settings.
Mode 3 vs Mode 7
Timer/Counter0 has two Fast PWM sub-modes selected by the Waveform Generation Mode bits WGM02 (in TCCR0B), WGM01, and WGM00 (in TCCR0A):
- Mode 3 — TOP is fixed at 0xFF (255). Both OC0A and OC0B are available as PWM outputs, each controlled by their own OCR register.
- Mode 7 — TOP is set by the OCR0A register, giving you a variable period. Because OCR0A is used for TOP, the PWM output must be taken from OC0B only.
WGM02 is in the TCCR0B register:
WGM01 and WGM00 are in the TCCR0A register:
Non-Inverting vs Inverting Output
Once the mode is chosen, output polarity is set using the Compare Output Mode bits in TCCR0A: COM0A1/COM0A0 for the OC0A pin, and COM0B1/COM0B0 for the OC0B pin. The table below shows the bit combinations for non-inverting and inverting Fast PWM:
The timing diagram below shows both non-inverting and inverting Fast PWM waveforms side by side:
Part A — Non-Inverting Fast PWM
Frequency
The Fast PWM output frequency is given by:
\(F_{w}=\frac{F_{osc}}{256 \times N}\)
Where \(F_{osc}\) is the CPU clock and N is the prescaler (1, 8, 64, 256, or 1024). With an 8 MHz clock and no prescaler (N = 1), this gives a PWM frequency of 31.25 kHz.
The Clock Select bits CS02, CS01, and CS00 in TCCR0B select the prescaler:
Duty Cycle
The OCR register value for a desired duty cycle D (0–100%) is:
\(OCR0 = \frac{256 \times D}{100} - 1\)
For example, a 75% duty cycle gives OCR0 = 191. You can use the online ATmega Timer/Counter calculator to compute this automatically:
Example 1 — Non-Inverting Fast PWM, Mode 3, OC0A Output
This example outputs a 75% duty cycle PWM signal at 31.25 kHz on the OC0A pin (PD6). Only COM0A1 needs to be set for non-inverting mode; WGM01 and WGM00 select Fast PWM mode 3; CS00 starts the timer with no prescaler.
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
int main(void)
{
DDRD |= (1<<PD6); // OC0A as output (Port D, Pin 6)
OCR0A = 191; // 75% duty cycle
// Non-inverting Fast PWM mode 3
TCCR0A |= (1<<COM0A1) | (1<<WGM01) | (1<<WGM00);
// No prescaler - start timer
TCCR0B |= (1<<CS00);
while (1);
return 0;
}
The waveform confirms a 75% duty cycle and the Fourier plot shows the fundamental at 31.25 kHz.
Example 2 — Non-Inverting Fast PWM, Mode 3, OC0B Output
To use OC0B (PD5) instead of OC0A, switch the compare unit to B by using COM0B1 and loading the duty cycle value into OCR0B. The WGM and CS bits are unchanged.
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
int main(void)
{
DDRD |= (1<<PD5); // OC0B as output (Port D, Pin 5)
OCR0B = 191; // 75% duty cycle
// Non-inverting Fast PWM mode 3 on OC0B
TCCR0A |= (1<<COM0B1) | (1<<WGM01) | (1<<WGM00);
TCCR0B |= (1<<CS00); // No prescaler
while (1);
return 0;
}
Example 3 — Non-Inverting Fast PWM, Mode 7, OC0B Output
In mode 7, OCR0A holds the TOP value rather than the fixed 0xFF, which lets you shorten the counter period. Since OCR0A is reserved for TOP, output is only available on OC0B. The TOP value in OCR0A must always be greater than or equal to the OCR0B duty cycle value.
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
int main(void)
{
DDRD |= (1<<PD5); // OC0B as output (Port D, Pin 5)
OCR0A = 200; // TOP value (must be >= OCR0B)
OCR0B = 191; // 75% duty cycle
// Non-inverting Fast PWM mode 7 on OC0B
TCCR0A |= (1<<COM0B1) | (1<<WGM01) | (1<<WGM00);
TCCR0B |= (1<<WGM02) | (1<<CS00); // WGM02 selects mode 7
while (1);
return 0;
}
Part B — Inverting Fast PWM
Inverting Fast PWM produces the complement of the non-inverting signal. The output pin is set at the compare match and cleared at TOP, flipping the active portion of the waveform. The output frequency is identical to the non-inverting case.
Duty Cycle Formula (Inverting)
Because the polarity is flipped, the OCR register value is calculated differently:
\(OCR0 = 255 - \frac{256 \times D}{100}\)
For a 75% duty cycle this gives OCR0 = 63. You can verify this with the online ATmega Timer/Counter calculator:
Example 4 — Inverting Fast PWM, Mode 3, OC0A Output
To enable inverting mode on OC0A, both COM0A1 and COM0A0 must be set in TCCR0A. The duty cycle value (63 for 75%) is loaded into OCR0A.
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
int main(void)
{
DDRD |= (1<<PD6); // OC0A as output (Port D, Pin 6)
OCR0A = 63; // 75% duty cycle (inverting formula)
// Inverting Fast PWM mode 3 - both COM0A bits set
TCCR0A |= (1<<COM0A1) | (1<<COM0A0) | (1<<WGM01) | (1<<WGM00);
TCCR0B |= (1<<CS00); // No prescaler
while (1);
return 0;
}
Example 5 — Inverting Fast PWM, Mode 3, OC0B Output
For inverting output on OC0B, set both COM0B1 and COM0B0 and load OCR0B with the inverted duty cycle value. Note that in the original code OCR0A was used for the OC0B example in error — the correct register is OCR0B.
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
int main(void)
{
DDRD |= (1<<PD5); // OC0B as output (Port D, Pin 5)
OCR0B = 63; // 75% duty cycle (inverting formula)
// Inverting Fast PWM mode 3 - both COM0B bits set
TCCR0A |= (1<<COM0B1) | (1<<COM0B0) | (1<<WGM01) | (1<<WGM00);
TCCR0B |= (1<<CS00); // No prescaler
while (1);
return 0;
}
Example 6 — Inverting Fast PWM, Mode 7, OC0B Output
Mode 7 inverting works the same as mode 7 non-inverting in terms of register setup, except both COM0B bits are set. OCR0A holds the TOP value and OCR0B holds the inverted duty cycle count. The TOP value must be greater than the OCR0B value.
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
int main(void)
{
DDRD |= (1<<PD5); // OC0B as output (Port D, Pin 5)
OCR0A = 200; // TOP value (must be > OCR0B)
OCR0B = 63; // 75% duty cycle (inverting formula)
// Inverting Fast PWM mode 7
TCCR0A |= (1<<COM0B1) | (1<<COM0B0) | (1<<WGM01) | (1<<WGM00);
TCCR0B |= (1<<WGM02) | (1<<CS00); // WGM02 selects mode 7
while (1);
return 0;
}
Compile and upload the above examples using your preferred ATmega328P programming tool. If you are new to the ATmega328P, start with a simple LED blink program first to verify your toolchain and hardware setup.
Summary
This tutorial covered all six Fast PWM configurations for ATmega328P Timer/Counter0. Here are the key points to remember:
- Use mode 3 for a fixed 8-bit resolution; both OC0A and OC0B are available as outputs.
- Use mode 7 when you need a custom TOP value; output is restricted to OC0B only.
- Set only COM0x1 for non-inverting output; set both COM0x1 and COM0x0 for inverting output.
- Non-inverting duty cycle: \(OCR0 = \frac{256 \times D}{100} - 1\)
- Inverting duty cycle: \(OCR0 = 255 - \frac{256 \times D}{100}\)
- PWM frequency: \(F_w = \frac{F_{osc}}{256 \times N}\)
The next tutorial in this series covers Phase Correct PWM with ATmega328P.
See also: