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

I am trying to use hardware PWM on an ATmega2560 using TC0 (8-bit timer) in fast PWM mode. I need to dynamically adjust the duty cycle, and this includes a zero duty cycle. However, this does not seem simple or even possible. Quoting the table:

The extreme values ​​for the OCR0A register are special cases when generating a PWM output signal in fast PWM mode. If OCR0A is set to BOTTOM, the output will be a narrow spike for each MAX + 1 clock timer. Setting OCR0A to MAX will result in a constant or low output (depending on the polarity of the output set with COM0A1: 0 bits).

So, setting OCR0A to 0 (= BOTTOM) will not actually result in a zero fill cycle, and my tests confirm this. A different approach needs to be used.

First, I taught to use the special case OCR0A = MAX, as described in the above quote. In combination with a temporary switch to inverted mode, this will lead to a zero filling cycle. However, since the COM0A1: 0 bit is not double buffered (and is not synchronized with OCR0A), this can lead to a failure in the output if the mode switches when the output signal is high (it will remain high until the next overflow). It does not seem to matter what order the OCR0A changes and the mode change is executed, both may fail.

I also considered another solution to disable PWM by setting COM0A1: 0 = 0. This will immediately set the output to a value in the PORT register, which will be zero. But there still remains the problem of returning from zero output to a non-zero filling cycle. From what I read in the datasheet, setting COM0A1: 0 to re-enable PWM will immediately switch the output to PWM, which may be the wrong value until the next comparison or timer overflow. Hence the failure.

Inverting the common PWM may be applicable, but then the problem simply becomes the achievement of a complete duty cycle with symmetrical problems.

Please note that it is not possible to disable PWM wave generation during forced output of output via PORT, as described in the data table:

The Compare Output mode bits (COM0x1: 0) have two functions. The signal generator uses the COM0x1: 0 bit to determine the output Compare (OC0x) in the following comparison. In addition, COM0x1: 0 bits control the output source of the OC0x output.

It is not possible to start PWM in a cycle or so on and switch to it when it is ready - turning on PWM immediately forces output to be output.

UPDATE. In the phase (with center alignment) PWM mode, this problem is absent, and in my case this is acceptable. I tried this and confirmed that it works for both zero and full duty cycle.

+6
source share
4 answers

You have two options:

  • if you use fast pwm: you can use inverted pwm. all you have to do is set the OC pins to reverse and invert the pwm comparison values. however now you have crashes with a 100% duty cycle

  • use the phase value pwm. feedback is that the maximum frequency is halved.

+2
source

I just came up on the same issue, but I needed to install Fast PWM on atmega2560.

The solution I found was to temporarily set the output to normal port mode (i.e., set the COMnX1 and COMnX1 bits of the TCCRnA register to zero when a zero loop is needed:

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

+2
source

In fast pwm mode, the duty cycle is: (OCRx + 1) / (TOP + 1) * 100% Thus, you can never get to 0% in non-inverting mode and never to 100% in inverting mode.

0
source

There is another option, just change the direction of the output to the input as follows:

 DDRB &= ~(1<<PB1); 

.. when you want to achieve a zero duty cycle. I know that this is some kind of hack, and sometimes I don’t feel like doing such things, but in any case it works.

0
source

Source: https://habr.com/ru/post/969825/


All Articles