About Me

Pilani, Rajasthan, India
I am an engineering student currently pursuing an undergraduate degree in Electronics & Instrumentation from BITS Pilani, Pilani campus. My hobbies are reading novels- fiction and non-fiction alike, playing and watching football, dabbling with new software and going through blogs. I love reading Electronics For You. It has helped me a lot in my college life. And sometimes, people around me.

Hope you find this blog useful. Thank you.
Showing posts with label AVR. Show all posts
Showing posts with label AVR. Show all posts

Friday, August 5, 2011

Timers in AVR - A basic introduction


Hello all. Back to Pilani, for one last time J Anyway, in this post, I shall be introducing the concept of Timers using ATmega32/16. So if you don’t like using those fancy delay functions that the IDEs provide or simply, want to create your own delay function, this post might be a good start.

So what are Timers?

Needless to say, Timers are those circuits in your controller that allow you to keep track of time. Any time-related activity – like the blink effect in your blinking LED, the rotation of your motor for precisely 5 seconds, those beautiful lighting patterns that you see in Diwali lightings - takes place because of timers in your controller.

Why do I need to know about Timers?

Yes, every IDE has a library that contains delay functions that you can use. But if you are a curious user, you will want to know as to what is happening when you say you want a delay of 1000ms. Or you will want to know why the function can’t give you a delay above a certain fixed value.
Yet another reason – if you want to implement Pulse Width Modulation (PWM), knowledge of timers is essential. So, it is time to ‘time’! Let us begin.

Basic Concept

First of all, you need to know that the clock of your controller may or may not be the same as that of your timer. This simply means, that the rate at which your CPU executes instructions can be different from the rate at which the timer times. Timing is done with the help of a counter register that counts up to its maximum possible value and then again goes to zero, only to repeat the entire cycle. Checking the value of this register against a particular value helps you to achieve the desired delay. The methods of timing differ in the method of checking this value, as described below.

Timers in ATmega32/16

One look at the ATmega32/16 datasheet tells that it has two 8-bit timers and one 16-bit timer. 8-bit and 16-bit refers to the size of the counter register. The counter of the 8-bit timer can count up to 255 (28 – 1) before resetting to 0 and the counter of the 16-bit timer can count up to 65535 (216 – 1) before resetting to 0.
I will be talking about the 8-bit counter named Timer/Counter0, as it is easier to work with than the 16-bit timer. First, I will explain the crude method of checking the register value with an ‘if’ condition. And second, I will explain the ‘Clear on Timer Compare’ (CTC) Mode.

Crude Method

I call this the crude method because it is the easiest method and involves no software complexity. The steps involved in timing using this method are:
      1)      Enable the timer
      2)      Decide the timer frequency
      3)      Decide the delay needed
      4)      Calculate the counter value that corresponds to the desired delay
      5)      Use this value in the ‘if’ condition in your program

Enable the timer

Looking at the register description for this timer/counter, on Page 80 of the datasheet, we see that the lowermost three bits of the register TCCR0 are involved in the enabling process. The table on Page 82 tells that to enable the timer, we need to write a ‘1’ to the CS00 bit of TCCR0 register. The corresponding code is:
TCCR0 |= (1<<CS00);

Decide the timer frequency, delay and calculations

As mentioned in the post, the clock of the timer and the CPU may or may not be the same. And this facility is extended to us by the presence of ‘prescaler circuits’ in the controller. These circuits enable us to scale down the CPU frequency (F_CPU) by 8, 64, 256 and 1024 times. For instance, if we are using a prescaler of 64 and F_CPU is 1MHz, then the timer will not see each period of the CPU as 1µs but as 64µs. Therefore, the increment in counter register that would have happened after 1µs will now take place after 64µs. That is, the frequency has been scaled down by 64 times. As a result, longer delays can be realized without the need of an external clock.
Suppose we wish to blink an LED at a frequency of approximately 5 Hz i.e. goes on-off at every 0.2 seconds. We have been given that F_CPU is 1MHz. We have to keep in mind that our counter can’t count above 255. With proper calculation, we see that using a prescaler of 1024 and checking the counter for a value of 199 will do the job roughly.

