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

Last post
119 posts / 0 new

Pages

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

To answer your question, npat_avr, keep in mind that the timer counts up, *and then back down* in PWM modes (except for Fast PWM). So if COUNT is 1024, the total cycle is 2048 counts. In the example you give, you've divided the two into 2048 to get 1024, but the equation is still the same and still correct.

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

Very nice tutorial, but when you will complete this tutorial?

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

Hey, I have a question... I NEED 3 PWM for a time based thingy... I want to create a clock with LED's and I want the glow (for minutes/seconds/Hours) to be slowly changing for each LED
12 LED's for seconds, minutes, and hours each (36 total)

SO consider the first 2 second led's on the chain:
12:00:00 Led1: 100% Led2: 0%
12:00:01 Led1: 80% Led2: 20%
12:00:02 Led1: 60% Led2: 40%
etc.

I believe you have the idea.
Then minutes would go by the same idea however hours would go by increments of 16.67% every 10 minutes.

SO I would be multiplexing to just turn the LED's obviously, however I have no idea how to implement the PWM.... Ideas?
Do some of the larger atmega chips have more timers????

Edit - Oh, wait the ATmega328P has 6 PWM channels!!!! Thats exactly how many I needed! :P HAHAHA.

Ok, I think I can get this to work then.

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

The at90usb1287 has three timers at least, and the PWM megas (can't remember their part numbers) can do something like 6 channels at once.

However, PWM for LEDs isn't that critical to get absolutely perfect. Your best best is software PWM, which uses one fast tick timer and an array keeping track of the individual channel's CURRENT and TOP values. Each time the ISR fires, increment the CURRENT values for each channel, and if it matches the channel's TOP, you reset it back to zero and toggle the channel pin.

Via that method, you just set the channel's TOP array value to the desired frequency, and away you go - you can get many, many channels out of that without too much effort. The slightly wonky PWM frequencies from the conditional logic in the ISR won't be noticeable on a LED.

- Dean :twisted:

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

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

Can you make a MINI tut on THAT?

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

Twist, here's an example of what I'm talking about:

#define NUM_CHANNELS       2
#define PWM_CHANNEL_PORT   PORTD
#define PWM_CHANNEL_DDR    DDRD

uint16_t SoftPWM_TOP[NUM_CHANNELS];
uint16_t SoftPWM_COMPARE[NUM_CHANNELS];
uint16_t SoftPWM_CURRENT[NUM_CHANNELS];
uint8_t  SoftPWM_PinMasks[NUM_CHANNELS] = {(1 << 0), (1 << 1)};

void SetupPWMTimer(void);
void SetupPWMChannels(void);
void SetupPWMHardware(void);

int main (void)
{
	SetupPWMTimer();
	SetupPWMChannels();
	SetupPWMHardware();

	// Enable interrupts
	sei();

	// Loop forever, PWM taken care of via interrupt
	for (;;);
}

void SetupPWMTimer(void)
{
	// TODO: Set up timer 1 to fire the compare ISR every .1ms
}

void SetupPWMChannels(void)
{
	// Assuming .1ms timer granularity, set first software PWM channel to 100ms period
	SoftPWM_TOP[0] = 1000;

	// Assuming .1ms timer granularity, set second software PWM channel to 50ms period
	SoftPWM_TOP[1] = 500;
	
	// Set first PWM channel to 1/10 duty cycle
	SoftPWM_COMPARE[0] = (SoftPWM_TOP[0] / 10);

	// Set second PWM channel to 1/3 duty cycle
	SoftPWM_COMPARE[1] = (SoftPWM_TOP[1] / 3);
}

void SetupPWMHardware(void)
{
	for (uint8_t Channel = 0; Channel < NUM_CHANNELS; Channel++)
	{	
		// Set PWM channel as output
		PWM_CHANNEL_DDR  |= SoftPWM_PinMasks[Channel];

		// Start with channel ON
		PWM_CHANNEL_PORT |= SoftPWM_PinMasks[Channel];
	}	
}

ISR(TIM1_COMPARE_ISR)
{
	// Loop through each software PWM channel
	for (uint8_t Channel = 0; Channel < NUM_CHANNELS; Channel++)
	{
		// Increment each channel's CURRENT value
		SoftPWM_CURRENT[Channel]++;
		
		// When a channel's CURRENT reaches its COMPARE, clear its output
		if (SoftPWM_CURRENT[Channel] == SoftPWM_COMPARE[Channel])
		{
			PWM_CHANNEL_PORT &= ~SoftPWM_PinMasks[Channel];
		}

		// When a channel's CURRENT reaches its TOP, reset it and set its output
		if (SoftPWM_CURRENT[Channel] == SoftPWM_TOP[Channel])
		{
			PWM_CHANNEL_PORT |= SoftPWM_PinMasks[Channel];
			
			SoftPWM_CURRENT[Channel] = 0;
		}
	}
}

Note that you have to set up timer 1 to your desired PWM resolution according to the CTC chapter of my Timers tutorial.

Basically, once you've set up your timer's resolution, you then set each software channel's COMPARE and TOP values to the desired multiple of this resolution -- for example, if your timer interrupts every 1ms, the timer TOP and COMPARE values are in multiples of 1ms.

Each timer the timer interrupts it increments each channel's CURRENT value. If the CURRENT value reaches the channel's COMPARE value, it clears the output. If the CURRENT value reaches TOP, it resets CURRENT and sets the output. This way each channel gets its own frequency (set by TOP) and duty cycle (set by COMPARE).

- Dean :twisted:

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

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

Also, to add to what I've written above, note that by increasing the timer resolution (i.e. making it interrupt more times a second) you have finer control over the PWM channels, but at the expense of more CPU usage. The more channels you add will also increase the CPU usage -- although if you want a single frequency for all channels and just want to change each channel's duty cycle, you can use a single TOP value for all channels.

I haven't looked at the assembly output for this, but it might be the case that you can optimise it by making each channel a struct containing its TOP, COMPARE, CURRENT and Pin Mask values so that it can use indirect-lookup-with-offset instructions.

- Dean :twisted:

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

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

G'day everyone,

Dean u r a champion. Just a quick question. I'm trying to use fast PWM for switching a MOSFET. I'm using an ATMEGA128 and I want the switching frequency to be 50 KHZ. I'm unsure on how to set this up, any help or pointers in the right direction would be hugely appreciated.

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

alectravelyan,

In fast PWM, your choice of frequency is very limited, as TOP is fixed to be either 8, 9 or 10 bits long (depending on the AVR model and timer used). Each time the timer reaches TOP, it is reset back to zero, thus TOP sets the PWM frequency.

When in Fast PWM mode, you can only change the TOP value by specifying the number of bits you want, and by using the timer's prescaler to prescale the input clock frequency. If you specify your AVR's clock frequency, I can give you the settings which would get you closest to 50KHz.

Fast PWM is not designed to give you perfect frequency you desire, it's really only designed to give you control over the duty cycle only.

The other alternative would be to use the other PWM modes which give control over both TOP and COMPARE -- at 50KHz, I suspect this might give you better results with a fast enough AVR master clock.

- Dean :twisted:

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

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

Ahh no! The tutorial is not finished! That is such a shame.

The timer tutorial was absloutely incredible and I was hoping I be able to learn PWM in the same manner. sigh...

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

Hey guys,
N00b here. First thanks for the help Dean. Loved the tuts, but ya left me feeling like I was dating in middle school again. jk. (Only on the PWM, though)

However, I did find a good example. That I was able to understand. Needed a lil reformatting for all of us to understand.

So here is the pwm code. I can't take credit for it's generation. Check the Beer-ware license for that info. I did however edit it into one file, and note the freakin hell out of it.

This works perfectly on my tiny2313. If you get the original from the website, and get the iocompat.h it should work for any of the differences for your MCU. I find that making those changes helps me understand it better though.

#include 
#include 
#include 

enum { UP, DOWN };


int main (void)
{

    /* Timer 1 is 10-bit PWM (8-bit PWM on some ATtinys). 
		Setting WGM10 & WGM11 only will give phase correct PWM
		Setting WGM12 also will give fast PWM, but that's on TCCR1B
		COM1A1 = Clear OC1A on match when upcounting-Set OC1A
					when downcounting on match
	*/
    TCCR1A |= ((1<<WGM10)|(1<<WGM11)|(1<<COM1A1));
	/* Clock Selects are for prescallers
		Current CS10 is for clock without prescalling
		Prescaler    8 = (1<<CS11)
		Prescaler   64 = ((1<<CS11)|(1<<CS10))
		Prescaler  256 = (1<<CS12)
		Prescaler 1024 = ((1<<CS12)|(1<<CS10))
	*/
    TCCR1B |= ((1<<WGM12)|(1<<CS10));

    // Set Timer1/PWM register value to 0.
    OCR1A = 0;

    /* Enable OC1A or PB3 as output. 
		Not sure why but only works with this pin
	*/
    DDRB = (1<<3);

    // Enable timer1 overflow interrupt.
    TIMSK = (1<<TOIE1);

    sei ();

    // loop forever, the interrupts are doing the rest
    for (;;)                    
        sleep_mode();

    return (0);
}

ISR (TIMER1_OVF_vect) 
{
    static uint16_t pwm;		//pwm counter var
    static uint8_t direction;	//enum var

	/*
	For those who are wondering by ++pwm, it's actually
		incrementing or decrementing everytime through the switch
		However, it does that before comparing to min or max
	*/
    switch (direction)          
    {
        case UP:	//increment counter and check against Max-1
            if (++pwm == 1023)
				//start the counting other direction
                direction = DOWN;
            break;

        case DOWN:	//decrement counter and check against min
            if (--pwm == 0)
				//start counting in other direction
                direction = UP;
            break;
    }
	//set the calc'd value to Timer1 output register
    OCR1A = pwm; 
}



/*
 * Obtained from http://www.nongnu.org/avr-libc/user-manual/group__demo__project.html
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 43):
 *  wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
 * Hey I wanna beer too ;) Actually jack & coke or a smoke, but same deal: Bart Robinson
 * ----------------------------------------------------------------------------
 *
 * Simple AVR demonstration.  Controls a LED that can be directly
 * connected from OC1/OC1A to GND.  The brightness of the LED is
 * controlled with the PWM.  After each period of the PWM, the PWM
 * value is either incremented or decremented, that's all.
 *
 * $Id: group__demo__project.html,v 1.1.1.18 2009/03/05 20:35:12 joerg_wunsch Exp $
 */

Enjoy :-p :twisted:

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

Quote:

    /* Enable OC1A or PB3 as output.
      Not sure why but only works with this pin
   */
    DDRB = (1<<3);

There is no provision to select which pins outputs the PWM channels of the timer. It is hard-wired in the chip. Thus Timer/Counter1's channel A always has it's output on PB3.

On some other microcontrollers you can "route" peripheral outputs to different pins, but not so on AVRs.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington]

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

