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.

4
  • 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. Commented Oct 25, 2016 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?). Commented Oct 25, 2016 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
    Commented Oct 25, 2016 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. Commented Oct 25, 2016 at 8:54

1 Answer 1

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
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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