Introduction to timers [tutorial part 6]

Goodnight fellow reader, today I will talk a bit about timers, they are super useful and usually they give a lot of headaches to the newbies and the not so newbie user. Timers are used to count time, and can be used to generate precise delays, make a stable “heart-beat” to our application or can be used to generate pwm signals, all handy stuff that we can use.
Timers have the advantage of being implemented in hardware so they can run asynchronous from our code, this is like a very simplified multi-tasking, but permits us to off-load some work from the processor to the timers hardware, the Atmega328p present in the Arduino as 3 timers, timer 0, timer 1 and timer 2, they have a fundamental difference between them, timer 0 and timer 2 are 8 bits timers, this means that they can count up to 255, instead timer 1 is a 16 bits timer and can count up to 65535. Timers are also very complex and have lots of registers that can be configured in many ways so when using them its mandatory to open the datasheet.

The clock source of the timers is always tied to the frequency that our AVR runs, in the Arduino case they have a base frequency of 16Mhz, but we can use prescalers (a piece of hardware that can divide the source clock), and in the case of the timers this prescaler can be either 1, 8, 64, 256 or 1024. Having this wide range of prescallers permits us to have a ratter big range of frequencies and that’s always a good thing to ear.

The timers have different operating modes, the 4 major ones are phase correct PWM, fast PWM, CTC(Clear Timer on Compare Match) and normal mode, that is well acting as a simple counter, then depending if we are using 8 or 16 bits timer there are sub-modes but they all do the same, but in different ways. All timers have associated with them three registers, TOP, BOTTOM and MAX that can be used for example to change the frequency when in PWM mode, but I will talk about that latter. TOP defines the maximum value that the timer can count, it can be either the maximum value or other user defined value, varies with the selected mode, BOTTOM is the minimum value and its always 0(zero), we can change BOTTOM instead of TOP but that as some limitations so we just leave BOTTOM untouched, and MAX is always the maximum value that a timer can count to,  in the 16 bits timer its 65535 and in the 8bits timers its 255.

I will divide this tutorial in two parts, in this first part I will talk about the normal and the CTC modes, and in the second part I will aboard the PWM modes and how to control some leds and servos with it.

Lets dive into the normal and CTC modes then, so lets do something simple and easy like another blinky but this time we will use the timers and not any sort of software delays like _delay_ms(), as we are using timers, we need to do some maths first to setup our timers so they will count up to where we want. In this example I will not even use interrupts, I will just poll the timer register and see when the desired elapsed time is meet and then just toggle the led and do it all over again.
We will toggle the led at a rate of 2Hz, this means that the led will be on for 500ms and off for another 500ms, as our system clock is 16Mhz, and the biggest timer that we have can only count up to 65535 this means that we could only measure up to:

1/16Mhz = 0,0000000625s  //This is our timer resolution
0,0000000625 * 65535 = 0,0040959375s, a little bit more than 4ms

As you can see the 16Mhz clock is too fast so we must use the prescalers to reduce the clock that is feed to the timer, so lets do a little table to see what are the possible timer resolutions when using all the available prescaler values:

Timer resolution = (Prescaler / Input frequency)
Prescaler values can be  1, 8, 64, 256 or 1024
And the input frequency is 16Mhz.

Prescaler valuer | Timer resolution
1                | 0,0000000625s = 62,5 nS
8                | 0,0000005s = 0,5uS
64               | 0,000004s = 4uS
256              | 0,000016s = 16us
1024             | 0,000064s = 64uS

So using prescalers we have a much larger choice of frequencies, now lets see what value do we need to put in our timer to have an exact delay of 500ms(2Hz) to do our new blinky, to do that we will use a little handy formula that can be easily derived from the datasheet:

Target Timer Count = (((Input Frequency / Prescaler) / Target Frequency) - 1)

Input frequency is 16Mhz
Target frequency is 2Hz

Prescaler value | Target timer count
1               |    7999999
8               |    999999
64              |    124999
256             |    31249
1024            |    7811,5

As the maximum value that the 16 bits timer can handle is 65535 the first three values can be discarded as they will not fit in the 16bits register, also the last value is fractional so although it can be used it will drift over timer and accumulate large errors, this leaves us with the forth value that in conjunction with the 256 prescaler will give us a perfect 2hz delay, so lets start with the pseudo-code to make this new timer based blinky!

#include <avr/io.h>

int main(void){

   //Set led as output
   //Configure timer

   for(;;){
      //Read timer value and act according with it
   }

   return 0;
}

As we are doing all the maths for a 16 bits timer, this means that we have to use Timer/Counter 1 of the Atmega, all the information about this timer is in page 114 and followings in the datasheet.
As I already said, one thing that we need to configure is to put our timer in normal mode, then select the prescaler values and then turn the timer on.

