Friday, August 12, 2011

AVR timers do more than count time

Probably Timer/Counters are complex peripherals in microcontrollers, but as fact they are most commonly used no matter what complexity program is. Designers of timers have put a lot of thought in them making them very flexible, versatile for all timing dependent tasks like measuring time periods, generating PWM signals, generating output signals and timed interrupts.

Timers run independently from AVR core. Once set, they just do their silent job while AVR can do other tasks or simply go to sleep. AVR can read timer values, or changeoperation modes when ever it needs or simply can be interrupted with several available interrupts. If you see application where frequency is measured, music is generated or motor is driven – there is definitely timer involved.

8 bit and 16 timers

AVR microcontrollers usually have three or even more timers. Atmega328 (also ATmega48, ATmega88 and Atmega168) has two 8-bit timers and one 16-bit timer. Each of them can be configured individually with different rates and functions. Like, one can generate PWM, other measure count pulses, and third debounce buttons. Simply speaking 8 bit timers can count up to 255 counts while 16 bit timer can count to 65365. Once these values are reached, timers start over from 0. This is called timeroverflow. All of these can be set with some thresholds to trigger interrupts. Usually thresholds are set with Output Compare Registers OCR. When set timer will count and compare its current value with OCR and if match – timer will generate an interrupt.

Speaking of timers all three have partially similar functionality and also each contain special functions. So we can’t apply same approach to all of them. So wee will need to discuss them separately later.

Timer/Counter clock sources

Before getting to more details lets discuss one important vital part of timers – clock source. In order to make timer count we need to provide it with clock source. Generally speaking all timers can count synchronously to AVR core and asynchronously. Synchronous counting means that timer is tied to FCPU clock source directly or prescalled. If microcontroller is clocked with 16MHz crystal then timer ticks according to this source. In asynchronous counting mode timer is clocked from external clock source: T0 pin for Timer/Counter0, T1 pin for Timer/Counter1 and TOSC1 pin for Timer/Counter2.

Speaking of Timer/Counter2 – it can be set to run as Real Time Clock (RTC) with external 32.768KHz crystal.

Timer/Counter prescallers

Prescaller simply speaking is a 10-bit binary counter that scales down clock source by dividing frequency by power factor of 2. This way can have longer time counts but we sacrifice a resolution for this. For instance lets take a self descriptive image of Atmega328 TimerCounter2 prescaller.

You can see that no matter what timer clock source is selected it goes through prescaller part where it can divided by 8, 32, 64, 128, 256, and 1024. which prescaling factor is selected depends on bits CS20, CS21 and CS22 set in TCCR2B. For other timers this is pretty similar.

With prescallers you can have longer counting times and this way avoid intervention of software to prolong counting with program counters. For instance, if MCU is clocked at 1MHz without prescaller counter fills up to 255 value very fast – in 256µs, while with prescaller 1028 it will fill up in ~0.26s. It is easy to calculate these values if you know what timer resolution is. Simply speaking – resolution is a smallest time period of one timer count. It can be easily calculated by using simple formula:

Resolution=1/Frequency

So if microcontroller is clocked with 1MHz source, then 8 bit timer without prescaller will run with resolution:

Resolution=1/1MHz=1µs

so if timer is counts 256 ticks until overflow then it takes:

T=Resolution*Ticks=1µs*256=256µs

If we use 1024 prescaller we get:

Resolution=1/(Frequency/Prescaler)=Prescaller/Frequency=1024/1MHz=1024µs;

Then to count up to overflow takes:

T=Resolution*Ticks=1024µs*256=0,262144s=~0.26s

If you need higher resolution and longer times then consider using 16-bit timer or do this with help of firmware.

Timer interrupts in AVR

This tutorial will teach you about the 8 and 16 bit timers on an ATmega168 microcontroller. Because the ATmega168 is very similar to the ATmega48, ATmega88 and ATmega328, the examples should also work on these. For other AVR microcontrollers the general principles will apply but the specifics may vary.


Timer interrupts on an atmega168 microcontroller

What are the 8 and 16 bit timers?