Johan,
I really appreciate that answer. I've been banging my head against the monitor for a couple(a lot more, but I'll pretend) hours.
Now to figure out another way to do a multi-channel PWM.

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

Quote:

a multi-channel PWM

How many channels?

Most AVRs have several Timer/Counters each being capable of driving two PWM channels. The tiny2313 has the eight bit Timer/Counter0 with two PWM channels, and the sixteen bit Timer/Counter1 also with two PWM channels, making for a total of four PWM channels. While the frequency must be the same for the two channels within each T/C the duty cycle is independently set for each channel.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington]

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

I hadn't thought about it before but I keep posting this code segment to other threads and maybe this is the appropriate place for it. What it shows is how to do PWM on an arbitrary pin by doing "soft PWM" but with timer interrupts. It works by starting a timer to have both overflow (PWM frequency) and compare (duty cycle) interrupts. In this case I wanted to vary a pulse width on PC0 using the fastest PWM frequency I could get (so timer 0 counting 256 with no prescaler) and OCR0 can be varied from 0x00 to 0xFF to vary the duty cycle:

// The following two ISRs are doing "poor man's PWM" 
//  but this allows it to be on a pin of my choice
ISR(TIMER0_COMP_vect) {
        // clear the output pin on OCR0 match
	PORTC &= ~(1<<PC0);
}
ISR(TIMER0_OVF_vect) {
        // set the output pin at timer overflow
	PORTC |= (1<<PC0);
}

