Fast PWM on ATmega328, up to 8MHz
sacrificing duty cycle resolution to get higher frequency
A couple of days earlier, a friend asked me how he could get fast PWM from an Atmel ATmega328 microcontroller —fast as in over 62.5KHz. Surpisingly I couldn't find a working code example, despite the fact there are many articles and forum posts about this. Of course one may always refer to the uC's datasheet, but the code part isn't always straightforward.
So, without delay here is a sample code you can load to your Arduino Uno or directly to an AVR, which will give you a 250KHz, 6 bit resolution PWM on pin 3 (ATmega pin 5) and a 8MHz, 1 bit resolution —thus only 50% duty cycle— on pin 5 (ATmega pin 11). The duty cycle of the 250KHz PWM is rolling.
So how does this code work? Let's talk about the uC for a bit first.
Fast PWM
The ATmega328 has 3 counters and usually runs at 16MHz. We will focus on counters #0 and #2 —counter #1 is a bit different.
A PWM waveform is generated from a counter by counting clock ticks, a register and a comparator. The counter's purpose is to create the duty cycle resolution. One complete cycle of the counter is one period of your PWM. In most tutorials this is referred as the second clock division during PWM generation. The counter's size (and thus the duty cycle resolution) is 8 bits, which equals to 256 values. So from the get-go, your 16MHz clock gets divided by 256 —because a cycle of the counter takes 256 ticks— and may give a maximum frequency of 62.5KHz. In order to get lower frequencies, you can divide your clock by another factor, known as the first clock division. This is also called pre-scaling, because it precedes the counter.
The register and the comparator are used to set and create the duty cycle output. The register sets for how long during each period the output is high. For example for a 25% duty cycle, you would set the register to
256 * 0.25 - 1 = 63
. The comparator compares the register's value with the current counter value and gives high
in the output if the value of the former is equal or lower from the value of the latter and low
otherwise.
For each counter you actually get 2 registers and 2 comparators, so you can get 2 PWM waveforms with different duty cycles but with the same frequency.
If you managed to read until here, you learnt how the normal fast PWM mode of the ATmega328 works. In the datasheet it is referred to as waveform generation mode 3.
Faster than Fast
It should be clear by now that in order to get above 62.5KHz you have to sacrifice something; duty cycle resolution. You also have to give up one PWM output per counter. Enter waveform generation mode 7.
What happens in this mode, is that you use one register and one comparator to set the top value of the counter. By controlling when your 8bit counter resets, you effectively set the frequency —remember, one cycle of the counter is one period of your PWM. Also you lower your duty cycle resolution since it depends on how may discrete values your counter has in a period. The second register and comparator pair works as always, generating the PWM output. An obvious requisite, is that the second register should be lower or equal to the first register.
Code Explained
Here is how we got the 250KHz waveform from timer/counter #2. The counter has control registers
TCCR2A
and TCCR2B
which hold flags that set its mode of operation. We show only the settings for fast PWM. Also it has registers OCR2A
and OCR2B
, the function of which we described in the previous section (remember registers and comparators).Everyone loves images
This is how our PWMs look on a logic analyzer.
250KHz with rolling duty cycle:

8MHz, logic analyzer samples at 24MHz, so it can't detect accurately the duty cycle:

Attribution
As stated there are many articles and forum posts about the subject. The one I found really useful and have to give credit is this. Of course do not forget to read your microcontroller's datasheet.
That's all folks
The reason my friend needed that fast PWM is interesting on its own and I hope he will find some time to write about it in the future.
Comments
Post a Comment