Consider a wrist watch. At regular intervals it ticks and the hand moves to the next number. At any point in time you can read the accumulated count (the time) and once the time reaches a certain threshold, an event occurs (the alarm rings). Timers on AVR microcontrollers are a little like this.

The ATmega168 has two 8-bit and one 16-bit timers. This means that there are 3 sets of counters, each with the ability to count at different rates. The two 8-bit counters can count to 255 whilst the 16 bit counter can count to 65,536.

When the counters reach certain thresholds we can trigger interrupts, which cause Interrupt Service Routines (ISRs) to be executed. Timers are very handy because they allow operations to run automatically, independently of the main processing thread.

8 bit timer registers

The ATmega168 has 2, 8-bit timers: Counter0 and Counter2. Each of these timers are controlled by the following registers.

Counter0Counter2Description
TCCR0ATCCR2ATimer/Counter Control Register A
TCCR0BTCCR2BTimer/Counter Control Register B
TCNT0TCNT2Timer/Counter Register
OCR0AOCR2AOutput Compare Register A
OCR0BOCR2BOutput Compare Register B
TIMSK0TIMSK2Timer/Counter Interrupt Mask Register
TIFR0TIFR2Timer/Counter Interrupt Flag Register

We’ll focus on Counter0 and the most commonly used registers.

Each counter has 2 thresholds. for Counter0 these are stored in registers OCR0A and OCR0B. When these threshold are reached “something” happens. This “something” is defined in TCCR0A, TCCR0B and TIMSK0. TCCR0B also allows you to set the rate at which the timer is updated.

TCCR0A and TCCR0A are shown below.

bit76543210
TCCR0ACOM0A1COM0A0COM0B1COM0B0--WGM01WGM00
Read/WriteR/WR/WR/WR/WRRR/WR/W
Initial Value00000000
bit76543210
TCCR0BFOC0AFOC0B--WGM02CS02CS01CS00
Read/WriteWWRRR/WR/WR/WR/W
Initial Value00000000

WGM02, WGM01 and WGM00 control the counter’s mode as shown in the table below.

ModeWGM02WGM01WGM00Description
0000Normal
1001PWM, Phase Correct
2010Clear Timer on Compare (CTC)
3011Fast PWM
4100Reserved
5101PWM, Phase Correct
6110Reserved
7111Fast PWM

We’ll focus on the normal and CTC modes. A detailed discussion of timer modes can be found in section 14.7 of the ATmega168 datasheet.

COM0A1, COM0A0, COM0B1 and COM0B0 control the behavior of the OC0A (PD6) and OC0B (PD5) pins. These pins can be controlled from the Output Compare Registers (OCR0A/OCR0B). The settings depend on the modes being used and is outside the scope of this tutorial. Section 14.9.1 of the ATmega168 datasheet describes these bits in detail.

An ATmega168 with default fuses runs at 8MHz with the system clock prescaler enabled. This means that the timer can be updated, up to 8,000,000 times per second. By setting CS02, CS01 and CS00 we can slow down this rate, as shown here.

CS02CS01CS00Description
000No clock source (Timer/Counter stopped)
001Clock(No prescaling)
010Clock/8 (From prescaler)
011Clock/64 (From prescaler)
100Clock/256 (From prescaler)
101Clock/1024 (From prescaler)
110External clock source on T0 pin. Clock on falling edge.
111External clock source on T0 pin. Clock on rising edge.

TIMSK0 controls which interrupts are enabled. Each counter has 3 interrupts, one for each Output Compare Register (threshold) and one for overflow. The full list of available interrupts can be found in the AVR libc Interrupts Documentationunder the section labelled “Choosing the vector: Interrupt vector names”.

bit76543210
TIMSK0-----OCIE0BOCIE0ATOIE0
Read/WriteRRRRRR/WR/WR/W
Initial Value00000000

8 bit timer example

In this example we run run a sweep of the 8 red LEDs on the main routine. We will then blink the green LED on/off 4 times every second. The circuit diagram and source code is shown below.


