Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   This topic is locked: you cannot edit posts or make replies.
View previous topic Printable version Log in to check your private messages View next topic
Author Message
abcminiuser
PostPosted: Jul 18, 2008 - 10:07 AM
Moderator


Joined: Jan 23, 2004
Posts: 9828
Location: Trondheim, Norway

This is a continuation of my Timers tutorial and assumes the reader has read and understood that text before beginning this one.

Part Nine - Pulse Width Modulation (PWM)


The previous sections of the timers tutorial have been dealing with a simple task - flashing a LED. We've managed to accomplish that task using a variety of methods which all center around the "Clear On Timer Compare" (or CTC) method of using the timer, in both software and hardware. But what if we want to dim the LED instead? Now we are getting into a new timer concept, that of Pulse Width Modulation, abbreviated to PWM for short.

Pulse Width Modulation allows us to interface our digital components with the analogue world. We can use PWM to adjust a motor's speed, a LED's brightness or a speaker's tone. PWM is a very important concept, which is used all throughout the world of digital electronics. It is a way of approximating an analogue source, which with a little filtering can be used as a real analogue source (albeit with a few limitations).

It's important to note that PWM does not change our AVR's limitations; the signal sent out by the timer is still a true digital signal. However, by altering the on and off time of the signal at a given frequency, we can adjust the average on time to give an approximate analogue signal. This signal is good enough for immediate use in many applications - including motor speed control and LED dimming - without any extra filtering, or with the addition of a capacitor the output can be smoothed to a real analogue wave.

Let's start with a picture representing the different types of signals (modified from Wikipedia):



The top waveform is a traditional analogue signal, varying smoothly from GND to VCC volts. The bottom waveform is a digital representation of the top, using PWM.

PWM allows us to set an overall frequency, and then vary the on and off time (called the duty cycle) of the output within each timer cycle. A longer duty cycle gives a longer on time, resulting in an analogue representation closer to the VCC voltage. A duty cycle of 100% (on for the entire cycle) gives a VCC output, while a duty cycle of 0% (off for the entire cycle) gives a GND output.

When we use the CTC timer mode, what we are actually doing is essentially PWM, but with a fixed duty cycle of 50%, and a variable frequency. For this example, we're using PWM and will conversely be using a fixed frequency and varying the duty cycle to dim our LED.


There are several different PWM modes that the AVR timers can be initialized in, each with slightly different characteristics. These are as follows:

    1) Fast PWM (8, 9 or 10 bit)
    2) Phase Correct PWM
    3) Phase and Frequency Correct PWM



Before we can explore the different modes, we need to understand a little of the timer terminology. Frequency, as we know, is the number of cycles per second that the timer runs at - a higher frequency gives us a faster timer. In the PWM world, having a faster PWM frequency gives us finer control over the output, as we can respond faster to new PWM duty cycles. This is especially important when using PWM to produce audio from digital samples; a faster PWM frequency is required to give the full output frequency range by varying the duty cycle.

Next, we have the BOTTOM value. This is the lowest value that the timer will reach in the current mode. In all timer modes on all AVRs, this will be zero. Accompanying BOTTOM is TOP, which is the maximum value that the timer will reach before either (depending on the mode) resetting back to 0x00 or begin counting in reverse back to BOTTOM. For the normal mode, TOP is equal to the maximum value the timer can reach. For CTC mode, TOP is user settable, which gives us our control over the timer period. We are now using PWM, thus TOP is now set to give the PWM frequency.

Finally, we have our PWM COMPARE value. This sets the duty cycle - when this value is reached the waveform is inverted from its current state. Varying the COMPARE value will give us our varying duty cycle.

Now, let's get down to business and go into the three PWM modes.


Fast PWM

