[TUT] [C] Newbie's Guide to AVR PWM (Incomplete)

119 posts / 0 new
Last post
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

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 :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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?)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simply beautiful, Dean. :D 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. :) )

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.

If you think education is expensive, try ignorance.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@new2atmel

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

Thx in advance

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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=PNphpBB2&file=viewtopic&t=37871

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thx that makes sense I think :)

Pages