AVR Timers – CTC Mode


AVR SeriesHello friends! Welcome to the another tutorial on AVR Timers. Till now, we have covered the following topics in AVR Timers:

The basic concepts of timers and its applications have been discussed in earlier posts. In this post, we will discuss about a special mode of operation – Clear Timer on Compare (CTC) Mode.

CTC Mode

So till now, we have dealt with the basic concepts. We had two timer values with us – Set Point (SP) and Process Value (PV). In every iteration, we used to compare the process value with the set point. Once the process value becomes equal (or exceeds) the set point, the process value is reset. The following code snippet explains it:

max = 39999;   // max timer value set  <--- set point

// some code here
// ...
// ...
// ...

// TCNT1 <--- process value
if (TCNT1 >= max)   // process value compared with the set point
{
    TCNT1 = 0;      // process value is reset
}

// ...

Here, we have used the example of TIMER1. Since TIMER1 is a 16-bit timer, it can count upto a maximum of 65535. Here, what we desire is that the timer (process value) should reset as soon as its value becomes equal to (or greater than) the set point of 39999.

So basically, the CTC Mode implements the same thing, but unlike the above example, it implements it in hardware. Which means that we no longer need to worry about comparing the process value with the set point every time! This will not only avoid unnecessary wastage of cycles, but also ensure greater accuracy (i.e. no missed compares, no double increment, etc).

Hence, this comparison takes place in the hardware itself, inside the AVR CPU! Once the process value becomes equal to the set point, a flag in the status register is set and the timer is reset automatically! Thus goes the name – CTC – Clear Timer on Compare! Thus, all we need to do is to take care of the flag, which is much more faster to execute.

Let us analyze this CTC Mode in detail with the help of a problem statement.

Problem Statement

Let’s take up a problem statement to understand this concept. We need to flash an LED every 100 ms. We have a crystal of XTAL 16 MHz.

Methodology – Using CTC Mode

Before proceeding any further, let’s jot down the formula first. I also recommend you to read my TIMER0 tutorial in order to understand this better. I won’t be revising the basic concepts here, just their application.Timer CountNow, given XTAL = 16 MHz, with a prescaler of 64, the frequency of the clock pulse reduces to 250 kHz. With a Required Delay = 100 ms, we get the Timer Count to be equal to 24999. Up until now, we would have let the value of the timer increment, and check its value every iteration, whether it’s equal to 24999 or not, and then reset the timer. Now, the same will be done in hardware! We won’t check its value every time in software! We will simply check whether the flag bit is set or not, that’s all. Confused, eh? Well, don’t worry, just read on! ;)

Okay, so now let me introduce you to the register bits which help you to implement this CTC Mode.

TCCR1A and TCCR1B Registers

The Timer/Counter1 Control Register A – TCCR1A Register is as follows:

TCCR1A Register

TCCR1A Register

The Timer/Counter1 Control Register B – TCCR1B Register is as follows:

TCCR1B Register

TCCR1B Register

You are already aware of the Clock Select Bits – CS12:0 in TCCR1B (if not, view the TIMER1 post, scroll down a bit and you will find it there). Hence, right now, we are concerned with the Wave Generation Mode Bits – WGM13:0. As you can see, these bits are spread across both the TCCR1 registers (A and B). Thus we need to be a bit careful while using them. Their selection is as follows:

Wave Generation Mode Bit Description

Wave Generation Mode Bit Description

We can see that there are two possible selections for CTC Mode. Practically, both are the same, except the fact that we store the timer compare value in different registers. Right now, let’s move on with the first option (0100). Thus, the initialization of TCCR1A and TCCR1B is as follows.

TCCR1A |= 0;   
// not required since WGM11:0, both are zero (0)

TCCR1B |= (1 << WGM12)|(1 << CS11)|(1 << CS10);   
// Mode = CTC, Prescaler = 64

OCR1A and OCR1B Registers

Now that we have set the CTC Mode, we must tell the AVR to reset the timer as soon as its value reaches such and such value. So, the question is, how do we set such and such values? The Output Compare Register 1A – OCR1A and the Output Compare Register 1B – OCR1B are utilized for this purpose.