Example circuit for atmega168 interrupts

  1. #include
  2. #include
  3. #include
  4. #define green_led_on() PORTC |= _BV(0)
  5. #define green_led_off() PORTC &= ~_BV(0)
  6. #define green_led_is_on() bit_is_set(PORTC,0)
  7. int main (void)
  8. {
  9. DDRB = 0b11111111; // All outputs
  10. DDRC = 0b01111111; // All outputs (Although we will just use PC0 )
  11. TIMSK0 = _BV(OCIE0A); // Enable Interrupt TimerCounter0 Compare Match A (SIG_OUTPUT_COMPARE0A)
  12. TCCR0A = _BV(WGM01); // Mode = CTC
  13. TCCR0B = _BV(CS02) | _BV(CS00); // Clock/1024, 0.001024 seconds per tick
  14. OCR0A = 244; // 0.001024*244 ~= .25 SIG_OUTPUT_COMPARE0A will be triggered 4 times per second.
  15. sei();
  16. while(1)
  17. {
  18. sweep();
  19. }
  20. }
  21. void sweep()
  22. {
  23. PORTB = 0b10000000;
  24. for (int i=0;i<8;i++)
  25. {
  26. _delay_ms(100);
  27. PORTB >>= 1;
  28. }
  29. }
  30. ISR(SIG_OUTPUT_COMPARE0A)
  31. {
  32. if (green_led_is_on())
  33. green_led_off();
  34. else
  35. green_led_on();
  36. }

Line 15 sets the CTC mode. This ensures that the counter is reset when it reaches OCR0A. After we have setup the timer registers, we call sei() to enable the global registers.

On line 37, you will see “ISR(SIG_OUTPUT_COMPARE0A)”. This is the interrupt service routine and will get called each time the interrupt is triggered.

8 bit timer example 2 – Dual interrupts

In this example we will use TimerCounter0 Compare Match A and Match B interrupts. We we turn the LED on at Match B and off at Match A. This will produce the following waveform.


Timing diagram for timer interrupt example

  1. #include
  2. #include
  3. #include
  4. #define green_led_on() PORTC |= _BV(0)
  5. #define green_led_off() PORTC &= ~_BV(0)
  6. int main (void)
  7. {
  8. DDRB = 0b11111111; // All outputs
  9. DDRC = 0b01111111; // All outputs (Although we will just use PC0 )
  10. TIMSK0 = _BV(OCIE0A) | _BV(OCIE0B); // Enable Interrupt TimerCounter0 Compare Match A & B (SIG_OUTPUT_COMPARE0A/SIG_OUTPUT_COMPARE0A)
  11. TCCR0A = _BV(WGM01); // Mode = CTC
  12. TCCR0B = _BV(CS02) | _BV(CS00); // Clock/1024, 0.001024 seconds per tick
  13. OCR0A = 244; // 0.001024*244 ~= .25 SIG_OUTPUT_COMPARE0A will be triggered 4 times per second.
  14. OCR0B = 220; // 0.001024*220 ~= .225 SIG_OUTPUT_COMPARE0B will be triggered 25ms before SIG_OUTPUT_COMPARE0A
  15. sei();
  16. while(1)
  17. {
  18. sweep();
  19. }
  20. }
  21. void sweep()
  22. {
  23. PORTB = 0b10000000;
  24. for (int i=0;i<8;i++)
  25. {
  26. _delay_ms(100);
  27. PORTB >>= 1;
  28. }
  29. }
  30. ISR(SIG_OUTPUT_COMPARE0A)
  31. {
  32. green_led_off();
  33. }
  34. ISR(SIG_OUTPUT_COMPARE0B)
  35. {
  36. green_led_on();
  37. }

16 bit timer

The ATmega168 has a single 16 bit timer, which is referred to as Counter1. It works like the 8 bit timer, except the counter has more bits in it. This intervals to be set with longer duration and greater precision. The registers used by this timer are:

