Skip to main content
Changed order to not change mode after setting OCR2A and stop the timer before all changes
Source Link
KIIV
  • 4.9k
  • 1
  • 14
  • 23
  TCCR2B = 0;          // stop the timer and reset WGM22
  TCCR2A = _BV(WGM21); // turn on CTC mode with top in OCR2A
  OCR2A  = 124;         // = (16*10^6) / (2000*64) - 1 (must be <256)
  TCCR2BTCNT2  = _BV(CS22);0;  // Set CS22 bit for 64 prescaler
  TCNT2//initialize counter =value 0;to 0
  TCCR2B = _BV(CS22);  // Set CS22 bit for 64 //initializeprescaler counter(for valuestarting tothe 0timer)
  TCCR2A = _BV(WGM21); // turn on CTC mode with top in OCR2A
  OCR2A  = 124;         // = (16*10^6) / (2000*64) - 1 (must be <256)
  TCCR2B = _BV(CS22);  // Set CS22 bit for 64 prescaler
  TCNT2  = 0;          //initialize counter value to 0
  TCCR2B = 0;          // stop the timer and reset WGM22
  TCCR2A = _BV(WGM21); // turn on CTC mode with top in OCR2A
  OCR2A  = 124;        // = (16*10^6) / (2000*64) - 1 (must be <256)
  TCNT2  = 0;          //initialize counter value to 0
  TCCR2B = _BV(CS22);  // Set CS22 bit for 64 prescaler (for starting the timer)
Even CTC mode is working, reorder is needed
Source Link
KIIV
  • 4.9k
  • 1
  • 14
  • 23

So you're right that CTC is acting weird. I've noticed this few years ago too on different board, but I've always suspected asychronous mode (I've added 32k RTC Xtal on Arduino Mega).

However Fast PWM mode with OCR2A as a TOP value seems to be working:

class TimerTwo
{
  public: //methods
    void initialize();
    void attachInterrupt(void (*isr)());
    void detachInterrupt();
    void (*isrCallback)() = nullptr;
};

TimerTwo Timer2;

ISR(TIMER2_COMPA_vect) { //ISR on Compare Match A
  Timer2.isrCallback();
}

void TimerTwo::initialize() {
  cli();
 
  OCR2A = 124;                        // = (16*10^6) / (2000*64) - 1 (must be <256)
  TCCR2A = _BV(WGM21) | _BV(WGM20);   // turn on fast PWM mode with top in OCR2A
  TCCR2B = _BV(WGM22) | _BV(CS22);    // Set CS22 bit for 64 prescaler
  TCNT2  = 0;                         // initialize counter value to 0

  sei();
}

void TimerTwo::attachInterrupt(void (*isr)()) {
  isrCallback = isr;
  TIMSK2 |= _BV(OCIE2A);
}

void TimerTwo::detachInterrupt() {
  TIMSK2 &= ~_BV(OCIE2A);
  isrCallback = nullptr;
}

volatile uint32_t counter = 0;
void isrHandler() {
  ++counter;
}

void setup() {
  Serial.begin(115200);
  Timer2.initialize();
  Timer2.attachInterrupt(&isrHandler);
}

void loop() {
    static uint32_t counter_old = 0;
    Serial.println(counter - counter_old);
    counter_old = counter;
    delay(500);
}

EDIT: Ok, so after some digging on this issue I've found that setting CTC mode might cause OCR2A corruption (I guess?) . It seems to be working if you reorder the settings to:

  TCCR2A = _BV(WGM21); // turn on CTC mode with top in OCR2A
  OCR2A  = 124;         // = (16*10^6) / (2000*64) - 1 (must be <256)
  TCCR2B = _BV(CS22);  // Set CS22 bit for 64 prescaler
  TCNT2  = 0;          //initialize counter value to 0

So you're right that CTC is acting weird. I've noticed this few years ago too on different board, but I've always suspected asychronous mode (I've added 32k RTC Xtal on Arduino Mega).

However Fast PWM mode with OCR2A as a TOP value seems to be working:

class TimerTwo
{
  public: //methods
    void initialize();
    void attachInterrupt(void (*isr)());
    void detachInterrupt();
    void (*isrCallback)() = nullptr;
};

TimerTwo Timer2;

ISR(TIMER2_COMPA_vect) { //ISR on Compare Match A
  Timer2.isrCallback();
}

void TimerTwo::initialize() {
  cli();
 
  OCR2A = 124;                        // = (16*10^6) / (2000*64) - 1 (must be <256)
  TCCR2A = _BV(WGM21) | _BV(WGM20);   // turn on fast PWM mode with top in OCR2A
  TCCR2B = _BV(WGM22) | _BV(CS22);    // Set CS22 bit for 64 prescaler
  TCNT2  = 0;                         // initialize counter value to 0

  sei();
}

