1

board: Arduino Mega (ATMEGA2560)

I want to generate pulses using timer1 configured as Fast PWM, this is my code which works fine:

#include <avr/io.h>

int main(void)
//void setup()
{

  DDRB |= (1 << DDB5) | (1 << DDB6); // PWM outputs


  ICR1 = 0x7FFF;  // TOP
  OCR1A = 0x3FFF; // 50% of ICR1
  OCR1B = 0x3FFF; // 50% of ICR1

  TCCR1A |= (1 << COM1A1) | (1 << COM1B1);
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM12) | (1 << WGM13);
  TCCR1B |= (1 << CS10);

}

void loop() {

}

I don't understand why it doesn't work if I use void setup() instead of int main(void). I'm working with arduino IDE 1.8.2 and always used void setup(), in this case I used int main(void) because it is used in some turorials I found like this one: https://www.youtube.com/watch?v=O_Yqf_cugwE

EDIT: When I say that it doesn't work, what happens is that instead of having PWM signals I just have a constant 5V output in both OC1A and OC1B pins

  • Try using = instead of |=. – Edgar Bonet May 3 '18 at 16:03
  • Using = instead of |= I have now a 0V output instead of 5V. I tried to initialize TCCR1A = 0; and TCCR1B = 0; first. – Mr. C May 3 '18 at 16:18
2

If you don't define your own main(), your program will be linked with the main() provided by the Arduino core library, which roughly looks like this (I am simplifying a little bit):

int main(void)
{
    init();      // Arduino core initialization
    setup();     // user's initialization
    for (;;)
        loop();  // user's main loop
}

The core's init() function configures Timer 1 for 8-bit phase correct PWM at 490 Hz, which means that, by the time your setup() runs, the timer's control registers are not in their default state anymore, and some of their bits are already set to 1. If you then update these registers using the |= operator, you end up with a mix of the core's configuration and your own.

This can be fixed either by zeroing these registers first or, more simply, by setting their values with the = operator, which has the effect or setting every bit of those registers to the value you want.

The following works whether you use or not the Arduino core library:

#ifdef NOCORE
int main(void)
#else
void setup()
#endif
{
    DDRB   = _BV(PB5) | _BV(PB6);
    TCCR1A = _BV(COM1A1)
           | _BV(COM1B1)
           | _BV(WGM11);
    TCCR1B = _BV(WGM12)
           | _BV(WGM13)
           | _BV(CS10);
    ICR1   = 0x7fff;  // TOP
    OCR1A  = 0x3fff;  // 50% of ICR1
    OCR1B  = 0x3fff;  // 50% of ICR1
}

#ifndef NOCORE
void loop(){}
#endif

Note that:

  1. The control registers are set (=) rather than just modified with |=
  2. The mode is set before the output compare registers. This is because setting the output compare registers does not work well when the timer is in an 8-bit mode.
  • Thank you for pointing out that the order in which the timer is set up could affect in some way, i had no idea. With your code it still does not work for me, did you have a chance to test it? – Mr. C May 3 '18 at 18:31
  • @Mr.C: I tested it (and it works) on an Uno. I had to change DDRB to _BV(PB1) | _BV(PB2) in order to fit the Uno's pinout. Note that on the previous version of my answer I mistakenly left the DDRB setting appropriate for the Uno. – Edgar Bonet May 3 '18 at 18:44
  • After changing DDRB to _BV(PB1) | _BV(PB2) to the corresponding pins in MEga DDRB to _BV(PB5) | _BV(PB6) it works perfectly, i didnt notice that. Thank you so much @Edgar Bonet, after your explanation about the core's init function it is more clear for me now why it was not working with void setup(). – Mr. C May 3 '18 at 18:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.