0
votes

I'm doing a project for which I need two measurements from two different ADCs and two different PWM signals related to them. The values measured are stored in the variables freq and duty. As the names state, I want one PWM signal's frequency to vary depending on the value of freq, while the other one must change its duty cycle depending on duty. The problem is that the first signal works alright but the second doesn't.

I'm using an ATmega328p. I've tried using a constant value instead of the variable duty but the same happened. Instead of the PWM signal, the output pin (OC0B) is constantly set high, i.e. 5 V DC. The function is really simple:

//Timer0 configuration
TCCR0A = 0b00100011;
TCCR0B = 0b00001001; //Fast PWM, no prescaler, non-inverted, out OC0B
OCR0B = duty;

I've triple-checked the values of the TCCR0 registers but everything seems to be correct. What could be causing this behaviour?

1
There is an extensive discussion about it on this web page.Hans Passant
You probably want to use mode 3 instead of mode 7. Or you forgot to set OCR0A.Edgar Bonet
@EdgarBonet Sorry for my ignorance, but what do you mean? I don't understand what you mean by "mode 3" or 7. Also, why would I set OCR0A if I want to use the B output?Tendero

1 Answers

2
votes

Expanding my comment into a full answer.

On page 140 of the datasheet there is a table listing all the “waveform generation modes”. The code you show in your question sets the timer into mode 7: fast PWM with TOP = OCR0A. In this mode, the timer counts from zero up to the value stored in OCR0A, then rolls back to zero and starts again. You could use this mode to generate a PWM signal on OC0B. You would then be able to control both the signal period (by setting the OCR0A register) and the pulse width (via OCR0B). If you fail to set OCR0A, it defaults to zero, and it won't work.

If you are happy with a period of 256 clock cycles and do not want to change it, you could write 255 into OCR0A. Alternatively, you can set the timer into mode 3: fast PWM with TOP = 0xff. In this mode, the period is 256 cycles, irrespective of the value stored in OCR0A.

Below is a simple test program that demonstrates the use of mode 3. It generates a PWM signal where the pulse width is 64 CPU cycles and the period is 256 cycles.

#include <avr/io.h>

int main(void)
{
    uint8_t duty = 64;

    // Set pin PD5 = OC0B as output.
    DDRD  |= _BV(PD5);

    // Configure Timer 0.
    OCR0B  = duty - 1;    // set duty cycle
    TCCR0A = _BV(COM0B1)  // non-inverting PWM on OC0B
           | _BV(WGM00)   // mode 3: fast PWM, top = 0xff
           | _BV(WGM01);  // ditto
    TCCR0B = _BV(CS00);   // clock at F_CPU

    for (;;) ;
}