int main(void) {

	// going to use PORTC.0 to PWM the contrast voltage
	DDRC = (1<<DDC0);
	TIMSK |= ((1<<OCIE0) | (1<<TOIE0)); // use both interrupts
	OCR0 = 10; // 10 out of 256 means very short on period (low voltage)
	TCCR0 = (1<<CS00); // timer on - nice high PWM frequency

	// Might later consider PWMing the backlight voltage too
	// so it would also be adjustable ...
	sei();

this is just a code "snippet" for GCC, not a complete program.

The application was actually to vary the pin 3 (contrast) voltage of an HD44780 LCD module. As the comments say it would be possible to vary the backlight voltage in a similar way.

The way this example works is that it runs an 8bit timer with no prescale so every 256 clock cycles it will overflow and cause an OVF interrupt. At this point the output is turned on. The counter then starts to count up 0, 1, 2, 3,... and I have set the OCR0 register to 10 so when it counts up to 10 and TCNT0==OCR0 it will trigger the COMP(are) interrupt. At this point I switch the output off. So in a complete period of 256 counts the output is on for 10 and off for 246. So the output is only "on" for about 4% of the time. As the output pin is switching between 0V and 5V then it'll be like a voltage that is just 4% of this will be produced by the output pin (after a bit of RC filtering). So it's 4% * 5V = 0.19V

In my example I don't vary OCR so the output voltage is always at this level. But say I now set OCR to 211 (out of 256) then the output signal will be on for 211 clocks and off for 256-211=45 clocks. Because of this the output will appear to be 211/256 * 5V = 4.12V (and so on).

Cliff

 

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

Actually 3 timers proved to be enough, but I wound up doing something close to what clawson just posted.
lol, wish I had seen that lastnight.

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

Ok I tried the code from Joerg above and it worked. The LED is dimming perfectly (Thanks, Joerg!!).

Now I am trying to understand what the waveform of the LED current would look like? I understand the average DC value is changing for every cycle but can anyone help me with a waveform picture? I have 8MHz as my clock with no prescalar. The rest of the code is exactly identical to Joerg's code above. Thanks.

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

Dean,thanks for the wonderful tutorial.Can you give some example codes for the PWM section like in previous cases and complete this section whenever possible.

Regards,
Peter

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

Thank you so much Dean for all that effort of explaining the intro of PWM to newbie like me. It was very easy to visualize how PWM works after reading this article. So, when's the remaining tutorial coming?

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

I've been saying this for a very long time now, but "as soon as I get the chance". I've got a heck of a lot of University on at the moment, but that'll be ending for the year in a little more than a month.

IIRC, another user wrote his own PWM tutorial here, which was complete - that might be helpful in the interim.

- Dean :twisted:

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

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

can't wait until this tutorial is finished, i have look through many tutorials explaining PWM and Timers on the AVRs and they are all incomprehensible. This will make life a bit easier for all new AVR users :)

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

Hi Dean,

It is very long long time since you posted this "incomplete" tutorial on PWM. When can you finish this tutorial, really like your tutorial and the way you present your idea. You are a superb lecturer! Pls finish the tutorial, there are thousands of ppl waiting for your PWM tutorial!

cs

I'm happy ytd, today, and tmr :)

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

Hi,

I do intend on finishing it soon (after exams, in two weeks), but it's been very low on my priority list as I think it would be largely redundant now. There are two other complete PWM tutorials posted here now:

http://aquaticus.info/pwm

And:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=76406

Which means any effort I make will just add to the noise and cover already covered ground.

- Dean :twisted:

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

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

Good tutorial, any ideas?
I have a potentiometer to adjust with the ADC the value of the frequency of the pwm but I want to put another pot to adjust the duty cycle, using the 16 bits with the OCR and ICR.
I'm using the assembly code, any ideas on how to do it?

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

Use one of the WGM modes where ICR1 is "TOP". That is used to vary the PWM frequncy then OCR1 is used to vary the duty cycle.

 

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

I'm using that, but the duty cycle is like a porcentage. I have 10 bits of the ADC for the duty cycle. 1024 would be 100% duty cycle but depending of the frequency of the another pot that are adjusting it that is also 10 bits. I know I have to do some conversions, I can add and multiply, I have the code in Assembly. Any Ideas to adjust the duty cycle. Thank you

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
duty = top * value / 1024;

Regards,
Steve A.

The Board helps those that help themselves.

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

Dean, by chance if you read this. Could you help me out?

I'm trying to get 16 bit PWM modulation to work. Here is my code, it doesn't seem to be working



DDRB   = (1 << 3 ) | ( 1 << 2) | (1 << 1); 

TCCR1A |= (1 << COM1A1) | ( 1 << COM1B1 ) ; //set both to non inverting mode
TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM13) | (1 << WGM12) ;
ICR1 = 65535;