Fast PWM is useful for outputting PWM values quickly, at a loss of phase correctness - changes to the duty cycle will be reflected immediately, with the new signal being phase incorrect. When selected, the timer will count up from BOTTOM to TOP, with TOP being fixed at the bit-width of the fast PWM -- we are given a choice of 8, 9 or 10 bits depending on the timer bit width (8 bit timers will obviously not offer Fast PWM in more than 8-bits). The timer, when started, will count up continuously until TOP is reached, when it wraps back to BOTTOM and starts again. Inside this period when the counter reaches the COMPARE value, the output pin is set when the correct value is reached (and cleared when the timer wraps back from TOP to BOTTOM), so that varying COMPARE we get a PWM of a fixed frequency but a variable duty cycle.



This gives us the ability to change the duty cycle rapidly, in applications where the phase change does not matter. Applications such as motor control are particular about the phase, so we need to use the Phase Correct PWM mode.


Phase Correct PWM

Phase correct PWM gives phase-correct output as the duty cycle changes. The concept of phase is foregn to some, so we'll take a look graphically at how phase-incorrect (Fast PWM) and phase-correct PWM waveforms differ:



Notice the difference? In the case of Fast PWM, the high points are always aligned to the start of each period, with a smaller duty cycle resulting in a shorter ON time. Phase Correct PWM by contrast aligns the high points to the center of each period, so that a smaller duty cycle results in a shorter ON time -- but the ON times of all signals are aligned. As inducated in the Fast PWM explanation, this mode is useful in applications where the phase of the signals should not change, even if the duty cycles do. Phase Correct is slower than Fast PWM (as the name of the latter implies) due to the way Phase Correct PWM works.

When selected, the timer will count up from BOTTOM to TOP, and then start counting downwards back to BOTTOM before repeating. When upcounting, reaching COMPARE will turn on the output pin, while reaching the same value when downcounting will turn the output off. This results in the timer period being twice as long as Fast PWM mode (since the timer also has to count back to BOTTOM rather than just wrapping) but produces a phase-correct signal.



In Phase Correct PWM, the TOP value is variable and so the mode supports a variable PWM frequency. For generating simple audio tones from a speaker it is common to use the variable frequence of this mode to change the note pitch, and use the duty cycle to change the volume; a higher duty cycle results in a longer ON timer for the speaker, and so produces a louder sound.

SECTION INCOMPLETE - More updates soon.

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.


Last edited by abcminiuser on Aug 31, 2008 - 12:44 PM; edited 1 time in total
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
new2atmel
PostPosted: Aug 13, 2008 - 04:30 PM
Rookie


Joined: Aug 06, 2007
Posts: 27


Hi all,
Firstly I have to say the Dean is a gentleman and a scholar for providing such an educational tutorial.
Secondly, if anyone is interested here is some PWM code I wrote in AVR Studio. It uses UART commands from the PC for triggering the PWM on or off. It uses the Mega32 @10MHz and sets up the PWM for motor control with the frequency set at ~20kHz @ 75% duty cycle using Timer 0

Code:

