Posted by on Jan 7, 2012 in Atmel AVR, Microcontrollers | 163 comments

# AVR Timers – PWM Mode – Part II

Hello folks! Long time no see! :)

In my previous post, we have discussed the basic concepts of PWM. Let’s summarize it first:

• PWM stands for Pulse Width Modulation.
• It can be generated by comparing predetermined waveform with a reference voltage level or by making simple analog circuits.
• Duty Cycle of a PWM waveform is given by the following relation.
• There are three modes of PWM operation – Fast PWM, Phase Correct PWM and Frequency and Phase Correct PWM
• How to choose timer, operation mode and compare output mode for generating the desired PWM.
So now, without much hassle, let’s see how to implement it using the AVR microcontrollers. Before we proceed, I suggest you to go through my previous posts on Timers and PWM.

# Problem Statement

Let us take a problem statement. We need to generate a 50 Hz PWM signal having 45% duty cycle.

### Analysis

Given that

`Frequency = 50 Hz`

In other words, the time period, T

`T = T(on) + T(off) = 1/50 = 0.02 s = 20 ms`

Also, given that

`Duty Cycle = 45%`

Thus, solving according to equation given above, we get

```T(on)  = 9 ms
T(off) = 11 ms```

Now, this can be achieved in two ways:

1. Use Timer in CTC Mode
2. Use Timer in PWM Mode

# Methodology – CTC Mode

Okay, so I won’t be writing any code here (just the pseudo code). I assume that after reading my previous posts, you are smart enough to write one yourself! We will discuss only the concepts.

Firstly, choose a suitable timer. For this application, we can choose any of the three timers available in ATMEGA32. Choose a suitable prescaler. Then set up the timer and proceed as usual. The catch lies here is that you need to update the compare value of OCRx register everytime. One such way is discussed in the pseudo code given below.

This is analogous to the traditional LED flasher, except the fact that the on and off times are different.

### Pseudo Code

```#include <avr/io.h>
#include <avr/interrupt.h>

uint8_t count = 0;               // global counter

// initialize timer, interrupt and variable
void timerX_init()
{
// set up timerX with suitable prescaler and CTC mode
// initialize counter
// initialize compare value
// enable compare interrupt
// enable global interrupts
}

// process the ISR that is fired
ISR (TIMERx_COMPA_vect)
{
// do whatever you want to do here
// say, increment the global counter
count++;

// check for the global counter
// if count == odd, delay required = 11 ms
// if count == even, delay required = 9 ms
// thus, the value of the OCRx should be constantly updated
if (count % 2 == 0)
OCRx = 9999;      // calculate and substitute appropriate value
else
OCRx = 10999;     // calculate and substitute appropriate value
}

int main(void)
{
// initialize the output pin, say PC0
DDRC |= (1 << 0);

// initialize timerX
timerX_init();

// loop forever
while(1)
{
// do nothing

}
}```

Now this is one method. And it’s very inefficient. You can increase its efficiency by writing a better C code (syntax-wise), however the concept remains the same. If you have any other method/concept, you are most welcome to share it here! :)

UPDATE: One of the readers of maxEmbedded, “coolpales” has written this code, and it worked for him.

Please note that this code not tested yet! So, if any of you is trying it out, do post your results here, I would be happy to see them! :)

# Methodology – PWM Mode

Okay, so now lets learn about the PWM mode. The PWM Mode in AVR is hardware controlled. This means that everything, by everything I mean “everything”, is done by the AVR CPU. All you need to do is to initialize and start the timer, and set the duty cycle! Cool, eh?! Let’s learn how!

Here, I have used Timer0 of ATMEGA32 for demonstration. You can choose any other other timer or AVR microcontroller as well. Now let’s have a look at the registers.

## TCCR0 – Timer/Counter0 Control Register

We have come across this register in my Timer0 tutorial. Here, we will learn how to set appropriate bits to run the timer in PWM mode.

TCCR0 Register

We will discuss only those bits which are of interest to us now.

• Bit 6,3 – WGM01:0 – Waveform Generation Mode – These bits can be set to either “00” or “01” depending upon the type of PWM you want to generate. Here’s the look up table.

Waveform Generation Mode Bit Description

• Bit 5,4 – COM01:0 – Compare Match Output Mode – These bits are set in order to control the behavior of Output Compare pin (OC0, pin 4 in ATMEGA32) in accordance with the WGM01:0 bits. The following look up table determine the operations of OC0 pin for Fast PWM mode.

Compare Output Mode, Fast PWM Mode

Now lets have a look at the Fast PWM waveforms. Detailed explanation can be found in my previous tutorial.

Fast PWM