OCR1A = 60000;
OCR1B = 60000;


But it doesn't seem to be working. I also tried


OCR1AH = 60000 >> 8;
OCR1AL = 60000;

I'm just trying to get an output on ports OCR1A and OCR1B. For the 8 bit pwm channel, this always worked fine and was easy. Just had to set OCR2 = X and that would be it. But it doesn't seem to work as easily for 16 PWM.

Any ideas?

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

Please do not cross post. This is already being discussed here.

Regards,
Steve A.

The Board helps those that help themselves.

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

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

Thank you very much for this help. I am writing a program to control my servo using the PWM on the ATmega1280 (Arduino Mega).
I tried to understand the code and write a similar program but I failed. Here is the code I am using:

void pwm_r()
{
	OCR1A = 2000;
}

void pwm_l()
{
	OCR1A = 1000;
} 
   

void pwm_c()
{
	OCR1A = 1500;    
}  


void init_pwm()
{
	DDRB |= (1<<DDB3);

	//initialization of timer 1 and the frequency (50Hz)

	ICR1 = 20000;

	TCCR1A  = ((1 << COM1A1) | (1 << COM1B1) | (1 << WGM11) | (0 << WGM10)); 

	TCCR1A = ((1 << COM1A1) | (1 << COM1B1)); 
	TCCR1B = ((1 << CS10) | (1 << CS11) | (1 << WGM13));
	ICR1 = 0xFF; 
	TCCR1B = ((1 << CS10) | (1 << CS11) | (1 << WGM13) | (1 << WGM12)); 

}

I then call pwm_l, pwm_c, and pwm_r in main. The purposes of the functions are to turn the servo counter-clockwise, position it to center, and clockwise respectively. When I download the program, it only turns the servo clockwise.

What can I do to actually have the servo turn clockwise, counter-clockwise, and position it in the middle position??
Thanks a lot for the help.

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

Quote:

When I download the program, it only turns the servo clockwise.

Why are you seting TCCR1B and ICR1 twice? Only the second setting of each will work yet the OCR1=1000,1500,2000 with ICR1=20000 values sound like they are the ones you probably want to use (assuming F_CPU with the CS?? combination give th right tick rate)

 

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

Any Plans to Finish this tutorial ?

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

Hi
I am trying to use Atmega16 to turn on/off a MOSFET. I don't really want to generate a PWM. My goal is that when the voltage at a specific point of the circuit is equal or greater than 5V, the MOSFET will turn on, otherwise the MOSFET will turn off.
I appreciate any hints or tutorial from all of you.
Thank you very much.

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

Quote:

I appreciate any hints or tutorial from all of you.

You hijacked thew wrong tutorial. You wanted the one about Analog to Digital Conversion. Your program would basically be:

while(1) {
  take_AC_reading()
  if (reading >= threshold) {
   set IO to turn MOSFET on
  }
  else {
   clear IO to turn MOSFET off
  }
 }
}

 

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

What i ahve understood so far from this tutorial is as follows please let me know if i am correct
TOP=OCRxx BOTTOM=TCNTx
for a PWM wave set the timer in the PWM mode first
then for say 75% duty cycle i.e. we need a count of 192/255 means OCRxx=0xC0 and TCNTx=0xFF.
now since TOP is set at 255 count and if the frequency of the CPU is say 16 Mhz then then total Time period of the wave will be 255/16Mhz=16Microsecs of which 12 microsecs is the ON period.Now this time period can be easily modified by using prescalar values.
Am i correct ?? please let me know.
but i will get the 25% off period only if i use the Toggle mode isnt it ?

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

Quote:
i am correct

TOP=OCRxx - this depends on what mode you are in, but in the example you gave, OCRxx is the duty cycle, not TOP

BOTTOM=TCNTx - No, never. TCNTx is the current value of the timer. BOTTOM is always 0.

then for say 75% duty cycle i.e. we need a count of 192/255 means OCRxx=0xC0 and TCNTx=0xFF. - OCRxx is correct, assuming that you have selected a mode where TOP is 255. Again, no need to set TCNTx.

255/16Mhz=16Microsecs of which 12 microsecs is the ON period. - Yes, except that it is really 256/16MHz.

Now this time period can be easily modified by using prescalar values. - Yes, but you can also vary this by changing what TOP is set to.

but i will get the 25% off period only if i use the Toggle mode isnt it ? - Incorrect. You need the "clear on compare, set on TOP" mode.

Regards,
Steve A.

The Board helps those that help themselves.

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

How to change the TOP value ???
is there a clear on compare and set on top mode..???

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

ohh yea i got the Clear and Set modes but how to change the TOP value ??
for example if i am using a 16 bit Timer.. i will have to give a huge count for a duty cycle of 75% as my top value will be oxffff

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

Quote:

How to change the TOP value ???

Pick a PWM mode from the WGM table in which the TOP column includes the name of a register rather than a fixed value.

 

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

Such a shame that this tutorial is incomplete! When I search for tutorials, I specifically look to see if you have written one first.

Still, what you have posted so far is very helpful. Thanks!

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

tabshizzle,

Did you also see:

PWM AVR Tutorial
and
PWM for complete idiots

 

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

Yes I did, those tutorials were helpful. Thanks clawson.

And while they are good tutorials, for some reason, I just prefer abcminiuser's style.

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

hi Dean, This is very useful material, espcially for beginners. THANKZ,

I hope you can make a PDF for it, I would like to save it for further use.

thankz again,

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

A very useful material indeed.

Thanks for sharing.

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

I can't grasp the difference between phase correct PWM and fast PWM.
I see that you consider the time periods to start at different moments, but that is not relevant to the circuit, is it? In both cases it sees some evenly spaced duty cicles.

And second: why 8-9-10 bit PWM and not 16bit PWM? Timer1 is 2 bytes long, it can count on 16 bits, but the PWM will be 10 bits because ......................

?

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

Quote:

In both cases it sees some evenly spaced duty cicles.

Depends on what you mean by "evenly". Lets consider a simplified case where the counter counts to 4 (ie 5 steps before it wraps. Lets look at 20% and 60% duty cycle they would be like below for fast PWM

20%: 10000100001000010000...
60%: 11100111001110011100...

but for phase correct PWM they would be

20%: 00100001000010000100...
60%: 01110011100111001110...

Now, finally, to hopefully make the difference obvious lets look at two syscles of 20% and two cycles of 60% for both fast PWM and phase correct PWM

fast PM           10000100001110011100
phase correct PWM 00100001000111001110

Now, lets align the 20% on-parts with each other

fast PM           ..10000100001110011100
phase correct PWM 00100001000111001110..
                    ^    ^    ^    ^

and notice how the 60% on-parts are not matching.

Phase correct PWM is about centring the on-part around a specific, iterating, point in time (which I have marked above with ^). (Fast PWM starts its on-parts at those points).

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington]

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

Here's a tip. If you want to know how something looks different then type "phase correct PWM" into Google's image search. You'll get a number of results including this one:

(rather ironically that URL says that is hosted on fourwalledcubicle.com (Dean's site) and appears on Freaks in a Timer tutorial)

EDIT irony upon irony, that picture is in the first post of this very thread - so exactly what don't you understand about it now? Surely that shows exactly how fast/phase-correct differ - with phase correct having the pulse centred in the time frame.

 

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

I guess the question 'chooglin' might ask now is: Why do you need it?

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington]

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

I do understand that P.C. PWM means the cycles are centered on specific points in time.
OK, the theory is solid, but the motors see this in both cases:
pulse at t.... pulse at t+T.... pulse at t+2T

Can you explain (without unwitty irony) the physical phenomenon why the centering of impulses at equal time intervals works for motors and the lack of centering doesn't?

Attachment(s): 

Pages

Topic locked