OCR1A Register

OCR1A Register

OCR1B Register

OCR1B Register

Since the compare value will be a 16-bit value (in between 0 and 65535), OCR1A and OCR1B are 16-bit registers. In ATMEGA16/32, there are two CTC channels – A and B. We can use any one of them or both. Let’s use OCR1A.

OCR1A = 24999;   // timer compare value

TIFR Register

The Timer/Counter Interrupt Flag Register – TIFR is as follows. It is a common register to all the timers.

TIFR Register

TIFR Register

We are interested in Bit 4:3 – OCF1A:B – Timer/Counter1, Output Compare A/B Match Flag Bit. This bit is set (one) by the AVR whenever a match occurs i.e. TCNT1 becomes equal to OCR1A (or OCR1B). It is cleared automatically whenever the corresponding Interrupt Service Routine (ISR) is executed. Alternatively, it can be cleared by writing ’1′ to it!

Code

Now that we are aware of the methodology and the registers, we can proceed to write the code for it. To learn about I/O port operations in AVR, view this. To know about bit manipulations, view this. To learn how to use AVR Studio 5, view this. To learn how this code is structured, view the previous TIMER0 post.

#include <avr/io.h>

// initialize timer, interrupt and variable
void timer1_init()
{
    // set up timer with prescaler = 64 and CTC mode
    TCCR1B |= (1 << WGM12)|(1 << CS11)|(1 << CS10);

    // initialize counter
    TCNT1 = 0;

    // initialize compare value
    OCR1A = 24999;
}

int main(void)
{
    // connect led to pin PC0
    DDRC |= (1 << 0);

    // initialize timer
    timer1_init();

    // loop forever
    while(1)
    {
        // check whether the flag bit is set
        // if set, it means that there has been a compare match
        // and the timer has been cleared
        // use this opportunity to toggle the led
        if (TIFR & (1 << OCF1A)) // NOTE: '>=' used instead of '=='
        {
            PORTC ^= (1 << 0); // toggles the led
        }

        // wait! we are not done yet!
        // clear the flag bit manually since there is no ISR to execute
        // clear it by writing '1' to it (as per the datasheet)
        TIFR |= (1 << OCF1A);

        // yeah, now we are done!
    }
}

So, now you have an LED flashing every 100 ms! Now let’s use another methodology to sort out the same problem statement.

Methodology – Using Interrupts with CTC Mode

In the previous methodology, we simply used the CTC Mode of operation. We used to check every time for the flag bit (OCF1A). Now let’s shift this responsibility to the AVR itself! Yes, now we do not need to check for the flag bit at all! The AVR will compare TCNT1 with OCR1A. Whenever a match occurs, it sets the flag bit OCF1A, and also fires an interrupt! We just need to attend to that interrupt, that’s it! No other headache of comparing and stuffs!

There are three kinds of interrupts in AVR – overflow, compare and capture. We have already discussed the overflow interrupt in previous posts. For this case, we need to enable the compare interrupt. The following register is used to enable interrupts.

TIMSK Register

The Timer/Counter Interrupt Mask Register- TIMSK Register is as follows. It is a common register to all the timers. The greyed out bits correspond to other timers.

TIMSK Register

TIMSK Register

We have already come across TOIE1 bit. Now, the Bit 4:3 – OCIE1A:B – Timer/Counter1, Output Compare A/B Match Interrupt Enable bits are of our interest here. Enabling it ensures that an interrupt is fired whenever a match occurs. Since there are two CTC channels, we have two different bits OCIE1A and OCIE1B for them.

Thus, to summarize, whenever a match occurs (TCNT1 becomes equal to OCR1A = 24999), an interrupt is fired (as OCIE1A is set) and the OCF1A flag is set. Now since an interrupt is fired, we need an Interrupt Service Routine (ISR) to attend to the interrupt. Executing the ISR clears the OCF1A flag bit automatically and the timer value (TCNT1) is reset.

