Anyone know how to make output of pwm timer0 low?

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

I have a running pwm on timer0 at a tiny 45.
Now at the minimum pwm, the output still gives a pulse with a very low duty cycle. I would like to have the pin constant low instead of this pulsating pin.
I'm using mode 7 (fast pwm with TOP=OCRA).

I 'solved' it by using

TCCR0B = 0;									// Stop clock. i.e. output is then low
PORTB |= (0<<PB1); // force low

but sometimes it does not work and the output is latched to high. Clearly it is not a real solution.

Anyone an idea?

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

Quote:

Now at the minimum pwm, the output still gives a pulse with a very low duty cycle.

Yep, AVRs do that. I think there is a mention in the datasheet on that. I thought the new models had that changed, but apparently not.

IIRC you can dodge the issue by using inverted instead of normal PWM, and invert your duty cycle value. And/or, stop the timer, disconnect the pin, and set it low when doing 0.

Lee

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

That's the disadvantage (or the price we have to pay) for FastPWM. Encountered the same issue this afternoon on a Tiny2313 that uses FastPWM on Timer0. I may solve this by moving to the 16-bit timer1. Phase&Frequency Correct PWM may do the job. But for the Tiny45 such a solution isn't available. Poor you ...

Nard

edit: speedy Lee :)

A GIF is worth a thousend words   They are called Rosa, Sylvia, Tessa and Tina, You can find them https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

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

Thanks guys,

I could not find any refs in the data sheets to this phenomenon. What about timer1 or Phase&Frequency Correct PWM? Why would that be different?

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

Plons wrote:
That's the disadvantage (or the price we have to pay) for FastPWM. Encountered the same issue this afternoon on a Tiny2313 that uses FastPWM on Timer0. I may solve this by moving to the 16-bit timer1. Phase&Frequency Correct PWM may do the job. But for the Tiny45 such a solution isn't available. Poor you ...

Don't count on it... I've found the glitch at the OCRx to be on all of the timers. Fortunately for me, when driving a motor, it's pretty much insignificant.

Of course, you could always check OCRx for zero, and force the output to a high or low as needed.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

The short answer is: the 16-bit Timer1 has more features than the 8bit Timer0.
I stumbled earlier over this and solved it (IIRC) with Phase&Frequency Correct PWM. So I will re-write that part and see prove if the braincells are still intact.

Edit: you may be right Carl :) But I will give it a try anyway. My current little project is using the interrupts of OCR0A and B to do stuff. But I saw that very same glitch on the scope.

A GIF is worth a thousend words   They are called Rosa, Sylvia, Tessa and Tina, You can find them https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

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

I tried to stop the clock and forcing it to be output low. See code in first post. Sometimes I see this latch glitch.
Would it be possible to use the overriding signals (mentioned in i/o ports of datasheet, table 10-2: Generic Description of Overriding Signals for Alternate Functions). I've got no idea on how to use them. Perhaps someone could elaborate on this?

Plons, I hope you solve it. It would be nice if you could report about it. Right now I've got some soldering to do....

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

Quote:

I could not find any refs in the data sheets to this phenomenon.

Try to find this (from Mega88):
Quote:
The extreme values for the OCR0A Register represents special cases when generating a PWM waveform output in the fast PWM mode. If the OCR0A is set equal to BOTTOM, the output will be a narrow spike for each MAX+1 timer clock cycle. Setting the OCR0A equal to MAX will result in a constantly high or low output (depending on the polarity of the output set by the COM0A1:0 bits.)

So, like I said, you can dodge it by having inverted output and invert your duty-cycle value. But then you may get 255/256 high. Try it and see.

Lee

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

Nick, just as a quick hint: overriding the timer-function: make sure to clear COM0A1, COM0A0, COM0B1, and COM0B0 in TCCR0A. If PortB.0 and PortB.1 are clear, you should get the firm NULL ;)

A GIF is worth a thousend words   They are called Rosa, Sylvia, Tessa and Tina, You can find them https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

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

Plons, thanks, I think I did not set the com0xN bits.