#include <avr/io.h>

int main(void){

   DDRB = (1<<PB5);       //Set PB5 as output

   //Configure timer
   TCCR1B = (1<<CS12);    //1:256 prescaler

   for(;;){
      //Read timer value and act according with it
      if(TCNT1 >= 31249){      //Our pre-calculated timer count
         PORTB ^= (1<<PB5);    //Toggle the led state
         TCNT1 = 0;            //Reset the timer value
      }
   }

   return 0;
}

And that’s it, using a timer in normal mode is very very easy, all we need to do is to set up the pre-calculated prescaler value that permits us to get the desired frequency and then we just read the timer value until it gets up to our desired count, do what we want to do and reset the timer to have a stable time base.
The prescalers value are set using the bits CS12, CS11 and CS10 in the TCCR1B register, those are related to the prescaler values like this:


CS12    CS11    CS10      Prescaler
  0       0       0       Timer off/no clock source
  0       0       1       1:1 prescaler/this is the same as not having prescaler
  0       1       0       1:8 prescaler
  0       1       1       1:64 prescaler
  1       0       0       1:256 prescaler
  1       0       1       1:1024 prescaler

So, the desired prescaler was 256 so we only need to set the CS12 bit and leave the rest untouched. As usual and because our micro-controller as an 8 bits architecture we cant really read or write a 16 bits value like we are doing to read the actual timer value and to reset it, in fact TCNT1 is not a real register, instead it is a “short-cut” that the AVR Lib-C provides us, and when we read this register we are in fact reading the real TCNT1H and TCNT1L registers, those are the high and low registers that form the 16 bit word that is the timer count, its like the ADCW “short-cut” and is handy to write cleaner code.

Now I will explain how to use another way to use timers, in this way we will use interrupts instead of constantly polling(reading) the timer count to decide what to do. Interrupts are a nice capability of most micro-controllers. An interrupt is a signal that is generated for example when our timer reaches the desired count and when the micro-controller gets that signal it stops what it was doing, services the interrupt and then go back to what he was doing before the interrupt, this can be saw as a multi-tasking behaviour, as our micro-controller can execute a big and heavy main loop and then service interrupts to (for example) refresh an lcd at a desired frame-rate or to do multiplexing of displays or leds, and mantain constant refresh times, and many other uses.

The interrupt is served/attended in a special function called interrupt service routine, this functions is not called by us coders in our code, but by signals generated inside the micro-controller, so we just create the special function, configure the timer and our micro-controller will handle the rest. There are some caveats about using interrupts that you should know right now, one NEVER uses delays inside interrupts, interrupts are supposed to be fast and clean, delaying inside an interrupt means that you are doing it in the wrong way, also, it is good practice to not call functions inside interrupts, due to the overhead introduced by the called functions, so remember, interrupts should be kept clean. If you want to have a complex program that works say every 10ms, it is better set a flag in the interrupt service routine and then use the flag in the main loop to know if the interrupt as already fired or not, and last but not least EVERY variable that is shared between interrupts and any other functions must be declared as volatile, for example:

int variable1 = 0;    //This is not a volatile variable and should no be used as a shared variable
volatile int variable2 = 0;    //This is a volatile variable as you can see by the means of the volatile keyword

To create an interrupt function there is also a special method to do them, they are declared using a special keyword and they accept as argument the interrupt vector/name, the vector names can be found in the section 11 of the manual, page 58, called Interrupts, to the provided vector names in the table we need to add the _vect keyword and replace all the spaces by _, let me show you how to do it, also interrupt service routines don’t have any return so if you need information back from an interrupt use a global variable declared as volatile, or use pointers:

ISR(TIMER0_COMPA_vect){            //This is an interrupt service routine for the TIMER0 COMPA vector
   //Put your code here
}

To finalize this crash-course about interrupts, you need to configure them, as usual, because almost every peripheral of our micro-controller can generate interrupts, so, things like all the 3 timers, the ADC, the USART, the SPI interface, the I2C interface, external interrupts from IO pins and some other things can all generate interruptions, and we also need to enable global interrupts, this is like a switch in the micro-controller that says if we can service the generated interrupts or not.

We will now use our timer in CTC mode, in this mode the timer counts up to a pre-programmed value, and then it generates an interrupt, resets itself and starts again counting from 0, all this is done in hardware so this free’s up our micro to do more important tasks than setting a timer back to 0 again. Again we will be doing the blinky program with the same 2hz frequency as the one made using the timer in normal mode.
Lets start with the pseudo-code:

#include <avr/io.h>

