ATmega328P, Timer0, PWM, Phase Correct

Hi,

I'm trying to set up a timer like described on the title but the output is always high (5V all the time).
The code is this:

void setup(){

DDRD = (1 << DDD6) | (1 << DDD5);

TCCR0A = 1 << COM0A1 | 0 << COM0A0 | 1 << COM0B1 | 0 << COM0B0 | 0 << WGM01 | 1 << WGM00;

TCCR0B = 1 << WGM02 | 1 << CS02 | 0 << CS01 | 0 << CS00;

OCR0A = 44; //neutral
OCR0B = 44; //neutral
}

void loop(){

}

It will be a error on the code or it's some bug of the chip?

Best regards

From a first impression, the definitions look correct. Perhaps you should try this not in the Arduino setup/loop structure, but as a simple main?

void main() {

  // same register definitions
  while (1);

}

That will probably require #include <avr/io.h>, maybe some other libraries?

Edit: Just to be on the safe side, you measured the signal with a scope / fast logic analyzer, right?

Ze_L:
It will be a error on the code or it's some bug of the chip?

It will be an error in the code.

  OCR0A = 44; //neutral
  OCR0B = 44; //neutral

Without checking your other stuff, exactly how long do you expect the duty cycle to be?

thanks all for the comments.

about de duty cycle to the neutral position, i think that 44 is correct because i want aprox 1400 us

It looks like you are using mode 7, fast PWM with top at OCR0A.

Since your top is 44, and your duty cycle is 44, it will be always on.

I think it's Phase Correct PWM (mode 5) - note the 0 for WGM01...

TCCR0A = 1 << COM0A1 | 0 << COM0A0 | 1 << COM0B1 | 0 << COM0B0 | 0 << WGM01 | 1 << WGM00;
TCCR0B = 1 << WGM02 | 1 << CS02 | 0 << CS01 | 0 << CS00;

Oops, yes you are right. That's why I don't like it when people mention bits that are not used. :slight_smile:

Mode 5 still tops at OCR0A.

True, it confused me quite a bit too until I got it sorted out... I think... :slight_smile: Definitely not recommended for code readability!

Yes. I do wish the OP would give us some more details. Maybe I'll find the time today to actually run this code on some Arduino and see what I get.

Looks like I was right. If I change the code to this:

void setup(){ 
  DDRD = (1 << DDD6) | (1 << DDD5);
  TCCR0A = 1 << COM0A1 | 0 << COM0A0 | 1 << COM0B1 | 0 << COM0B0 | 0 << WGM01 | 1 << WGM00;
  TCCR0B = 1 << WGM02 | 1 << CS02 | 0 << CS01 | 0 << CS00;
  OCR0A = 44; 
  OCR0B = 22;
}
void loop() { }

I measure 714 Hz (period 1400 µS) with a duty cycle of 50%, on pin D5.

Ah, you beat me to it :slight_smile:

I just finished my own check, and you were right Nick. In Phase Correct PWM with Compare Output mode, as in our case, the pin sets and clears when the counter TCNT0 matches OCR0x on the way up and on the way down. Now, in mode 5, TCNT0 only goes up to OCR0A, so the pin never clears (or, in inverted mode, never sets).

Your corrected code works for the OC0B pin (PD5) because its target (22) is lower than OCR0A (44). If the OP wishes to get a PWM on two separate pins, it will require working in mode 1 (where TCNT0 goes all the way to 255), or setting pins "manually" in interrupt functions.

Well, that was a nice exercise in figuring out the datasheet :slight_smile:

Always fun to do. And to make sense of all those timer modes. :slight_smile:

Thanks all for the answers.
Sorry about my time to response, i was out for a days.

Yes, i want to work with 2 outputs. My first code was with timer1 and worked well.
I was trying to do it with timer0 or 2 because i had a limitation at the hardware.

I have just solved my problem with the hardware. Now, i can use it (timer1).

One more time, thanks all for the answers.

At the end of the year maybe i can show you my project.
Best regards