Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve zero duty cycle PWM in AVR without glitches?

I'm trying to use hardware PWM on ATmega2560, using TC0 (an 8-bit timer), in Fast PWM mode. I need to dynamically adjust the duty cycle, and this includes zero duty cycle. However, this does not appear to be easy or even possible. Quoting the datasheet:

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, setting OCR0A to 0 (=BOTTOM) will not actually result in zero duty cycle, and my tests confirm this. Some other approach needs to be taken.

First, I've taught about using the OCR0A=MAX special case as described in the quote above. Combined with temporarily switching to inverted mode, this will result in zero duty cycle. However, since the COM0A1:0 bits are not double buffered (and not synchronized with OCR0A), this may result in a glitch in the output, if the mode is switched while the output is high (it will be left high until the next overflow). It does not appear to matter what order the OCR0A change and the mode change is done, both may glitch.

I've also considered another solution, to turn off the PWM by setting COM0A1:0=0. This will immediately set the output to the value in the PORT register, which would be zero. But there's still the problem of going back from zero output to a non-zero duty cycle. From what I read in the datasheet, setting COM0A1:0 to re-enable the PWM will immediately switch the output pin to the output of the PWM, which may be an incorrect value until the next compare match or timer overflow. Hence, a glitch.

Inverting the PWM overall may be applicable, but then the problem just becomes achieving full duty cycle, with symmetric issues.

Note that it is not possible to leave the PWM waveform generation enabled while forcing the output of the pin via PORT, as explained in the datasheet:

The Compare Output mode (COM0x1:0) bits have two functions. The Waveform Generator uses the COM0x1:0 bits for defining the Output Compare (OC0x) state at the next Compare Match. Also, the COM0x1:0 bits control the OC0x pin output source.

There is no way to let the PWM run for a cycle or so and switch to it when it's ready - enabling PWM immediately forces the pin output.

UPDATE. The phase-correct (center-aligned) PWM mode does not have this issue, and in my case is acceptable. I have tried it and confirmed that it works for both zero and full duty cycle.

like image 216
Ambroz Bizjak Avatar asked May 25 '14 07:05

Ambroz Bizjak


2 Answers

you have two options:

  1. if you use the fast pwm: you can use an inverted pwm. all you need to do is set the OC Pins to inverse mode and invert your pwm compare values. however - you now have glitches with 100% duty cycle

  2. use the phase correct pwm. draw back is that the maximum frequency is halved.

like image 112
vlad_tepesch Avatar answered Sep 28 '22 02:09

vlad_tepesch


I just came through the same issue, but needed to stick with a Fast PWM setting on a atmega2560.

The solution I found was to temporarily put the output pin to normal port operation (i.e. set the COMnX1 and COMnX1 bits of the TCCRnA register to zero when a zero duty cycle is needed :

TCCR1A &= (0<<COM1A1) & (0<<COM1A1);

like image 30
vince Avatar answered Sep 28 '22 02:09

vince