int main(void){

   //Configure led pin
   //Configure timer in CTC mode
   //Enable global interrupts, so our interrupt service routine can be called
   //Enable timer interrupts

   for(;;){
      //Our infinite loop, this will remain clean, everything is done in the interrupt
   }

   return 0;
}

ISR(){        //This is our interrupt service routine

   //Toggle led state
}

As the led stuff is trivial, lets talk a bit more about how to put the timer in CTC mode, the various modes of operation of the timer 1(and for reference, also timer 0 and timer 2 work in this same way) are set by 4 bits, 2 in the TCCR1A and 2 in the TCCR1B register, this 3 bits, called WGM13, WGM12, WGM11 and WGM10 define the mode of the timer and are described in table 15.4 (waveform generation mode), in page 137 of the Atmega328P datasheet, as we want CTC mode, we only need to set the WGM12 bit in the TCCR1B register and them instead of comparing the desired count in the timer count register, we set our desired count in one of the two compare registers of timer 1, this registers accept a 16 bits value, and does the hardware compare with the actual timer count, and when they are equal they call the interrupt and clear the timer count, as the TCNT1 register they can also be accessed via 2 registers called OCR1AH and OCR1AL, OCR1BH and OCR1BL, or by the handy OCR1A and OCR1B short-cuts.
We also need to enable timer interrupts, this is like a local switch that says to our micro-controller if and which parts of our timer can generate interrupts, in this example we only need to set one bit of this register, the OCIE1A, this bit says that we want interrupts when there is a compare match with the value saved in the OCR1A register, and we set this bit in the TIMSK1 (Timer1 Interrupt mask register) register.
Lets then put this information in the code:

#include <avr/io.h>

int main(void){

   DDRB = (1<<PB5);    //Configure led pin

   //Configure timer in CTC mode
   TCCR1B = (1<<WGM12)|(1<<CS12);    //Enable CTC mode, and set prescaler to 1:256
   //Enable timer interrupts

   //Enable global interrupts, so our interrupt service routine can be called

   for(;;){
      //Our infinite loop, this will remain clean, everything is done in the interrupt
   }

   return 0;
}

ISR(){        //This is our interrupt service routine

   PORTB ^= (1<<PB5);    //Toggle led state
}

As we are using the CTC mode this means that we must put our desired count in the OCR1A register, this is shown in the waveform generation mode table, and thus our interrupt service routine will be the one related to this register, and is called TIMER1_COMPA_vect, COMPA because its the OCR1A register.

To enable the interrupts we just need to call sei() or cli() to respectively enable interrupts(sei means set interrupts) and disable interrupts(cli means clear interrupts), those are functions that are defined in the interrupts library and that’s why we need to include it, so lets complete the code:

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

int main(void){

   DDRB = (1<<PB5);    //Configure led pin

   //Configure timer in CTC mode
   TCCR1B = (1<<WGM12)|(1<<CS12);    //Enable CTC mode, and set prescaler to 1:256
   OCR1A =  31249;            //sets the desired count to generate the 2Hz signal
   TIMSK1 = (1<<OCIE1A);        //Enable timer interrupts

   sei();    //Enable global interrupts, so our interrupt service routine can be called

   for(;;){
      //Our infinite loop, this will remain clean, everything is done in the interrupt
   }

   return 0;
}

ISR(TIMER1_COMPA_vect){        //This is our interrupt service routine

   PORTB ^= (1<<PB5);    //Toggle led state
}

Now its just a matter of compiling the code, and to upload it to your board and see the led blinking.

I will now show even another way to do our blinky by creating the useful milis functionality provided by the Arduino, this is also a way to show how to use variables shared in the main program and by an interrupt service routine, and also how to use another timer. I will use timer 0 for this, because I want a 1 mili-second signal, this means a frequency of 1Khz so, there is no need to waste the 16 bits timer when an 8 bits timer is enough to this job, so lets calculate what will be our timer and count value.

Target Timer Count = (((Input Frequency / Prescaler) / Target Frequency) - 1)

Input frequency is 16Mhz
Target frequency is 1000Hz or 1Khz

Prescaler value | Target timer count
1               |    15999
8               |    1999
64              |    249
256             |    61,5
1024            |    14,625

As you can see only the 1:64 prescaler gives us an integer value, the 1:256 and 1:1024 both gives us fractional values and those will accumulate errors with time, so its better to avoid them, so lets use the 1:64 prescaler and use 249 as the compare value, we will again use the timer in CTC mode, due to its clean work. So lets jump to the timer 0 section of the datasheet and see how to put our timer in the CTC mode.

