3

This is a follow up to my previous question.

I have Timer2 in CTC mode, with TOP=OCR2A set to 150 (with a prescaler of 8, giving a 75us timing interval).

The datasheet states that setting COM2B1 to 1 in TCCR2A will "clear OC2B on compare match" (= Arduino pin D3) when you are in CTC mode.

I would like to use this functionality to get a "pwm" signal with a period of 75us, with duty cycle determined by OCR2B. I realize that this is a very convoluted way of achieving this, but eventually I want to be continually be changing OCR2B to get a (rapidly) varying duty cycle.

In the compare channel A interrupt I would like to turn D3 high, relying on the "clear on compare match" feature of channel B to turn it low a small interval later.

I have the following minimal(-ish) example:

#define OCIEA 1
#define CA21 1

void setup() {
  // PD3 as output
  DDRD |= (1 << PD3);

  // Pause the timers so they sync up
  GTCCR = (1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); // Halt all timers

  // Reset timer
  TCNT2 = 0; // set timer2 to 0 (8-bit timer)

  // Enable CTC mode
  TCCR2A = (1 << WGM21); // Timer 2 in CTC (TOP = OCR2A)

  // Clear output pins on compare match
  TCCR2A |= (1 << COM2B1); // Clear OC2B on match

  // Set prescaler
  TCCR2B = (1 << CA21); // set timer 2 divisor to 8

  // Set output compare
  OCR2A = 150; // Determines TOP for Timer2

  // Determines the pulse width
  OCR2B = 75; // Timer 2 output B (controls OC2B = PD3 = D3)

  // Enable interrupts for timer 2
  TIMSK2 = (1 << OCIEA);

  // Set the timers going again
  GTCCR = 0; // release all timers
}

ISR(TIMER2_COMPA_vect)
{
  TCCR2A &= ~((1 << COM2B1) | (1 << COM2B0)); // Disable clear OC2B on match
  DDRD |= (1 << PD3); // Enable output
  PORTD |= (1 << PD3); // Output high
  TCCR2A |= (1 << COM2B1); // Enable clear OC2B on match
}

void loop() {

}

Ideally the ISR would just consist of PORTD |= (1 << PD3); but this does not give my desired 50% duty cycle, but apparently it's impossible to write to the pin with COM2B1 enabled, so I tried various combinations of disabling it and reconnecting the pin but all I am getting is a very, very short pulse. It looks like as soon as COM2B1 is re-enabled, the pin goes low, even though a compare match on channel B should not have happened yet.

Setting COM2B0 instead of COM2B1 works as expected: the pin toggles state (but this is not what I want).

Why does this not work the way I expect it to, and is there a way to get my desired behavior? Also, if this is not possible, what on earth is the purpose of the clear on compare match feature if you can't turn the pin on at all when using it?

I have discovered I can sort of get the behavior I want by setting COM2B0 instead of COM2B1 (toggle on match rather than clear on match) and forcing a compare match in the interrupt (toggling the pin off) so that later the "real" toggle on match will turn it off. However, this is not ideal (as if the real and forced match overlap, I would lose track of the pin's state), and I'm still wondering what the purpose of the clear on match functionality is if it just forces the pin low.

  • 1
    I think a potential solution might be to, in the interrupt, activate set on match, force a match, and then set it back to clear on match (and possibly force a match again if I detect the forced and "real" matches overlapped). I can't try this out until this afternoon, and it still seems needlessly complicated. – Tom van der Zanden Oct 25 '16 at 7:13
  • 2
    Why don't you use mode 7 instead of mode 2? Mode 7 combines CTC with fast PWM, which seems to be what you want, although it's not officially called “CTC” (but why would you care about the official name?). – Edgar Bonet Oct 25 '16 at 8:30
  • 1
    Use Edgar's solution. Or use ISR(TIMER2_COMPB_vect) to set the pin to low, but this isn't ideal. – Gerben Oct 25 '16 at 8:50
  • That makes sense. It seems I should have read the answers I got to my original question more carefully. Thanks. I'm not sure if I should delete this now (since a more careful reading of the original question solves my problem), but I am still interested why what I came up with doesn't work and what the use of "clear on match" in CTC mode is. Also, I think this is a strong case of me suffering from the XY problem. – Tom van der Zanden Oct 25 '16 at 8:54
2

The PWM modes manage pin at both ends of the cycle.

The point of the CTC modes is that they manage the pin only at one end of the count, but allow you to manage the other end explicitly.

To manage both ends explicitly, you use normal mode.

To set the OC2B bit with FOC2B in the TCCR2B with your interrupt:

ISR(TIMER2_COMPA_vect)
{
  TCCR2A |=  (1 << COM2B0); // Set OC2B on Compare Match
  TCCR2B |=  (1 << FOC2B ); // Force Output Compare B OC2B 
  TCCR2A &= ~(1 << COM2B0); // Clear OC2B on Compare Match
}
-3

Arduino pre-configures as

TCCR2A = (1 << WGM20);

TCCR2B = (1 << WGM22);

thus Initially reset the register

TCCR2A=0;//reset the register

TCCR2B=0;//reset the register

  • 1
    That would be relevant if the OP used the |= and &= operators to only change some of the bits of TCCR2A and TCCR2B. However, the OP is already overwriting those registers with the = operator, making your answer pointless. – Edgar Bonet Jul 18 '18 at 12:04
  • As you have used block quote formatting, presumably you have sourced this information from somewhere. Please edit your answer and include the the link to the source from whence it came. Did it come from here, Issue with Timer2 in CTC mode on the arduino uno board, per chance? Plagiarism is generally frowned upon. – Greenonline Jul 18 '18 at 12:47

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.