Interrupt Service Routine (ISR)

Now let’s proceed to write an ISR for this. The ISR is defined as follows:

ISR (TIMER1_COMPA_vect)
{
    // toggle led here
    PORTB ^= (1 << 0);
{

Okay, that’s all we need to do in the ISR. Now let’s see how the actual code looks like.

Final Code

To learn about I/O port operations in AVR, view this. To know about bit manipulations, view this. To learn how to use AVR Studio 5, view this. To learn how this code is structured, view the previous TIMER0 post.

#include <avr/io.h>
#include <avr/interrupt.h>

// initialize timer, interrupt and variable
void timer1_init()
{
    // set up timer with prescaler = 64 and CTC mode
    TCCR1B |= (1 << WGM12)|(1 << CS11)|(1 << CS10);

    // initialize counter
    TCNT1 = 0;

    // initialize compare value
    OCR1A = 24999;

    // enable compare interrupt
    TIMSK |= (1 << OCIE1A);

    // enable global interrupts
    sei();
}

// this ISR is fired whenever a match occurs
// hence, toggle led here itself..
ISR (TIMER1_COMPA_vect)
{
    // toggle led here
    PORTC ^= (1 << 0);
{

int main(void)
{
    // connect led to pin PC0
    DDRC |= (1 << 0);

    // initialize timer
    timer1_init();

    // loop forever
    while(1)
    {
        // do nothing
        // whenever a match occurs, ISR is fired
        // toggle the led in the ISR itself
        // no need to keep track of any flag bits here
        // done!
    }
}

Hence, now we have seen how to implement the CTC mode using interrupts, reducing the code size, comparisons and processing time. But this is not over yet! We can reduce them further! Let’s take the same problem statement.

ATMEGA16/32 OC Pins

ATMEGA16/32 OC Pins

Methodology – Using Hardware CTC Mode

Okay, so now, all of you have a look at the pin configuration of ATMEGA16/32. Can you see the pins PB3, PD4, PD5 and PD7? Their special functions are mentioned in the brackets (OC0, OC1A, OC1B and OC2). These are the Output Compare pins of TIMER0, TIMER1 and TIMER2 respectively. Before we learn how to use them, let’s have another look at the TCCR1A register.

TCCR1A Register

The Timer/Counter1 Control Register A – TCCR1A Register is as follows:

TCCR1A Register

TCCR1A Register

Now time for us to concentrate on Bit 7:6 – COM1A1:0 and Bit 5:4 – COM1B1:0 – Compare Output Mode for Compare Unit A/B. These bits control the behaviour of the Output Compare (OC) pins. The behaviour changes depending upon the following modes:

  • Non-PWM mode (normal / CTC mode)
  • Fast PWM mode
  • Phase Correct / Phase & Frequency Correct PWM mode

Right now we are concerned only with the CTC mode. The following options hold good for non-PWM mode.

Compare Output Mode, non-PWM

Compare Output Mode, non-PWM

Since we need to toggle the LED, we choose the second option (01). Well, that’s all we need to do! No need to check any flag bit, no need to attend to any interrupts, nothing. Just set the timer to this mode and we are done! Whenever a compare match occurs, the OC1A pin is automatically toggled!

But we need to compromise on the hardware. Only PD5 or PD4 (OC1A or OC1B) can be controlled this way, which means that we should connect the LED to PD5 (since we are using channel A) instead of PC0 (which we had been using in all the examples till now).

Now let’s see how the code looks like!

Code

To learn about I/O port operations in AVR, view this. To know about bit manipulations, view this. To learn how to use AVR Studio 5, view this. To learn how this code is structured, view the previous TIMER0 post.

#include <avr/io.h>
#include <avr/interrupt.h>

// initialize timer, interrupt and variable
void timer1_init()
{
    // set up timer with prescaler = 64 and CTC mode
    TCCR1B |= (1 << WGM12)|(1 << CS11)|(1 << CS10);

    // set up timer OC1A pin in toggle mode
    TCCR1A |= (1 << COM1A0);

    // initialize counter
    TCNT1 = 0;
    // initialize compare value
    OCR1A = 24999;
}

int main(void)
{
    // connect led to pin PD5
    DDRD |= (1 << 5);

    // initialize timer
    timer1_init();

    // loop forever
    while(1)
    {
        // do nothing
        // whenever a match occurs
        // OC1A is toggled automatically!
        // no need to keep track of any flag bits or ISR
        // done!
    }
}

Forcing Compare Match

Okay, so till now we have discussed almost all the concepts of CTC mode for TIMER1, except one – Forcing Compare Match. In the TCCR1A register, till now we have ignored Bit 3:2 – FOC1A:B – Force Output Compare for Compare Unit A/B.

TCCR1A Register

TCCR1A Register

If you see clearly, it’s mentioned that these bits are write only bits. They are active only in non-PWM mode. Well, for ensuring compatibility with future devices, these bits must be set to zero (which they already are by default). Setting them to ‘1’ will result in an immediate forced compare match and the effect will be reflected in the OC1A/OC1B pins. The thing to be noted is that FOC1A/FOC1B will not generate any interrupt, nor will it clear the timer in CTC mode.

CTC Mode – TIMER0

Till now we have explored CTC mode of TIMER1. In this section, I will describe the CTC mode of TIMER0 in brief. In other words, we will discuss about the registers only. We will not take a problem statement this time, because I assume that you have read whatever is written above and can use CTC mode of TIMER0 exactly in the same way! So let’s get started.

TCCR0 Register

The Timer/Counter0 Control Register– TCCR10 Register is as follows:

TCCR0 Register

TCCR0 Register

  • Bit 6:3 – WGM01:0 – Wave Generation Mode – Just like in TIMER1, we choose the type of wave mode from here as follows. Choose 10 for CTC mode.
Wave Generation Mode Bit Description

Wave Generation Mode Bit Description

  • Bit 5:4 – COM01:0 – Compare Match Output Mode – They control the behaviour of the OC0 (PB3) pin depending upon the WGM mode – non-PWM, Phase Correct PWM mode and Fast PWM mode. The selection options of non-PWM mode are as follows. Choose 01 to toggle the LED.
Compare Output Mode, non-PWM

Compare Output Mode, non-PWM

  • Bit 7 – FOC0 – Force Output Compare – This bit, when set to ‘1’ forces an immediate compare match and affects the behaviour of OC0 pin. For ensuring compatibility with future devices, this bit must be set to ‘0’.
  • Bit 2:0 – CS02:0 – Clock Select Bits – We are already familiar with these bits. View the TIMER0 post for more details.

OCR0 Register

The Output Compare Register– OCR0 Register is as follows:

OCR0 Register

OCR0 Register

The value to be compared (max 255) is stored in this register.

TIMSK Register

The Timer/Counter Interrupt Mask– TIMSK Register is as follows:

TIMSK Register

TIMSK Register

The Bit 1 – OCIE0 – Timer/Counter0 Output Compare Match Interrupt Enable enables the firing of interrupt whenever a compare match occurs.

TIFR Register

The Timer/Counter Flag Register– TIFR is as follows:

TIFR Register

TIFR Register

The Bit 1 – OCF0 – Output Compare Flag 0 is set whenever a compare match occurs. It is cleared automatically whenever the corresponding ISR is executed. Alternatively it is cleared by writing ‘1’ to it.

That’s it! With this much information, I am sure that you can successfully generate a timer in CTC mode of TIMER0. :)

CTC Mode – TIMER2

Well, I leave this to you! It is exactly similar to the TIMER0 CTC Mode! Just go through the datasheet and you are through!!

Well, that’s all for CTC Mode. I hope you enjoyed reading it! In the next post, we will discuss the different PWM modes and how to generate them. :)

So till then, subscribe to my blog to stay updated! Alternatively, you can also grab the RSS Feeds for that!

Thank You! :)

Mayank Prasad
mayank.vitu@gmail.com
About these ads

85 responses to “AVR Timers – CTC Mode

We'd love to hear from you!

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s