void TimerTwo::attachInterrupt(void (*isr)()) {
  isrCallback = isr;
  TIMSK2 |= _BV(OCIE2A);
}

void TimerTwo::detachInterrupt() {
  TIMSK2 &= ~_BV(OCIE2A);
  isrCallback = nullptr;
}

volatile uint32_t counter = 0;
void isrHandler() {
  ++counter;
}

void setup() {
  Serial.begin(115200);
  Timer2.initialize();
  Timer2.attachInterrupt(&isrHandler);
}

void loop() {
    static uint32_t counter_old = 0;
    Serial.println(counter - counter_old);
    counter_old = counter;
    delay(500);
}

So you're right that CTC is acting weird. I've noticed this few years ago too on different board, but I've always suspected asychronous mode (I've added 32k RTC Xtal on Arduino Mega).

However Fast PWM mode with OCR2A as a TOP value seems to be working:

class TimerTwo
{
  public: //methods
    void initialize();
    void attachInterrupt(void (*isr)());
    void detachInterrupt();
    void (*isrCallback)() = nullptr;
};

TimerTwo Timer2;

ISR(TIMER2_COMPA_vect) { //ISR on Compare Match A
  Timer2.isrCallback();
}

void TimerTwo::initialize() {
  cli();
 
  OCR2A = 124;                        // = (16*10^6) / (2000*64) - 1 (must be <256)
  TCCR2A = _BV(WGM21) | _BV(WGM20);   // turn on fast PWM mode with top in OCR2A
  TCCR2B = _BV(WGM22) | _BV(CS22);    // Set CS22 bit for 64 prescaler
  TCNT2  = 0;                         // initialize counter value to 0

  sei();
}

void TimerTwo::attachInterrupt(void (*isr)()) {
  isrCallback = isr;
  TIMSK2 |= _BV(OCIE2A);
}

void TimerTwo::detachInterrupt() {
  TIMSK2 &= ~_BV(OCIE2A);
  isrCallback = nullptr;
}

volatile uint32_t counter = 0;
void isrHandler() {
  ++counter;
}

void setup() {
  Serial.begin(115200);
  Timer2.initialize();
  Timer2.attachInterrupt(&isrHandler);
}

void loop() {
    static uint32_t counter_old = 0;
    Serial.println(counter - counter_old);
    counter_old = counter;
    delay(500);
}

EDIT: Ok, so after some digging on this issue I've found that setting CTC mode might cause OCR2A corruption (I guess?) . It seems to be working if you reorder the settings to:

  TCCR2A = _BV(WGM21); // turn on CTC mode with top in OCR2A
  OCR2A  = 124;         // = (16*10^6) / (2000*64) - 1 (must be <256)
  TCCR2B = _BV(CS22);  // Set CS22 bit for 64 prescaler
  TCNT2  = 0;          //initialize counter value to 0
Source Link
KIIV
  • 4.9k
  • 1
  • 14
  • 23

So you're right that CTC is acting weird. I've noticed this few years ago too on different board, but I've always suspected asychronous mode (I've added 32k RTC Xtal on Arduino Mega).

However Fast PWM mode with OCR2A as a TOP value seems to be working:

class TimerTwo
{
  public: //methods
    void initialize();
    void attachInterrupt(void (*isr)());
    void detachInterrupt();
    void (*isrCallback)() = nullptr;
};

TimerTwo Timer2;

ISR(TIMER2_COMPA_vect) { //ISR on Compare Match A
  Timer2.isrCallback();
}

void TimerTwo::initialize() {
  cli();
 
  OCR2A = 124;                        // = (16*10^6) / (2000*64) - 1 (must be <256)
  TCCR2A = _BV(WGM21) | _BV(WGM20);   // turn on fast PWM mode with top in OCR2A
  TCCR2B = _BV(WGM22) | _BV(CS22);    // Set CS22 bit for 64 prescaler
  TCNT2  = 0;                         // initialize counter value to 0

  sei();
}

void TimerTwo::attachInterrupt(void (*isr)()) {
  isrCallback = isr;
  TIMSK2 |= _BV(OCIE2A);
}

void TimerTwo::detachInterrupt() {
  TIMSK2 &= ~_BV(OCIE2A);
  isrCallback = nullptr;
}

volatile uint32_t counter = 0;
void isrHandler() {
  ++counter;
}

void setup() {
  Serial.begin(115200);
  Timer2.initialize();
  Timer2.attachInterrupt(&isrHandler);
}

void loop() {
    static uint32_t counter_old = 0;
    Serial.println(counter - counter_old);
    counter_old = counter;
    delay(500);
}