Calculation: 1µs * 1024 * 200 = 0.2048 seconds.

Now, you will say – “Hey! That’s not right...I need precision.” Well then, you will have to use the 16-bit timer/counter. In that case, you can use a prescaler of 8 and the counter value to be checked is 25000-1 = 24999.

Calculation: 1µs * 8 * 25000 = 0.2 seconds.

Note: The value to be checked is 1 less than the number of counts because the counter starts counting up from 0, not 1.

Code: For 8-bit timer/counter0, register involved for prescaling is TCCR0 and bits are CS02, CS01 and CS00. The table tells that writing a ‘1’ to CS02 and CS00 enable the 1024 prescaler.
TCCR0 |= ((1<<CS02)|(1<<CS00));

Using the ‘if’ condition

Now that you are done with the enabling, configuration and calculations, you need to actually implement the timing effect. This is done by checking the value of the counter against the calculated value. In the 8-bit case, the counter register is named TCNT0. The calculated value in the 8-bit case above was 199.

Code: 
if(TCNT >= 199)
{
 //your code here
TCNT0 = 0;
}

Observations from the above snippet:

      1)      Using a ‘>=’ is safer than ‘==’ as it is possible that the controller will miss the exact value due to some glitch.
      2)      It is necessary to reset the timer at the end of the ‘if’ condition, otherwise you will never get the desired delay (unless the value to be checked is itself 255! :P)
Assuming that the LED is connected to PORTB0 pin, the entire code using the 8-bit counter is:

#include <avr/io.h>

int main(void)
{
    DDRB = 0b00000001;
       TCCR0 |= ((1<<CS00)|(1<<CS02)); // enabling the timer with 1024 prescaler
       // on calculation the value to be checked comes out to be 199

       while(1)
    {
       if(TCNT0 >= 199)
          {
                 PORTB ^= (1<<0); //toggling the status of pin – XOR bit operator in C
                 TCNT0 = 0;
          }            
    }
}

The code for the 16-bit timer/counter can be made on similar lines using the registers mentioned in the datasheet.

Clear on Timer Compare (CTC) Mode

In this mode of timing, the checking of the counter value with the desired value obtained from calculations is done by the hardware instead of the software i.e. the ‘if’ condition. As a result, the time wasted in executing the piece of code is saved which can be fruitful in a complex application.
The overall funda of working remains the same except that instead of an ‘if’ condition, we store the desired counter value in a particular register and as soon as the counter obtains that value, the controller  sets (writes ‘1’) a bit in a register. Hence, we just need to check the status of a bit regularly rather than compare values, which is a much heavier operation.

Registers involved

      1)      The CTC mode is enabled by writing a ‘1’ to the WGM01 bit in the TCCR0 register (See table on Page 80).
      2)      The clock frequency selection for CTC is done in the same manner as the crude method.
      3)      The register used to store the value against which the counter value is to be compared is OCR0.   Naturally, it is an 8-bit register.
      4)      The bit that is set to ‘1’ when the counter reaches the value stored in OCR0 is the OCF0 bit in the TIFR register. A very important behaviour of this bit is that to reset this bit, we have to actually write a ‘1’ to it. The circuitry is such that it requires to be set to be reset.

Code:
#include <avr/io.h>

int main(void)
{
    DDRB = 0b00000001;
       TCCR0 |= ((1<<CS00)|(1<<CS02)); // enable the timer with a prescaler of 1024
       TCCR0 |= (1<<WGM01); // enable the CTC mode
       OCR0 = 199; // store 199 into OCR0
       while(1)
    {
        if(TIFR & (1<<OCF0)) // check if bit OCF0 is set to '1'
              {
                     PORTB ^= (1<<0); // toggle status of pin PORTB0
                     TIFR = (1<<OCF0); // write a '1' to OCF0 to reset it
              }                   
    }
}

Therefore, the same timing operation carried out by the Crude Method is carried out by CTC Mode operation in a much more efficient manner.

The aim of this post was to cover the basics of timers in microcontrollers and how they work. A more detailed post on timers later J
See ya!

Sunday, June 26, 2011