Now let me remind you that the AVR PWM is fully hardware controlled, which means that even the timer compare operation is done by the AVR CPU. All we need to do is to tell the CPU what to do once a match occurs. The COM01:0 pins come into play here. We see that by setting it to “10” or “11”, the output pin OC0 is either set or cleared (in other words, it determines whether the PWM is in inverted mode, or in non-inverted mode).

Similarly for Phase Correct PWM, the look up table and the waveforms go like this.

Compare Output Mode, Phase Correct PWM Mode

Phase Correct PWM

Even here, setting COM01:0 to “10” or “11” determines the behavior of OC0 pin. As shown in the waveforms, there are two instances – one during up-counting, and other during down-counting. The behavior is clearly described in the look up table.

Please note that OC0 is an output pin. Thus, the effects of WGM and COM won’t  come into play unless the DDRx register is set properly. Refer this tutorial for more info.

• Bit 2:0 – CS02:0 – Clock Select Bits – These bits are already discussed in Timer0 tutorial.

## OCR0 – Output Compare Register

We have come across even this register in my Timer0 tutorial. We use this register to store the compare value. But when we use Timer0 in PWM mode, the value stored in it acts as the duty cycle (obviously!). In the problem statement, its given that the duty cycle is 45%, which means

`OCR0 = 45% of 255 = 114.75 = 115`

And that’s it! Now we are ready to write a code for it! :)

## Edit: Note

The following code discusses how to create a PWM signal of a desired duty cycle. If you wish to change its frequency, you need to alter the TOP value, which can be done using the ICRx register (which is not supported by 8-bit timers). For 16-bit Timer1, it can be varied using ICR1A. I will discuss about this soon when we discuss about servo control.

## Code

So here goes the code. To learn about I/O port operations in AVR, view this. To know about bit manipulations, view this. To learn how to use AVR Studio 5, view this. To learn how this code is structured, view the previous TIMER0 post.

```#include <avr/io.h>
#include <util/delay.h>
void pwm_init()
{
// initialize TCCR0 as per requirement, say as follows
TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00);

// make sure to make OC0 pin (pin PB3 for atmega32) as output pin
DDRB |= (1<<PB3);
}

void main()
{
uint8_t duty;
duty = 115;       // duty cycle = 45% of 255 = 114.75 = 115

// initialize timer in PWM mode
pwm_init();

// run forever
while(1)
{
OCR0 = duty;
}
}
```

# Problem Statement

So now, let’s take another problem statement. This one is going to be a more of a practical stuff unlike the previous one!

Let’s take the traditional LED flasher where we need to blink an LED at a particular frequency. But hey, wait, didn’t we discuss it long back in this post (scroll down towards the end)? Hmm, so let’s modify it so as to incorporate PWM. Unlike the traditional LED flasher (where LEDs are either ON or OFF), lets make it glow at the maximum brightness, and then slowly decrease its brightness till it reaches zero, and then again increase its brightness slowly till it becomes maximum.

### Analysis and Code

So how do we do it? Yes, you guessed it right! Decrease the duty cycle slowly from 255 to zero, and then increase it from zero to 255. Depending upon the duty cycle, the voltage applied to the LED varies, and thus the brightness. The following formula gives the relation between voltage and duty cycle.

So here goes the code. I won’t explain it, you can decode it yourself. To learn about I/O port operations in AVR, view this. To know about bit manipulations, view this. To learn how to use AVR Studio 5, view this. To learn how this code is structured, view the previous TIMER0 post.

```// program to change brightness of an LED
// demonstration of PWM

#include <avr/io.h>
#include <util/delay.h>

// initialize PWM
void pwm_init()
{
// initialize timer0 in PWM mode
TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00);

// make sure to make OC0 pin (pin PB3 for atmega32) as output pin
DDRB |= (1<<PB3);
}

void main()
{
uint8_t brightness;

// initialize timer0 in PWM mode
pwm_init();

// run forever
while(1)
{
// increasing brightness
for (brightness = 0; brightness < 255; ++brightness)
{
// set the brightness as duty cycle
OCR0 = brightness;

// delay so as to make the user "see" the change in brightness
_delay_ms(10);
}

// decreasing brightness
for (brightness = 255; brightness > 0; --brightness)
{
// set the brightness as duty cycle
OCR0 = brightness;

// delay so as to make the user "see" the change in brightness
_delay_ms(10);
}

// repeat this forever
}
}```

So here ends my another much awaited and long tutorial! Next up.. Serial Communication! See you around!! :)

And yeah, if you have any suggestions, doubts, constructive criticisms, etc, you are most welcome to drop a note  below! Subscribe to my blog or grab the RSS Feeds to stay updated!