The 8 bit timer 0 section is number 14, and starts at page 98, from there we go to subsection 9 where all the registers are explained bit by bit (literally), and just like timer 1 there is also a waveform generation table but this is one is much smaller, this is because well the timer is also smaller, and again we only need to set one bit to enable CTC mode, in this case its the WGM01 in the TCCR0A register, the prescaler will be set to 1:64 by setting both CS01 and CS00 in the TCCR0B register, the desired compare count will be stored in OCR0A register, and then we need to again enable compare match interrupts, but now its the OCIE0A bit that needs to be set in the TIMSK0 register because we are working now with the timer 0, finally the interrupt vector name is TIMER0_COMPA_vect, lets get all this together!


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

void timer0_init(void);        //Function prototype

volatile unsigned long milis = 0;    //This is our shared volatile variable that will be used as the milis count
unsigned long now = 0;

int main(void){

   DDRB = (1<<PB5);        //Set the pin as an output
   timer0_init();

   for(;;){
      if(milis-now >= 500){
         now = milis;
         PORTB ^= (1<<PB5);    //Toggle the led at every 500ms/0.5s/2hz
      }
   }
   return 0;
}

void timer0_init(void){

   TCCR0A = (1<<WGM01);        //Timer in CTC mode
   TCCR0B = ((1<<CS01)|(1<<CS00));    //1:64 prescaler
   OCR0A = 249;            //Value to have an compare at every 1ms
   TIMSK0 = (1<<OCIE0A);        //Enable timer interrupts
   sei();                //Enable global interrupts
}

ISR(TIMER0_COMPA_vect){

   milis++;    //Increase milis count by one millisecond
}

This code is like the blinky without delay that you can find in the Arduino IDE, just done bare-metal.

And you can download the Avr Studio project here:

http://code.google.com/p/avr-tutorials/downloads/detail?name=milis.zip

Thanks for reading my blog and happy coding!!!

About these ads

18 responses to “Introduction to timers [tutorial part 6]

  1. Another excellent tutorial! Thank you for taking the time to make these amazing tutorials. I started tinkering with an Arduino Mega 1280 about a month ago and have learned a great deal from your site. Please keep up the outstanding work. Thanks again!

    • Thanks for the compliments mr. Welshde, its always nice to hear that my tutorials are helping you.
      I will keep posting them here and also keep your good work with the Atmega1280.

  2. Hi, Im playing with the incapture register and im having problems with switching the edge during a measure of distance. Will you write anything about incapture register?

  3. Thank you for the tutorial. As everyone else, I’ve learned great deal from the last 3 posts on these topic. I am impressed that you’ve managed to explain the complicated concepts involving AVR in such simple to understand manner.

    I would very much like to know if the tutorials on PWM is still on the way?
    Again, thank you.

    • Thanks for your comment anaon, yes the PWM tutorial is on its way.
      I always try to keep my writing simple and easy to understand and I’m glad that I’m managing to do that and that people can learn from reading the tutorials.

  4. Thank you so much for these tutorials! I just went through all of them and learned an immense amount in a short time. However, I would like to know where you learned all these things. For example where did you learn the functionalities of all the libraries, or is there another source which contains all the register info besides the datasheet that also explains everything nicely? Things like that. Thanks again.

    • Goodnight, I have learn programming in some classes from the university and I also learn a lot by myself at home, googling and toying around with my projects, that I need to some day put online, one good reference for programming is the manual of the C compiler for the avr’s:
      http://www.nongnu.org/avr-libc/user-manual/pages.html

      And also googling for what I want to do, but in some cases I end reading the datasheet two or three times and them trying until it works.

      • Thanks for showing me that site.
        Also, I’m not sure if you mentioned it in your tutorials, but did you know that you can download the AVR C code into the Arduino using the Arduino IDE? It saves you the hassle of downloading AVR studio and going through the command line process.

  5. For part 7 could you talk about interrupts?

  6. These are the best tutorials online for someone who wants to switch from arduino to AVR. Please keep up the good work, having a blast with these tuts!…Cheers!!

  7. thanks for this explanations

    I just triedthe sourcecodeexample of

    http://www.electronicsplanet.ch/mikrocontroller/avrcodesammlung/atmega16timer0fastpwm.htm

    and it worked. but thanks to you i underrstand, why it works ;-)

  8. Thanks a huge lot… it’s helped me tremendously… superb work…

  9. Never use this trick (AVR – thanks to God – is not PIC 16F84!):
    if(TCNT1 >= 31249){ //Our pre-calculated timer count
    PORTB ^= (1<<PB5); //Toggle the led state
    TCNT1 = 0

  10. thank you for such a smooth explanation.
    the best tutorial i’ve seen on this topic

Leave a Reply

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