2

Nick Gammon's cheatsheet for the Ardunino UNO's ATmega328P (below) shows some hints on the Clear Timer on Compare (CTC) modes of AVR chips. Most of the examples for CTC mode I find use the COMxxx registers of 01 = toggle to control the OCxx pin, which would give a 50% duty cycle at 1/2 the frequency of the timer clearing.

My question is about using the non-toggling COMxxx modes of Clear and Set, which don't seem to provide an automatic way to reset into the opposite state, as in the PWM modes.

For example:

void setup() {
  // put your setup code here, to run once:

   // Timer 1 CTC mode Clearing OC1B at 0.25Hz using OCR1A to set frequency
   // Output on OC1B  
   // Clear at OCR1B
   // WGM =15 0b0100 

   DDRB |= bit(DDB5)| bit(DDB6);  // Teensy2.0 atmega32u OC1A and OC1B outputs
  // DDRB |= bit(DDB1)| bit(DDB2);  // atmega168/UNO OC1A and OC1B (Tested by OP/Luis)
   TCCR1A =  bit(COM1A0) | bit(COM1B1)  ; // Toggle OC1A, Clear on OC1B    
   TCCR1B =  bit(WGM12)  | bit(CS12);  // Set /1 prescaler
   TCCR1C = 0;  // Note that it is good to initialize the timer
                // into a known mode before trying to set interesting TOPs 
   OCR1A  = 62500U ;    // Set TOP count to 16000000/(PreScaler *Ftimer)
   OCR1B  = OCR1A/2;    //  ~50% duty cycle
   TCCR1A =  bit(COM1A0) | bit(COM1B1)  ; // Toggle OC1A, Clear on OC1B    
   TCCR1B =  bit(WGM12)  | bit(CS12) | bit(CS10);  // Set /1024 prescaler
   TCNT1 = 0 ;
}

void loop() {
  // put your main code here, to run repeatedly:
  //OCR1B = 62500U/4-1; // 25% duty cycle. 
}

If I try the above code, I get a 0.125Hz ( 8s period signal) on PB5 and a constant low on PB6.

What is the way to set OC1B high to be cleared by the timer match? And similarly, vice versa: clearing OC1B to be set by the timer match?

Is there a direct way or do you fiddle with COM1Bx, trigger FOC1B, and then fiddle COM1B back?

enter image description here

This code uses the TCCR1C:FOC1B register to set the bit by messing with the TCCR1A:COM1Bx bits, but it seems awkward:

void setup() {
   // Timer 1 CTC mode Clearing OC1B at 0.25Hz using OCR1A to set frequency
   // Output on OC1B  
   // Clear at OCR1B
   // WGM =15 0b0100 

   DDRB |= bit(DDB5)| bit(DDB6);  // Teensy2.0 atmega32u OC1A and OC1B outputs
  // DDRB |= bit(DDB1)| bit(DDB2);  // atmega168/UNO OC1A and OC1B (Tested by OP/Luis)
   TCCR1A =  bit(COM1A0) | bit(COM1B1)  ; // Toggle OC1A, Clear on OC1B    
   TCCR1B =  bit(WGM12)  | bit(CS12);  // Set /1 prescaler
   TCCR1C = 0;  // Note that it is good to initialize the timer
                // into a known mode before trying to set interesting TOPs 
   OCR1A  = 62500U ;    // Set TOP count to 16000000/(PreScaler *Ftimer)
   OCR1B  = OCR1A/2;    //  ~50% duty cycle
   TCCR1A =  bit(COM1A0) | bit(COM1B1)  ; // Toggle OC1A, Clear on OC1B    
   TCCR1B =  bit(WGM12)  | bit(CS12) | bit(CS10);  // Set /1024 prescaler
   TCNT1 = 0 ;
}

void loop() {
  int saveCOM;
  Serial.println(TCCR1A,BIN);
  delay(7000); // 7 seconds
  saveCOM = TCCR1A; 
  TCCR1A |= bit(COM1B1) | bit(COM1B0) ; // config for set OC1B
  TCCR1C = bit(FOC1B); // force a compare to set bit
  TCCR1A = saveCOM ; // restore mode
}

This code has the 0.125Hz on OC1A, and a semi-random series of 1-4 second long pulses on OC1B.

I was interested in playing with the CTC modes for doing long cycle/low frequency PWM. With the normal PWMs you could range from a 1-bit 50% PWM at 8MHz to a 16 bit PWM at a frequency of 0.119Hz (8.388s) With the CTC modes, if you could manage the sets and clears in an TIMERx_OVF_vect with a couple 16 bit registers, you could extend it to 32 bits of PWM resolution with a period up to 152 hours.

  • If you don't set the WGM mode before you set the TOP/OCR1A/ICR1, it could be truncated to 8 (, 9, or 10?) bits from the Arduino default WGM=5=0b0101 modes. – Dave X Feb 23 '16 at 19:03
  • You can set the output using digitalWrite(10, HIGH). On compare match it's cleared. If it was already cleared, nothing happens. This would be useful to create a single pulse of a precise length. – Gerben Feb 23 '16 at 19:06
  • 1
    @Gerben Maybe it's my Teensy 2.0, but putting digitalWrite(PIN_B6,HIGH) or digitalWrite(15, HIGH) seems to stay high forever after the CTC config, or be cleared immediately if before the CTC setup. Checking TCCRA1, it seems that digitalWrite(PIN_B6,HIGH) unsets COM1B1 and COM1B0. – Dave X Feb 23 '16 at 19:47
  • Sorry, stupid me. The digitalWrite implementation will disable PWM. Instead do something like PORTB |= _BV(PB2). – Gerben Feb 23 '16 at 19:54
  • @Gerben. Stiil nope. it seems that the PORTB bit value is inhibited/overriden by the OC1B state. "If one or both of the COMnB1:0 bits are written to one, the OCnB output overrides the normal port func- tionality of the I/O pin it is connected to. If one or both of the COMnC1:0 bits are written to one, the OCnC output overrides the normal port functionality of the I/O pin it is connected to." in the TCCR1A section of my datasheet. If I toggle COM1Bxx on and off with an underlying high PORTB, it toggles the voltage off and on at the pin. – Dave X Feb 23 '16 at 20:03

Your Answer

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

Browse other questions tagged or ask your own question.