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.

Tuesday, August 30, 2011

Introduction to Pulse Width Modulation

Hi all. It’s been a while since the last post. But, it has been an eventful period all the same with placements going on in BITS Pilani.
Anyway, in this post, I shall be giving a basic introduction to a concept called Pulse Width Modulation, its need and applications and how it can be implemented on an ATmega32/16.

Pulse Width Modulation (PWM) – Basics

In layman language, PWM is a technique in which you vary the ratio of HIGH time to LOW time of a pulse. One of the applications is simulation of an analogue signal using digital TTL signals. What if you want to supply 2.5 Volts to a component? You can use a voltage divider circuit using R1=R2 and then supply the output across any one of these resistors to your component of interest. Simple enough? But what you are overlooking is the fact that this circuit is highly inefficient as there is always going to be power dissipation across the resistors. Also, this configuration is highly susceptible to errors because a slight change in resistance owing to wear and tear or long use is bound to change your input voltage.
 In PWM, you are actually fooling your component by switching between 5 Volts and 0 Volts so fast that it is not able to distinguish between the 5 Volts and 0 Volts and ends up seeing the average of these two signals i.e. 2.5 Volts. A corollary you can draw from this is that by simply adjusting the ratio of these two signals in a given time period, you can supply a variety of ‘analogue-like’ signals. For instance, in a PWM signal with a time period of 1 second, if I am supplying 5 Volts for 0.7 seconds and 0 Volts for the rest, what analogue voltage would my component see? That’s right – 3.5 Volts!

Why do I need to know PWM technique?

The world is analogue. Yes, there are desktops and laptops and mobiles and tablets and what not? All of these are digital in nature. But suppose you want to adjust the speed of your DC motor or you want a system in which the strength of the LED glow is proportional to some system parameter or you want to build a simple all-digital temperature control system? There are many applications in which PWM is helpful for the simple reason – It is energy-efficient as well as accurate, easy to implement and being digital in nature, it is not easily affected by noise.

Basically, in any digital system where you are varying a system parameter over a wide range, there is a high probability that PWM is involved; such is the popularity of this technique.

PWM using ATmega32/16

In any microcontroller, PWM is implemented by using the timers/counters available. The timers/counters have a PWM mode in which the user is supposed to let the controller know the desired time period and also the value of the counter at which the output has to go HIGH/LOW depending on the type of PWM.
For instance, suppose I want a PWM signal of 2.5 Volts. What I will do is I will tell the counter that I want a prescaler of 64 (say) on my clock of 1MHz (say). Also, I will tell it that it should set the output low whenever the counter reaches the value 127 (referred to as 'OCR' value). So, on its way to 255 (referred to here as the 'TOP'), whenever the counter encounters the value 127, the output goes HIGH/LOW. The following diagram will throw more light on the working of PWM in microcontrollers.

Now we will see how to implement this using AVR Studio. Please have your datasheet with you.J 

PWM implementation in AVR Studio
 There are various types of PWM:

1)      Fast PWM – In this type of PWM, in a single time period, a PWM signal will have first the HIGH signal and then the LOW signal.
2)      Phase-correct PWM – In this type of PWM, in a single time period, a PWM signal will be symmetric about the centre i.e. if plotted against time, the signal to the left and right of the centre of the signal will be mirror images.

3)      Phase and frequency correct PWM – In this type of PWM, you can alter the frequency of your signal. In the other types, your frequency remains fixed – only the duty cycle can be altered.

In this post, I will be covering only Fast PWM as it is the simplest to understand for beginners. Other modes will be covered in a future post. Watch out J

So let’s get started!

Registers and Terms involved in Fast PWM implementation

First and foremost, in any kind of PWM implementation, you will come across the following terms:
a)      MAX – This is the maximum value upto which the counter can count. For an 8-bit counter, MAX = 0XFF (255).
b)      BOTTOM – This is the value from where the counter starts counting at the start of every period. For an 8-bit counter, BOTTOM = 0 (0X00).
c)      TOP – This is the value with which the count is compared to decide when to switch the output to HIGH/LOW. (Please note, in the diagram above, TOP and MAX were used interchangeably. This is not always the case. Henceforth, we won't use the two terms interchangeably.)
d)     Duty cycle – This is the ratio of the on-time in a given period to the length of the entire time-period of the PWM signal.

We will be working with the 8-bit timer/counter to keep things simple enough. The registers involved in Fast PWM implementation are the same as the ones I mentioned in the post on Timers. You can refer to the description of the registers in that post for a better understanding. A brief recapitulation follows:

1)      TCCR0 – Manipulating WGM bits in this register help select the desired PWM mode and manipulating the CS bits help select the desired prescaler for the clock generation. Please refer to the datasheet for the required manipulations.
2)      TCNT0 – This 8-bit register stores the current value of the counter.
3)      OCR0 – This register stores the TOP value.
4)      TIFR – This register has a bit called OCF0 which goes HIGH whenever TCNT0 = OCR0 i.e. whenever the output switches from HIGH to LOW or vice versa (depending on the configuration selected). You need to write a ‘1’ to this bit to clear it. (Peculiar right?)

Following is the code for the generation of a 40% duty cycle Fast PWM signal with a clock frequency of 1 MHz prescaled by 64. The code is fully commented, but please make sure you have the datasheet with you to understand the various bit manipulations.



#include <avr/io.h>


int main(void)
{
    while(1)
    {
        TCCR0 |= (1<<WGM01)|(1<<WGM00);//selecting Fast PWM mode
TCCR0 |= (1<<COM01)|(0<<COM00); // selecting non-//inverting mode of PWM operation
// In non-inverting mode of operation, the HIGH portion of the //signal comes first during a given time period
TCCR0 |= (1<<CS01)|(1<<CS00); // selecting a pre-scaler //of 64
OCR0 = 101; // this is the TOP value; for 40% duty cycle, //TOP = (0.4*256)-1
// This code will generate a square wave having 40% duty cycle on the pin OC0 i.e. PB3 
    }
}

Some more information

One thing that would have become very clear is that the frequency of our PWM signal is different from the clock signal. There is a formula to evaluate your signal frequency. The formula (for an 8-bit counter) is given by:


256 is replaced by 65536 for a 16-bit counter.

To summarize, in Fast PWM mode:

1)      We can change the PWM frequency (also called modulation frequency) by changing the system clock settings and the prescaler value.
2)      We can change the PWM duty cycle by altering the TOP value which is stored in the register OCR0.

References

This post would not have been possible without the following treasures of information.







Conclusion

The other types of PWM and their implementation will be covered in a later post.
Hope this was helpful J   

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!