1. In the above LED Brightness code, OCR0 is given Brightness value. Is the Brightness value the MAX value and very 10ms the max is varied and hence we get varying wave even 10ms?
Is this right?

• Am sorry that is not MAX, it is TOP*.

2. Hi Mayank,

Thank you for the wonderful tutorials. In fast PWM mode i could generate time periods from the range of nano seconds to seconds. But for an application in need to exactly fire 25 PWM pulses of some time period. If i give a variable inside the while loop and increment it for 25 times and then stop the timer, will i exactly get 25 pulses or is there any other way to count the number of pulses using the code or the interrupt functions.

3. how can i generate 50hz square clock pulse using timer,
and how can i phase shifted clock pulse using ??
thanks

4. it worked with me as blinking LED !!

• Thanks!

5. Hello

i am using ATMEGA32U4 (arduino board ), i am facing problem with TIMER , i want to generate 1 Hz to 40 Hz signal in Two pins and change PWM signal with certain period of time .
example –
TIME | PIN9 Freq. | PIN9 PWM | PIN10 Freq. | PIN10 PWM | Alternate Mode

T0 | 2Hz | 50% | 2Hz | 50% | 0
T1 | 3Hz | 50% | 15Hz | 20% | 0
T2 | 30Hz | 40% | 2Hz | 50% | 0
T3 | 2Hz | 50% | 2Hz | 50% | 1

#Alternate Mode activate 180 degree phase shift b/w PIN9 and PIN10 .

6. Hi there

In your article, you do a wonderful job of describing how to change the duty cycle of a PWM pulse, but there doesn’t seem to be any mention of how to control the frequency of the pulse. If you find the time, could you possibly explain how to do this? It would be much appreciated

Thanks :)

• Nevermind, I missed your edit in the article. Thanks anyway :)

7. hi, i need to use timer-0 as overflow timer and as in PWM mode as the same time. is it possible logically. please let me know anyone if its right what i want to do.

• No, you can’t use them in both the modes at the same time. Use different timers, or you’ll have to generate PWM in software, which won’t be effective.

8. cheers mate, thanks for the tutorials!

9. Thanks for your wonderful tutorial. I want to control the speed of stepper motor with pwm and variable frequency (my stepper driver l297/l298). Is there any possiblity to do this? I read the data sheet of atmega2560 but i didnt find about variable frequency its only about variable duity cycle and fixed frequency. could you give me some hint?

thanks alot!!!

• PWM and CTC are two different modes of the timer. If you want to generate PWM signal using CTC, then you’ll have to manually toggle the pin value at regular intervals (or interrupts) generated by the CTC.

10. I can simply generate a PWM pulse using Timer0 and Timer2 as you explained how. But, when I try using Timer1 the pulses are not generated on OC1A and OC1B PINs. Are there any particular differences resulting this?

11. “The COM01:0 bits come into play here.” not “The COM01:0 pins come into play here.”!!!

12. Hi!
A wonderful tutorial series. Did you finally discussed the Servo control? Will be glad to have a look.
Thanks. :)

13. I get the following errors during execution:

Build started 27.6.2017 at 18:16:31
avr-gcc -mmcu=atmega168p -Wall -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT UART_LED.o -MF dep/UART_LED.o.d -c ../UART_LED.c
../UART_LED.c: In function ‘pwm_init’:
../UART_LED.c:6: error: ‘TCCR0’ undeclared (first use in this function)
../UART_LED.c:6: error: (Each undeclared identifier is reported only once
../UART_LED.c:6: error: for each function it appears in.)
../UART_LED.c:6: error: ‘COM01’ undeclared (first use in this function)
../UART_LED.c: At top level:
../UART_LED.c:12: warning: return type of ‘main’ is not ‘int’
../UART_LED.c: In function ‘main’:
../UART_LED.c:23: error: ‘OCR0’ undeclared (first use in this function)
make: *** [UART_LED.o] Error 1
Build failed with 5 errors and 1 warnings…

14. Hello a question, I would like to know how it is possible to generate a pwm signal with two timer at the same time, I mean use the timer2 to generate the frequency of 50hz or what is the same the period of 20ms and with the timer1 trought a potentiometer and the ADC generate the pulse to move the servomotor shaft

15. Thank you so much. Perfect place to learn about Atmel avr microcontrollers. The content is very intresting to read.

16. Thanks, helped me a lot

17. Hi, thank you for another article. I have a question here. In the 2nd code example loop consist of line `OCR0 = duty`. Is there sense of doing it in the loop repeatedly instead to do it once outside the loop? Am I missing something?

• It doesn’t matter in this specific example since we are not changing the duty cycle. So yes, it’d probably be better if it is done outside the loop.

18. delay() use timer0 too ;)