1

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.

VE7JRO
2,51519 gold badges27 silver badges29 bronze badges
asked Feb 23, 2016 at 18:46
12
  • 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. Commented Feb 23, 2016 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. Commented Feb 23, 2016 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. Commented Feb 23, 2016 at 19:47
  • Sorry, stupid me. The digitalWrite implementation will disable PWM. Instead do something like PORTB |= _BV(PB2). Commented Feb 23, 2016 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. Commented Feb 23, 2016 at 20:03

1 Answer 1

1

The comment by the OP under the question is:

I meant how do I set the OC1A pin when i'm using the clear-on-match CTC mode (and vice versa) I know toggle changes it every match, but I don't understand how to use the non-toggle modes.

This code toggles OC1A (D9 on the Uno) at a frequency of 19kHz giving an overall frequency of 38kHz:

void setup() 
 {
 pinMode (9, OUTPUT);
 TCCR1A = bit (COM1A0); // toggle OC1A on match
 TCCR1B = bit (WGM12) | bit (CS10); // CTC, no prescaler
 OCR1A = (F_CPU / 38000L) - 1; // zero relative 
 } // end of setup
void loop()
 {
 }

The non-toggle modes aren't particularly useful. When it matches it sets the output high, or low, which doesn't really achieve much in this case.

I suppose if you had a long CTC time (big prescaler and large amount to count up to) then you could use it to set that pin to high or low when the time elapsed.


On a Atmega328P, is there a convenient way to un-set or un-clear a timer in CTC clear-on-match, or set-on-match mode?

Do you mean the timer output? Not really because setting those bits means the timer controls the output pin. What you could possibly do is turn off the output control (bit (COM1A0)), change the pin yourself, and put it back, but I'm not sure if that would switch it back to the timer output.

answered Jun 26, 2024 at 7:01
2
  • Yes, I mean the timer output. It seems as if the CTC+set or CTC+clear modes could be a reasonable choice for using a timer to do a one-shot, but the reset seems uncertain. In higher frequency toggling modes one can often ignore the initial state, but for a one-shot behavior you need to know/control the initial state. // So one can't unset the timer output within a CTC set-on-match mode, and to do so you must exit the mode. And that OC1A might be initialized using the PORTB:1 bit when the you turn on the output control (bit COM1A0). I'll experiment with it. Commented Jun 27, 2024 at 14:17
  • 1
    @DaveX For the long periods you are describing it is probably easier to just have it trigger an interrupt and set the pin in the interrupt handler. Commented Jun 28, 2024 at 5:36

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.