Counter1Description
TCCR1ATimer/Counter 1 Control Register A
TCCR1BTimer/Counter 1 Control Register B
TCCR1CTimer/Counter 1 Control Register C
TCNT1HTimer/Counter 1 High Register
TCNT1LTimer/Counter 1 Low Register
OCR1AHOutput Compare Register 1 A High
OCR1ALOutput Compare Register 1 A Low
OCR1BHOutput Compare Register 1 B High
OCR1BLOutput Compare Register 1 B Low
ICR1HInput Capture Register 1 High
ICR1LInput Capture Register 1 Low
TIMSK1Timer/Counter Interrupt Mask Register
TIFR1Timer/Counter Interrupt Flag Register

In some ways this list looks like the registers used by the 8 bit timers. We will now examine the important differences.

TCCR1A, TCCR1B and TCCR1C play a similar role to TCCR0A and TCCR0B. These are shown below.

bit76543210
TCCR1ACOM1A1COM1A0COM1B1COM1B0--WGM11WGM10
Read/WriteR/WR/WR/WR/WRRR/WR/W
Initial Value00000000
bit76543210
TCCR1BICNC1ICES1-WGM13WGM12CS12CS11CS10
Read/WriteR/WR/WRR/WR/WR/WR/WR/W
Initial Value00000000
bit76543210
TCCR1CFOC1AFOC1B------
Read/WriteR/WR/WRRRRRR
Initial Value00000000

Some of the differences include

  • 4 mode bits instead of 3 (ie more modes)
  • The Force Output Compare bits are in TCCR1C
  • Input Capture Noise Canceler bit in TCCR1B (outside the scope of this tutorial)
  • Input Capture Edge Select in TCCR1B (outside the scope of this tutorial)

TCNT1H and TCNT1L are similar to TCNT0, but being a 16 bit counter they are split across 2 registers. Similarly with OCR1AH,OCR1AL, OCR1BH and OCR1BL.

ICR1H and ICR1L don’t have any equivalent in the 8 bit timers and allow you to capture the timer value on certain events.

16 Bit example

This example is similar to the previous one. Because we are using the 16 bit timer, we can increase the cycle time.

  1. #include
  2. #include
  3. #include
  4. #define green_led_on() PORTC |= _BV(0)
  5. #define green_led_off() PORTC &= ~_BV(0)
  6. int main (void)
  7. {
  8. DDRB = 0b11111111; // All outputs
  9. DDRC = 0b01111111; // All outputs (Although we will just use PC0 )
  10. TIMSK1 = _BV(OCIE1A) | _BV(OCIE1B); // Enable Interrupt Timer/Counter1, Output Compare A & B (SIG_OUTPUT_COMPARE1A/SIG_OUTPUT_COMPARE1B)
  11. TCCR1B = _BV(CS12) | _BV(CS10) | _BV(WGM12); // Clock/1024, 0.001024 seconds per tick, Mode=CTC
  12. OCR1A = 1954; // 0.001024*1954 ~= 2 SIG_OUTPUT_COMPARE1A will be triggered every 2 seconds
  13. OCR1B = 1929; // 0.001024*1929 ~= 1.975 SIG_OUTPUT_COMPARE1B will be triggered 25ms before SIG_OUTPUT_COMPARE1A
  14. sei();
  15. while(1)
  16. {
  17. sweep();
  18. }
  19. }
  20. void sweep()
  21. {
  22. PORTB = 0b10000000;
  23. for (int i=0;i<8;i++)
  24. {
  25. _delay_ms(100);
  26. PORTB >>= 1;
  27. }
  28. }
  29. ISR(SIG_OUTPUT_COMPARE1A)
  30. {
  31. green_led_off();
  32. }
  33. ISR(SIG_OUTPUT_COMPARE1B)
  34. {
  35. green_led_on();
  36. }

On line 15 and 16, where we set the value for the Output Compare Registers, we don’t need to set value for the high and low registers. The AVR Libc
library
abstracts these as a single 16 bit value.

More Information

I hope you’ve enjoyed this tutorial. Timers are a complex subject and I have tried to keep them simple by just looking at a slice of what they can do. I encourage to read the documentation and experiment. I’ve listed 2 good resources below.

AVR libc Interrupts Documentation
ATmega48/88/168/328 datasheet