Lee, thanks, It is in the tiny45 datasheet as well, only a bit different. And this could be an error in the datasheet or I interpret the datasheet completely wrong:

from datasheet (tiny45) pp78:

Quote:

The extreme values for the OCR0A Register represents special cases when generating a PWM
waveform output in the fast PWM mode. If the OCR0A is set equal to BOTTOM, the output will
be a narrow spike for each MAX+1 timer clock cycle. Setting the OCR0A equal to MAX will result
in a constantly high or low output (depending on the polarity of the output set by the COM0A1:0
bits.)

The error of the datasheet might be that OCR0B is used for the duty cycle. OCR0A and TCCR0B are used for the frequency. The physical pwm output is OC0B, PB1, pin 6.

Anyway, I think I've got it solved.

datasheet tiny45, pp76

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.

So I changed the COM0B0:1 to

init:
TCCR0A |=  ((1<<COM0B1) | (0<<COM0B0)); 	// output on OC0B

pwm low: 	OCR0B = 0;

Now, the pwm is inverted, but I get a constant low when OCRB=0. Works as written only in mode 5 (pwm, phase correct. Not in mode 7, fast pwm). Good. Ready to implement my hardware (soldering iron is still hot)

Oh, btw I never could get any output on OC0A (PB0, pin5) when using mode 5 or 7 (table 11-5). Perhaps the quotes above are not relevant to these modes?

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

Good work, Nick.

I modified my program to use Timer1 in Phase&FreqCorrectPWM: what a mess :)
Anyway, .... I used it on a Nixie-readout, and there I found this in the comments of the program:

'Timer0: fast pwm, inverted compare , top=oc0a, output oc0b
'WATCH OUT: if ocr0a=200 then
'if ocr0b=0: MAX dutycycle ( 99.5% )
'if ocr0b=20: 90% dutycycle
'if ocr0b=160: 20% dutycycle
'if ocr0b=200: oc0b=LOW and stays LOW

I used it there to generate the HV for the Nixies.
So the same finding. And corresponding with Lee's advice: 10 points :!: And bonus

Cheers

Nard

A GIF is worth a thousend words   They are called Rosa, Sylvia, Tessa and Tina, You can find them https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

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

Quote:
Oh, btw I never could get any output on OC0A (PB0, pin5) when using mode 5 or 7 (table 11-5). Perhaps the quotes above are not relevant to these modes?
I think the reason for no output, is this note in the datasheet(fast pwm, table 11-3)-
Quote:
A special case occurs when OCR0A or OCR0B equals TOP and COM0A1/COM0B1 is set. In
this case, the compare match is ignored, but the set or clear is done at BOTTOM.
in other words, there is no compare match taking place, but the pin is 'reset' to high/low at BOTTOM. Since OCR0A defines the TOP in mode 7, it will never produce a compare match and the pin status will only be determined by COM0A1:0 (and DDRB/PORTB if COM0A disconnected). This seems to explain why the 'TOP' end produces no spike (no compare match took place), where the 'BOTTOM' end you get the spike because you get the pin 'reset' AND get a compare match.

Although you already solved your problem, another option (I think) would be to simply 'disconnect' the OC0B register by clearing COM0B1 whenever OCR0B is 0, else set COM0B1 (with PB1 'preset' to 0 so output will be low when disconnected).

I must admit I'm getting confused, though, as the last 'solution' shows non-inverting mode

TCCR0A |=  ((1<<COM0B1) | (0<<COM0B0));    // output on OC0B

but is described as inverting (I confuse easily).

Also, the original post-

PORTB |= (0<<PB1); // force low

is the same as PORTB = PORTB | 0, which does nothing. If you wanted to clear a bit, PORTB &= ~(1<<PB1).

edit-

I now see the OP is in mode 5, which explains why no spike when 0CR0B is 0 and COM0B1:0 is 1:0, since the datasheet says it will be continuously low when OCR0x is set to BOTTOM (although it does not say it anywhere, maybe this is like the fast pwm mode and there is no compare match taking place at BOTTOM).

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

Curt,

Thanks,

yes you are right when talking about the inverting. Is a bit confusing. I use the non inverting mode:

TCCR0A |=  ((1<<COM0B1) | (0<<COM0B0));    // output on OC0B 

As you wrote, the assignment |(0<<COM0B0) is not correct to clear the bit. How can I rewrite this?

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

I was referring to clearing a pin on PORTB, so in that case-

Quote:
If you wanted to clear a bit, PORTB &= ~(1<<PB1).
but what you are referring to is a little different.

//case 1
TCCR0A |= ((1<<COM0B1)|(0<<COM0B0));
//case 2
TCCR0A |=  (1<<COM0B1);
//case 3
TCCR0A =  ((1<<COM0B1)|(0<<COM0B0)|(1<<WGM00)|(1<<WGM01));
//case 4
TCCR0A =  ((1<<COM0B1)|(1<<WGM00)|(1<<WGM01));

case 1 is misleading as COM0B0 will not change, case 2 is correct, case 3 is ok, and not misleading as it does show what COM0B0 will be even though not needed. Case 4 is what I would do.

I'm not sure why you need a pwm mode that uses OCR0A as TOP, but if you don't, you could get the use of OC0A as another pwm output by using mode 3 (or 1).

I'm also not sure if you understood the suggestion by others to 'invert'. What they are suggesting is to use 'inverted' mode on COM0B1:0 (fast pwm), along with 'inverting' your OCR0B values (OCR0B=0=full on,OCR0B>=OCR0A=full off). You won't get a high spike because a compare match never occurs at TOP (but I think you will still end up with a low spike when OCR0B=0).

To eliminate the 'spike', what I was suggesting (and have not tried it), was to simply set or clear COM0B1 wherever you are changing OCR0B. Assuming COM0B1:0 is already set to 1:0 (non-inverting mode, with a fast pwm timer mode), and PORTB1 is 0 (which it will be unless you change it somewhere), something like-

//assuming timer mode 7
//non-inverting output
//when changing OCR0B, do something like
if(OCR0B){
    //not 0, let OC0B do the output
    TCCR0A |= (1<<COM0B1);
}
else{
    //is 0, turn off OC0B output
    //let PORTB do the work
    TCCR0A &= ~(1<<COM0B1);
}

may prevent the high spike. Maybe.

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

Thanks Curt,

Is there a way to set and clear bit simultaneously in one C line?

What I use now is the following (syntax is not correct at the moment, see discussion above - but it works)


TCCR0A =  ((1<<COM0B1) | (0<<COM0B0)); 	// output on OC0B
   
//mode 5, pwm phase correct, TOP = OCRA (table 11-5 /pp 82)   
   TCCR0A |= ((0<<WGM01) | (1<<WGM00)); 
   TCCR0B  = ((1<<WGM02) | (0 << FOC0A) | (0 << FOC0B)) ;                


I do not get a high spike. I do get a low spike which is not a problem since I use this pwm to drive a dc/dc converter.
One reason why I do use the OCR0B for the duty cycle (zero to OCR0A) and have a fixed OCR0A is that I like a particular frequency for the pwm. This has something to do with filtering EMC noise. What I do not like about this setup is that I have a small amount of integral pwm settings (amount of ACR0A). Perhaps I should use another avr chip with a 16bits pwm. Actually I need 3 pwm timers to drive several converters. Perhaps a software solution is in this case better, but I like the hardware solution because then the avr can be used for other things as well.

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

Quote:
Is there a way to set and clear bit simultaneously in one C line?
It can be done with 1 line of C, but 1 line of C is not always better than 2 lines of C.

If I didn't know what TCCR0A contained (you should know in this case, as you are the only one changing these bits), but needed a bit cleared and another set-

TCCR0A = (TCCR0A | (1<<COM0B1)) & ~(1<<COM0B0);

But in your case, you know what you want all bits in TCCR0A to be, so just take care of it one time-

TCCR0A = (1<<COM0B1)|(1<<WGM00);

Also, just skip using (0<<SOMEREG), it will just cause you confusion.

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

Remember that once you disconnect the pin (and optionally stop the timer) you need to set the output pin low unless you know what part of the cycle it is in.

And why can't the invert method be used that is 0 lines of C?

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.