Atmega32 from AVR - a beginner's guide to microcontrollers

Hello everyone. My name is Atmega32. I belong to the AVR family of Atmel’s microcontrollers. We are a very well-cultured and user-friendly family. I am the most commonly used controller for beginner robots along with Microchip’s PIC microcontrollers (though I don’t like it...it is cheap!). The reason why people so commonly use me is that a variety of development tools are available for working with me and for exploiting my features to the best. Over the years, my manufacturers have been increasing my flash memory, so that you can stuff me with bulkier and bulkier codes and hence, I can do more for you. Please learn to use me well. Some time ago, beginners tried to use me without properly reading the datasheets and learning to use the programmer. I was so angry that I just blew up in their face and got all heated up! I deserve respect and care because I am a good servant.

Applications:
So let me tell you more about how you can use me. You build a wonderfully working obstacle sensor and an oh-so-precise motor driver circuit. But what will you do, if you want your motor to rotate for precisely five seconds once an obstacle is detected. The brightest person will use a number of logic gates and a clock. His best friend will use an analogue clock and design the hardware such that as soon as five seconds pass, a switching action takes place and the complex circuitry gets an input. The dumbest person will try to cheat by keeping a button pressed on his remote for five seconds. The average person...well...he is reading this post, so you know what he will do.
Almost each embedded application – be it your cell phone, be it your printer, be it the latest iPod Touch, be it the Salmoiraghi – has some or the other controller. Robotics is just another drop in the ocean. 

Prerequisites:
1) Very basic knowledge of C/C++/Java/any programming high level language.
2) Knowledge of concepts like binary numbers, hexadecimal numbers, inter-conversion of number types, Boolean algebra.
3) Desire to practically try out what is written.

Basics:
If you are a beginner and going through my datasheet for the first time, you won’t understand much and it is OK. Just have a look at my pinout diagram. You will see that most of the pins are named like this: PXY where X=A,B,C,D and Y=0 to 7. These are known as the I/O pins of the microcontroller. The other pins Vcc, GND, Reset, XTAL1, XTAL2, AVcc, AREF. You don’t need to care about the last four as of now. As for Vcc, that’s my mouth. If you want me to survive, you have to feed me. Just feed me a 5 Volt supply and a bit of current and I will be your genie! The GND pin SHOULD be connected to the circuit ground for best results.
I will now tell you about my various parts..err..ports.As for the PXY pins – I have 4 ‘ports’ – A,B,C and D (These will replace X). Each port has 8 pins – 0 to 7 (These will replace Y).

But what does I/O mean? I belong to the digital civilization and I follow TTL logic. In simple terms, I can’t differentiate between 0.2 Volts and 0.9 Volts because both are same for me – LOW. Similarly, I can’t differentiate between 3.6 Volts and 4.9 Volts because both are same for me – HIGH.
Practically,
0 to 1.4 Volts – LOW
3.4 to 5 Volts – HIGH
My inputs and outputs are always either HIGH or LOW. If any input or output is outside these ranges, well, don’t trust me. It is not my specialty!

Basic I/O configuration:
As I mentioned, 4 ports * 8 pins each = 32 I/O pins. But how do you tell me which pin you want to use? You do it using three ‘registers’. A ‘register’, in very simple terms, is nothing but a ‘group’ of 8 bits serving a similar purpose, generally. And this ‘group’ is given a name so that you can use it in your program to convey your desire to me.
The I/O registers commonly used are:

DDRX – DDR stands for Data Direction Register. This allows you to configure your pin as Input or Output. Now let me show you how to configure. Writing the following instruction (given inside single quotes):
‘DDRA = 0b11001001;’ – binary representation of port or ‘DDRA = 0xC9;’ – hexadecimal representation of Port. (Note: The pin order is 0b76543210)
Means that you want to set the pins 7,6,3 and 0 of Port A i.e Pins PA7, PA6, PA3 and PA0 as Output pins and the other pins of Port A as Input. By default all my 32 I/O pins are configured as Input i.e DDRX = 0b00000000.

PORTX – When you want to write either HIGH or LOW to a pin, you have to use my PORTX register. There are two cases:

      1)      Pin configured as Output