void PWM_Init()
{
   TCCR0 = (0<<WGM01)|(1<<WGM00)|(1<<CS00);//setup PMW, no prescaler
   OCR0 = 0xC0; //set 75% duty cycle
   DDRB |= (1<<DDB3);
}
void main()
{
   unsigned char PWM_on;
   unsigned char PWMON[]="PWM on Pin 4";
   unsigned char PWMOFF[]="PWM off Pin 4";
   PWM_on = 0;
   PWM_Init();
   while (1)
   {
      switch (Received_Command)
      {
        case '3':         
        if (PWM_on == 1)
        {
        TCCR0 ^=(1<<COM01); //disable OC0
        PWM_on = 0;
        UART_putstring(PWMOFF);
        USART_Transmit(LF);
        Received_Command = '0';
        }
        else
        {
        TCCR0 ^=(1<<COM01);
//Clear OC0 on compare match when up-counting. Set OC0 on compare match when downcounting.
        PWM_on = 1;
        UART_putstring(PWMON);
        USART_Transmit(LF);
        Received_Command = '0';
        }
   }//end while(1)
}





I won't bother with the UART code as there is a tute for this.
Enjoy Smile
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 13, 2008 - 04:35 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62321
Location: (using avr-gcc in) Finchingfield, Essex, England

Presumably this is cut from something larger? Otherwise what's the point of a switch() with only one case: ?

(also this is presumably only going to do 20KHz if F_CPU matches yours?)

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
new2atmel
PostPosted: Aug 13, 2008 - 04:44 PM
Rookie


Joined: Aug 06, 2007
Posts: 27


Yep it's huge, I just cut and pasted something that would work.
Quote:
(also this is presumably only going to do 20KHz if F_CPU matches yours?)

yes 20KHz will work only at 10MHz F_CPU with this setup - hence all the info.

Cheers
 
 View user's profile Send private message  
Reply with quote Back to top
fizgig
PostPosted: Aug 19, 2008 - 02:30 AM
Hangaround


Joined: May 03, 2005
Posts: 275
Location: Windsor, CA

Man, I can't wait for him to finish this tutorial!!!

Does anyone know of any other PWM lessons that are relevant to AVR users?
 
 View user's profile Send private message  
Reply with quote Back to top
emuler
PostPosted: Aug 30, 2008 - 09:05 AM
Raving lunatic


Joined: Feb 07, 2007
Posts: 2395
Location: New Delhi, India

Simply beautiful, Dean. Very Happy That explanation of Phase Correct PWM is the best I've ever read. Truly, a picture is worth a thousand words. (Not your words, of course. Smile )

Quote:
As this tutorial chain gets a lot of discussion and questions I'd think that moving all the tutorials to a new thread which is then locked would make sense.

I concur with what JohanEkdahl suggests. In addition, some navigation tabs (index page) so the reader can quickly jump to the desired chapter/section.
 
 View user's profile Send private message  
Reply with quote Back to top
jimy.pesin
PostPosted: Sep 29, 2008 - 09:34 PM
Newbie


Joined: Aug 29, 2008
Posts: 3
Location: Long Island, NY

I still don't see the benefit to going to a phase corrected PWM and I don't agree that you get a shorter ON time with the phase corrected PWM. The only thing is that by decreasing your frequency you will have a wider range to work with, but the minimum pulse width will remain the same and the duty cycle percentage will appear smaller because you are comparing the minimum on time to a longer period. So it seems like phase correction is be done with the fast PWM and introducing a delay to achieve the correction. Can anybody give me some insight on this?


Last edited by jimy.pesin on Oct 21, 2008 - 02:49 PM; edited 1 time in total
 
 View user's profile Send private message  
Reply with quote Back to top
jimy.pesin
PostPosted: Sep 29, 2008 - 09:35 PM
Newbie


Joined: Aug 29, 2008
Posts: 3
Location: Long Island, NY

I still don't see the benefit to going to a phase corrected PWM and I don't agree that you get a shorter ON time with the phase corrected PWM. The only thing is that by decreasing your frequency you will have a wider range to work with, but the minimum pulse width will remain the same and the duty cycle percentage will appear smaller because you are comparing the minimum on time to a longer period. So it seems like phase correction can be done with the fast PWM and introducing a delay to achieve the correction. Can anybody give me some insight on this?
 
 View user's profile Send private message  
Reply with quote Back to top
GooDy88
PostPosted: Oct 21, 2008 - 01:41 PM
Newbie


Joined: Oct 21, 2008
Posts: 4


@new2atmel

I tried to understand your code, but what means DDRB |= (1<<DDB3); and ^=

Thx in advance
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Oct 21, 2008 - 01:44 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62321
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:
I tried to understand your code, but what means DDRB |= (1<<DDB3); and ^=

You need to read this ("101") tutorial thread first:

http://www.avrfreaks.net/index.php?name ... mp;t=37871

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
GooDy88
PostPosted: Oct 21, 2008 - 01:46 PM
Newbie


Joined: Oct 21, 2008
Posts: 4


Thx that makes sense I think Smile
 
 View user's profile Send private message  
Reply with quote Back to top
alwelch
PostPosted: Nov 09, 2008 - 03:45 PM
Resident


Joined: May 01, 2002
Posts: 846
Location: Texas

I would love to see an organized note on specific AVRs such as the mega128 with all the registers and code organized for timer use for all the modes. It could use a base clock of say 8Mhz and show PWM frequencies possible, etc.

Al Welch Smile
 
 View user's profile Send private message  
Reply with quote Back to top
jwcolby
PostPosted: Nov 10, 2008 - 01:42 PM
Wannabe


Joined: Sep 25, 2006
Posts: 51
Location: 28638

Dean (ABCMini),

Any chance of seeing the rest of this tutorial including some code. I have to say I love your "top down, fill in the pieces" style for tutorial writing.

I am trying to pick up the pieces and write an independent PWM motor control "module" so that I can have one or N motors. I am doing a project to control the motors on my son's ride on toy, where the lack of control causes burned up motors and stripped gears.

Thanks for the tutorial, I read the entire timer tutorial last night and other than the fact that I am still not fluent on the C bit operators it was an easy read which says a lot about your style.

Thanks,

_________________
JWColby
AVRNubee
www.ColbyConsulting.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Nov 11, 2008 - 09:39 AM
Moderator


Joined: Jan 23, 2004
Posts: 9828
Location: Trondheim, Norway

Quote:

Any chance of seeing the rest of this tutorial including some code. I have to say I love your "top down, fill in the pieces" style for tutorial writing.


Thanks! It's been a while since I wrote any tutorials, so I'll try to pick it up again. My personal projects are starting to slow down, which is unfortunate for me but should be to the benefit to others.

I'm currently in the middle of end-of-year University exams, so I won't be able to work on this just yet. My future depends on me knowing how to do series-series feedback analysis by tomorrow.

Quote:

Thanks for the tutorial, I read the entire timer tutorial last night and other than the fact that I am still not fluent on the C bit operators it was an easy read which says a lot about your style.


Always good to know what I write is readable. I'm not always certain; it's very difficult to think from a complete new user's perspective when writing tutorials, and not sink into the depths of assumed knowledge.


For the C bit operators, read EW's "Programming 101" tutorial in the tutorials forum.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
robodeepak
PostPosted: Nov 13, 2008 - 09:45 AM
Newbie


Joined: Nov 12, 2008
Posts: 3


can i get this code in ATmega8??????????
 
 View user's profile Send private message  
Reply with quote Back to top
jwcolby
PostPosted: Nov 13, 2008 - 02:44 PM
Wannabe


Joined: Sep 25, 2006
Posts: 51
Location: 28638

I am thinking you can. I am hoping to get an Atmega8 running just a single PWM channel, which I will mount on a PC board with the HBridge to control a single motor. Then link it via two wire or RS232 to a central controller that actually runs my app.

Unfortunately I am still struggling to find code that I can get working. The unfortunate part is that according to my dev notes I had PWM code controlling a motor a year and a half ago but I lost the hard drive. Embarassed

_________________
JWColby
AVRNubee
www.ColbyConsulting.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Nov 13, 2008 - 11:12 PM
Moderator


Joined: Jan 23, 2004
Posts: 9828
Location: Trondheim, Norway

Here is a simple ATMEGA16 (IIRC) example code. It's actually a DAC - digital audio in on Port D and PWM output for a speaker on the Timer 1 compare output.

Code:
#include <avr/io.h>

int main (void)
{
   // Speaker as output
   DDRB   |= (1 << 1);
   
   // DAC inputs as input, pullup
   PORTD  |= 0xFF;
   
   // Set on match, clear on TOP
   TCCR1A  = ((1 << COM1A1) | (1 << COM1A0));

   // Phase + Frequency Correct PWM, Fcpu speed
   TCCR1B  = ((1 << CS10) | (1 << WGM13));

   // TOP is 0xFF for 8-bit audio
   ICR1    = 0xFF;

   for (;;)
     OCR1A = ((int8_t)PIND + 0x7F);
}


Phase and Freq correct mode only, but should get you started.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
anti_dark
PostPosted: Nov 17, 2008 - 05:47 PM
Newbie


Joined: Nov 03, 2008
Posts: 11


thanx a lot for the tutorials on timer. was having great problems in beginning with timers and interrupt. ur tutorial was pretty easy and coool to begin with. thanx again. my best wishes for ur exams
 
 View user's profile Send private message  
Reply with quote Back to top
anti_dark
PostPosted: Nov 17, 2008 - 05:49 PM
Newbie


Joined: Nov 03, 2008
Posts: 11


thanx a lot for the tutorials on timer. was having great problems in beginning with timers and interrupt. ur tutorial was pretty easy and coool to begin with. thanx again. my best wishes for ur exams
 
 View user's profile Send private message  
Reply with quote Back to top
murder01
PostPosted: Nov 20, 2008 - 06:02 PM
Newbie


Joined: Sep 24, 2008
Posts: 12


Hi freaks,
First of all thank you Dean for making life so easy for newbies like me. Your tutorials are so simple and easy to follow. Hats off to you.
Coming to the problem, I am using atmega8 to design a robot. I have to use PWM to control two motors that control the two wheels of the robot. This is what I have done so far:
- Read your timer tutorial and PWM tutorial
- Read the missing part of PWM from Data Sheet
- Wrote a code to initalize PWM and test the motors
The code is as follows:
Code:

#include<avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>
#define Delay( x ) _delay_loop_2( x )

#define F_CPU 1000000UL


pwm_init()
{
     TCCR1A |= (1<< COM1A1) | (1<< COM1B1) | (1<< COM1A0) | (1<< COM1B0) | (1<< WGM10)| (1<< WGM11) ;// 10 bit PWM phase correct
     TCCR1B |= (1<< CS10); // no prescaling
     //TCCR1B |= (1<< CS10) | (1<< CS12) ;
     TCNT1 = 0x0000;
}

void pwm_set( int left_speed, int right_speed )
{
     OCR1A = left_speed;
     OCR1B = right_speed;
}
int main ()
{
   unsigned int i;
   DDRD = 0xff;
   PORTD = 0x00;
   DDRB = 0xff;

// PD0 and PD1 - right motor
// PD7 and PD6 - left motor
//  1       0 forward
//  1       1 brake (both outputs low)
//  0       1 reverse
//  0       0 coast (both outputs off =high impedance?)

     PORTB |= (1 << PB1) | (1 << PB2);
     PORTD |= (1 << PD7) | (0 << PD6) | (1 << PD0) | (0 << PD1);

pwm_init();
while(1)
{
for(i=1;i<256;i++)
{
pwm_set(i,i);
Delay(5000); //20000 cycles
}
for(i=255;i>0;i--)
{
pwm_set(i,i);
Delay(5000);
}
}
}


What I don't understand is:
- When does OC1A and OC1B gets set or clear? In this PWM mode the TOP value is 0x03FF. And I am putting values ranfing from 1 to 255 and 255 to 1 in OCR1A and OCR1B. According to me, this code should change the speed of the motors, first increase and then decrease, or vice versa.
- Also how do I set duty cycle? Why would I need it? Suppose I want to use the duty cycle of 50%, that means i put half the value of 0x03FF into OCR1A...is that right?
- I want my robot to turn 90 degrees. I think this should be done by stopping one motor and rotating the other one. But for how long should I rotate the other one so that it turns 90 degrees. As in how do I fix the time for which a particular motor runs?
-How does prescaling affect PWM? I saw that changing prescaler values made the code not run any more.
Please consider my questions. I might look ignorant to some of you. Also if this was the wrong place to post please let me know and I will post in AVR Forums. I just had to thank Dean, so I posted here.

Regards.
Sid
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   This topic is locked: you cannot edit posts or make replies.
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits