100% Duty Cycle on PWM?

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Using following code wouldn't I get 100% duty cycle on PWM?

#include 
#include 
#include 
#include 

volatile bool TS;

int main()
{
static bool TF,TRF1;
volatile uint8_t value;

//Sets pin direction, PD6 Motor Drive, PB1 Motor Brake
DDRD |= 0x40;
DDRB |=	0x02;	

//Sets initial state of PD6 and PB1
PORTD &= ~0x40;	//Motor Drive off
PORTB &= ~0x02;	//Motor Brake off

//Enable Pull Up Resistors
PORTC |= 0x05;	//PC0(Gbx. Pos.),PC2(Trig.) 
PORTD |= 0xA0;	//PD5,PD7	
PORTB |= 0x05;	//PB0,PB2		

//Sets TC0 for Phase Correct PWM (opt. 5)
TCCR0A |= 0x01;
TCCR0B |= 0x08;
OCR0A = 0xFF; //255 (100% duty cycle)

	//Main Loop
	while(1){

		//Fire Gun when PINC2 is low
		if( TRF1 ){
			if( ((PINC&_BV(PINC2)) == 0) ){
			TCCR0A |= _BV(COM0A0);
			TCCR0B |= _BV(CS00);
			TRF1 = false;}
		}
		
	        //Stop Firing when PINC2 is high
		if( ((PINC&_BV(PINC2)) != 0) ){
			TCCR0B &= ~_BV(CS00);
			TCCR0A &= ~_BV(COM0A0);
			PORTD &= ~_BV(PIND6);
			TRF1 = true;
		}
		
	}//End Main Loop
		
}

Because when I tested this I could audibly hear the gearbox turning much slower than when I just turn PIND6 on and off directly without PWM. I want to be able to changed the duty cycle but also be able to have full power(100% duty cycle) as a setting. Perhaps I'm missing something.

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

Read the datasheet for the AVR you are using.
remember that a 8 bit PWM has 257 combinations so it can either not make 0% or 100% duty cycle.(if you need that you will need to make a special case where the output is normal IO's)

Jens

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

Test the signal by using an oscillocope or RMS multimeter in place of the motor. Also you can listen to the signal using a speaker, 0 and 100% should be completely quiet.

One of the two alternatives in main seems very busy, do it repeat too often?

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

If you want 0 to be full off and 255 to be full on then you need to reduce your PWM cycle from 0->255 to 0->254. You need to set your PWM TOP via a register to 254 instead of the default 255. Look in your datasheet to see how.

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

Quote:
remember that a 8 bit PWM has 257 combinations

Typo?

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

MattBucknall wrote:
Quote:
remember that a 8 bit PWM has 257 combinations

Typo?

Not really, but something that needs clarification. Imagine the case where you only have a 2-bit timer. If you want 0 to be full off, you can only get these values:

00: 0%
01: 25%
10: 50%
11: 75% (timer goes to 0 here)

No way to get 100%. But if you reduce the full-range PWM count by 1 (from 4 to 3 in this case), you can get the following values:

00: 0%
01: 33%
10: 67% (timer goes to 0 here)
11: 100% (the timer never reaches this value, so the output never switches)

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

@ kk6gm

I still don't understand how you get 257 combinations with 8-bit PWM. I count 256.

Matt.

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

0..256 where 256 is a special case where you disable the PWM and just set the output high. 0..256 is 257 combinations. 0-255 straight PWM codes and one special.

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

MattBucknall wrote:
@ kk6gm

I still don't understand how you get 257 combinations with 8-bit PWM. I count 256.

Matt.


Again using the 2-bit example, you will have 4 time slots in a cycle, right? And the PWM combinations of those 4 time slots can be any of the following:

0000
1000
1100
1110
1111

2 bits, 4 time slots, 5 (not 4) combinations from all OFF to all ON. In the same way, for any N-bit PWM there are 2^N+1 possible combinations.

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

Ah, okay. You mean possible combinations of mark/space ratios - not the number of combinations realized by an 8-bit PWM circuit (unless you also count disabling it).

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

I decided to check out the PWM behavior on a scope, and this is what I found. This is on an ATmega48P, Timer 0.

Fast PWM, OCR0A = 0: pulse 1 PWM clock wide
Fast PWM, OCR0A = 1: pulse 2 PWM clock wide
Fast PWM, OCR0A = 254: low pulse 1 PWM clock wide
Fast PWM, OCR0A = 255: output full on

P/C PWM, OCR0A = 0: output full off
P/C PWM, OCR0A = 1: pulse 2 PWM clock wide
P/C PWM, OCR0A = 254: low pulse 2 PWM clock wide
P/C PWM, OCR0A = 255: output full on

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

Quote:

I decided to check out the PWM behavior on a scope, and this is what I found. This is on an ATmega48P, Timer 0.

Fast PWM, OCR0A = 0: pulse 1 PWM clock wide
Fast PWM, OCR0A = 1: pulse 2 PWM clock wide
Fast PWM, OCR0A = 254: low pulse 1 PWM clock wide
Fast PWM, OCR0A = 255: output full on


Your results would be as expected.

In practice, this [not being able to reach both ends] usually isn't a killer. Let's look at your Fast PWM example, and let's say we are driving a motor, LED, lamp, or backlight. We'd really like OFF to mean OFF.

So then you use inverted PWM and complement the calculated OCR value. 0 now really means OFF. In the situations I mentioned, noone will be able to tell the difference between 254/255 and 255/255. But the motor might creep or the LED be dimly lit at 1/255 and hence the desire for 0/255.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch wrote:

Your results would be as expected.

In practice, this [not being able to reach both ends] usually isn't a killer. Let's look at your Fast PWM example, and let's say we are driving a motor, LED, lamp, or backlight. We'd really like OFF to mean OFF.

So then you use inverted PWM and complement the calculated OCR value. 0 now really means OFF. In the situations I mentioned, noone will be able to tell the difference between 254/255 and 255/255. But the motor might creep or the LED be dimly lit at 1/255 and hence the desire for 0/255.


I think it's unfortunate that in fast PWM a 0 value doesn't turn the output full off. If it did so then by using OCRA to set TOP you could easily get full off and full on in fast PWM as well as in p/c PWM. Oh well...

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

Quote:

I think it's unfortunate that in fast PWM a 0 value doesn't turn the output full off.

But you can use inverted PWM and get 255 = OFF. I don't know if there is anything "unfortunate" about it--if you try to get 257 states out of 256 values, one will be "missing". If the missing one is the full-off value, then use inverted PWM as I suggested. Or recognize the OFF condition, disconnect the pin, and clear the pin.

In politically-correct (or is that phase-correct?) PWM, you only get about half (of the possible 256/8-bits) of the states.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

But I am talking about getting 256 states out of 256 values, including full off and full on, by making TOP 254 instead of 255. It could have been done (I know of other families of PWM that do it) and it would have been a useful addition to AVR PWM capability. I don't lose sleep over it, but I do see it as an unfortunate design choice. Like I said, oh well...

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

You've lost me. Post the "truth table" as above using the 2-bit example and what you think should happen. Now assume a /1 prescaler. Aren't fractions of AVR clock cycles then needed?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Here's the desired outcome for a 2-bit system

000 (OCRB = 0)
100 (OCRB = 1)
110 (OCRB = 2)
111 (OCRB = 3)

There are only 3 time slots rather than 4 (OCRA set to 2, not 3).

I don't know what the internal HW would need to be to make this happen. Certainly keeping the output off on a 0 PWM value is not hard, just detect the 0 condition in the register and don't set the output high at the beginning of the cycle. As for the other values, yes, they need some kind of +1 lookahead or delaying the output by 1 clock or ???

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

volatile bool TS;

int main()
{
static bool TF,TRF1;
volatile uint8_t value;

//Sets pin direction, PD6 Motor Drive, PB1 Motor Brake
DDRD |= 0x40;
DDRB |=	0x02;	

//Sets initial state of PD6 and PB1
PORTD &= ~0x40;	//Motor Drive off
PORTB &= ~0x02;	//Motor Brake off

//Enable Pull Up Resistors
PORTC |= 0x05;	//PC0(Gbx. Pos.),PC2(Trig.) 
PORTD |= 0xA0;	//PD5,PD7	
PORTB |= 0x05;	//PB0,PB2

//Enable Global Interrupts and PCINT8
sei();				
PCICR  |= 0x02;		
PCMSK1 |= 0x01;			

//Sets TC0 for Phase Correct PWM on PIND6, Non-Inverted
TCCR0A |= 0x01;	//WGM00:Mode 5
TCCR0B |= 0x08;	//WGM02:Mode 5
OCR0A = 0xC0;

	//Main Loop
	while(1){

		//Fire Gun when PINC2 is low
		if( TRF1 ){
			if( ((PINC&_BV(PINC2)) == 0) ){
				TCCR0A |= _BV(COM0A1);
				TCCR0B |= _BV(CS00);
				TRF1 = false;}
		}

		//Stop Firing when PINC2 is high
		if( ((PINC&_BV(PINC2)) != 0) ){
			TCCR0B &= ~_BV(CS00);
			TCCR0A &= ~_BV(COM0A1);
			PORTD &= ~_BV(PIND6);
			TRF1 = true;
		}

		//Cycle counter
		if( TF != TS ){
			if( TS ){
				value++;
			}
		TF=TS;
		}
		
	}//End Main Loop
		
}

//Main Interrupt
ISR(PCINT1_vect)
{	
	//Reads PINC0 and sets TS True or False
	TS = ((PINC&_BV(PINC0)) != 0) ? true : false; 

}//End Main Interrupt

Again, on an ATMega88PA at 20Mhz. When using this code I tried adjusting the OCR0A value and yet I am not seeing an difference, it seems to be at 100% duty cycle, do I need to set the OCR0A value in the

		//Fire Gun when PINC2 is low
		if( TRF1 ){
			if( ((PINC&_BV(PINC2)) == 0) ){
				TCCR0A |= _BV(COM0A1);
				TCCR0B |= _BV(CS00);
				TRF1 = false;}
		}

segment? Frequency shouldn't matter as long as it is 255Hz or greater since I only have 8-bit resolution on TC0, so I just left it with a divider of 1 giving me almost 40kHz effective. Is there something else I need to do that is missing? I didn't find anything else in the data sheet.

And for 100% duty cycle:

Quote:
The extreme values for the OCR0A Register represent special cases when generating a PWM
waveform output in the phase correct PWM mode. If the OCR0A is set equal to BOTTOM, the
output will be continuously low and if set equal to MAX the output will be continuously high for
non-inverted PWM mode. For inverted PWM the output will have the opposite logic values.
Directly from the data sheet for the PA, so unless when they refer to output as something other than OC0A(aka PD6) and OC0B(PD5), then I should be able to hit 100% duty cycle without having to revert back to directly turning on and off PD6 by using
PORTD |= _BV(PIND6);

and

PORTD &= ~_BV(PIND6);

.

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

Quote:

When using this code I tried adjusting the OCR0A value and yet I am not seeing an difference, it seems to be at 100% duty cycle,

True enough. See the timing diargams. In that mode, the timer counts up to OCR0A and back down again. That is the TOP value.

You can't generate a PWM on OC0A in that mode. You can generate a PWM on OC0B.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.