Let us continue with the above configuration i.e. DDRA = 0b11001001. If you now write the instruction,
‘PORTA = 0b01000001;’
Focus only on Pins 7,6,3 and 0 which are configured as OUTPUT. A ‘0’ has been written to Pin 7 and 3 and a ‘1’ has been written to Pin 6 and 0. This means that if you connect your multimeter probes between Pin 7 and GND, the voltage will read ~0 Volts i.e. Pin 7 has been set to LOW. Same is the case with Pin 3. On the other hand, connection of probes between Pin 6 and GND results in a reading of ~5 Volts i.e. Pin 6 has been set to HIGH. Same is the case with Pin 0.

Basically, writing 1 to an OUTPUT pin sets it HIGH and writing 0 to an OUTPUT pin sets it LOW.
      
      2)      Pin configured as Input
Again, we will continue with the same pin configuration i.e. DDRA = 0b11001001. If you now write the instruction,
‘PORTA = 0b00100010;’
Focus only on pins 5,4,2,1 which are configured as INPUT. A ‘0’ has been written to Pin 4 and 2 and a ‘1’ has been written to Pin 5 and 3. There is something called a pull-up resistor. The function of this is to simply pull the potential of the pin to HIGH. And writing a ‘1’ to the input-configured pin enables this resistor. Writing a ‘0’ to an input-configured pin does not do so and hence the pin is said to be ‘floating’. This is an undesirable condition as it can pick up stray potentials from the surroundings or the breadboard and can lead to erroneous results which are hard to debug if you don’t know about this concept (Trust me!). So the good habit is to always pull HIGH an input-configured pin by writing ‘1’ to it. Or alternatively, ground the input-configured pin, when not in use.

PINX – This is the register that stores the current status of each and every pin. So, if you want to read a particular pin, say 4th pin of Port B, all you have to do is: 
      1) Write the following instruction: ‘char c = PINB;’ – This will transfer the contents of the 8 bit register PINB into the 8 bit character instance ‘c’.
      2) Since you want only the status of the 4th pin, perform a logical AND of ‘c’ with 0b00010000. What this will do is, it will clear all the bits except the 4th. If the 4th pin is HIGH, ANDing it with the above will give the result 0b00010000 (let us call it ‘g’) and 0b00000000 (let us call it ‘h’), if not. 
      3) Check the value of the ANDed result – if value is ‘g’, then the 4th pin was HIGH, if the value is ‘h’, the 4th pin was LOW.

NOTE: Some IDEs like Code Vision AVR also allow direct access of pins by commands like DDRB.1, PORTC.4, PINA.4 etc. which simplify my user’s life!

Coding:
Besides the knowledge of these registers for I/O, you also need to include some header files (if you are working in, say, AVR Studio). Code Vision AVR has a code wizard that performs all these formalities for you so that you can directly write your code!
Given below is a sample code for AVR Studio that shows you what all header files you should include and other things you need to initialize. Also the code includes the usage of a delay function (parameter in milliseconds) that introduces a delay in your program giving you time to observe your results. The result of burning this code into me will result in my pin PB0 going high and low alternatively at a 1 second interval.

#define F_CPU 1000000UL           // CPU counts from o to 999999 in 1 second!
#include <avr/io.h>
#include <util/delay.h>

int main()
{
DDRB = 0b00000001;
while(1)
    {
        PORTB = 0b00000000;
        _delay_ms(1000);          // the parameter is 1000 ms = 1 second
        PORTB = 0b00000001;
        _delay_ms(1000);
    }
}

Important links and references:
1) http://www.atmel.com/dyn/resources/prod_documents/doc2503.pdf - detailed datasheet with sample codes for each and every feature
2) http://iamsuhasm.wordpress.com/tutsproj/avr-gcc-tutorial/ - a very good I/O tutorial with graphics, but please note, there are mistakes in this tutorial
4) http://www.avrfreaks.net/ - THE BEST site to learn more about AVR microcontrollers and their features and tutorials and discussions and lots more!


Thank you for reading my post. I wish you luck and hope you are able to use me well for your robot!