Archive

Archive for May, 2012

MSP430 Interrupt Rising and Falling Edge

May 18th, 2012

In previous post we have seen how interrupt works in MSP430 and we saw that how interrupt is generate on rising edge. What if we need to generate interrupt on falling edge ?

We can specify the edge using the following statement

For low to high
P1IES &= ~0x02 ;

For High to low
P1IES |= 0x02 ;

If you do not specify anything, the value of the corresponding bit is 0, so , by default it is is low to high edge. Here is the full code for high to low interrupt.

 

#include <msp430x14x.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;  // Stop Watch Dog Timer
P3DIR |= 0x10; // P3.4 set to output
P1IE |= 0x02 ; // Interrupt on Input Pin P1.1
P1IES |= 0x02 ; //  High to Low Edge
_BIS_SR(GIE);
}

#pragma vector = PORT1_VECTOR
__interrupt void InterruptVectorPort1()
{
P3OUT ^= 0x10; // Toggle P3.4
P1IFG &= ~0x02; // Clear Interrupt Flag
}

Here is how the screen shot looks like with this code

 

Finally, if you want to cause interrupt on falling as well as rising edge, there is a trick for it. What you is - toggle the edge sensitivity inside the interrupt service routine using a statement like.

P1IES ^= 0x02 ;

Here is how the screen shot looks like when interrupt is triggered at rising as well as falling edge.

The code in the interrupt service routine should be as follows.

#pragma vector = PORT1_VECTOR
__interrupt void InterruptVectorPort1()
{
P3OUT ^= 0x10; // Toggle P3.4
P1IES ^= 0x02 ; // Toggle Edge sensitivity
P1IFG &= ~0x02; // Clear Interrupt Flag
}

Uncategorized

MSP430 Interrupt Tutorial

May 18th, 2012

In this post we have tried to explain the Concept of Interrupt using real world example. Let us assume that you want to monitor the port Pin P1.1 using interrupt. Whenever, the P1.1 changes from low to high and interrupt occurs. When that happens, the P3.4 is toggled.

We have tried to keep the code to minimal possible. Here is goes.

#include <msp430x14x.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop Watch Dog Timer
P3DIR |= 0x10; // P3.4 set to output
P1IE |= 0x02 ; // Interrupt on Input Pin P1.1
_BIS_SR(GIE);
}

#pragma vector = PORT1_VECTOR
__interrupt void InterruptVectorPort1()
{
P3OUT ^= 0x10; // Toggle P3.4
P1IFG &= ~0x02; // Clear Interrupt Flag
}

Now connect a source of input to P1.1. Here is a screen shot when P1.1 and P3.4 were captured ( P1.1 in blue and P3.4 is in Red).

Notice that P3.4 changes only on the rising edge of the clock.  There is no interrupt on the falling edge of the clock. What if you want to generate an interrupt of the falling edge of the clock ? What if you want to generate interrupt on the falling as well as rising edge ? We will cover it in the next post. Before that we want to mention and important thing - Clearing the interrupt flag. Notice the statement

P1IFG &= ~0x02; // Clear Interrupt Flag

If you do not give this statement , you will get scopeshots something like

Notice how P3.4 keeps toggling not only at the rising edge, but also at regular intervals. Why ? Because, we have not cleared the interrupt flag. So it keeps entering the interrupt since interrupt Flag is not cleared. That brings us to an important rule.

"Clear the interrupt once you have entered into the Interrupt Service Routine".

 

 

Uncategorized

Understanding Timers in MSP430 #3

May 17th, 2012

We now define an interrupt vector. When a timer interrupt occurs, it runs the code defined in the interrupt routine. Take a look at the Interrupt routine.

#include <msp430x14x.h>

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P6DIR |= 0x08; // P6.3 Set P6.3 to output
CCTL0 = CCIE; // CCR0 interrupt enabled
CCR0 = 60000;
TACTL = TASSEL_2 + MC_2; // SMCLK, contmode
_BIS_SR(GIE); // Enable interrupt
}

// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
P6OUT ^= 0x08; // Toggle P6.3
CCR0 += 60000; // Add Offset to CCR0
}

If you run this code you and observe the signal, you get a screen shot something similar to

Some Experiments

Here are some experiments you can do.

1. Try changing

CCR0 += 60000;

to

CCR0 += 30000;

and you will observe that time period becomes half. Changing it to CCR0 += 6000; will reduce it to 1/10th.

2. If you want a slower timer, you may change the

TACTL = TASSEL_2 + MC_2;

to

TACTL = TASSEL_1 + MC_2;

Which will change the clock from SMCLK ( derived from 4 MHz) to ACLK ( derived from 32.768 KHz).
3. If you change

TACTL = TASSEL_2 + MC_2 ;

to

TACTL = TASSEL_2 + MC_2 + ID_1;

it doubles the time period ( by by halving the clock period used for timer interrupt). Bit 7-6 defines it.

IDx Bits

00 divide by 1
01 divide by 2
10 divide by 4
11 divide by 8

Uncategorized

Understanding Timers in MS430 #2

May 17th, 2012

Add three more lines in the main programs ( highlighted in red).

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P6DIR |= 0x08; // P6.3 Set P6.3 to output
CCTL0 = CCIE; // CCR0 interrupt enabled
CCR0 = 60000;
TACTL = TASSEL_2 + MC_2; // SMCLK, contmode
_BIS_SR(GIE); // Enable interrupt
}

Let is now try to understand the code one by one..

CCTL0 Register

If you plan to use a Timer, the first register that you need to set is CCTL0. It is a 16 bit register and settings of this register effects how we use the register. For our purpose we just tell it to enable the interrupt using

CCTL0 = CCIE;

Notice that we have not yet enabled the timer.

CCR0

This register will define the amount of time after which the timer event will occur. We have set it to

CCR0 = 60000;

TACTL

Bit 9-8 selects the source of the clock

The Possible values are

00 TACLK
01 ACLK
10 SMCLK
11 INCLK

We have basically selected the SMCLK which is a 4 MHz clock in our case.

The bits 5-4 selects how the counting. Possible values are

00 Stop mode: the timer is halted
01 Up mode: the timer counts up to TACCR0
10 Continuous mode: the timer counts up to 0FFFFh
11 Up/down mode: the timer counts up to TACCR0 then down to 0000h

We have selected 10 which makes the counter count upto 0FFFFh

Enable General Interrupt

Finally we have to enable the general interrupt using.

_BIS_SR(GIE);

This statements sets the GIE bit in the Status register which enables the interrupt. Notice that we have not yet defined the interrupt vector. We will do it in the next page. The code as of now will compile but will not produce any observable result.

Uncategorized

Understanding Timers in MSP430

May 17th, 2012

We will understand the concept of timer by writing an actual software. The purpose of the program is to generate well defined pulse(s) of alternate high and low. This is something simple, but the key here is to understand the Timer concept rather than generating the square pulse. You will need an oscilloscope to capture the high low sequence.

Preparing your hardware

Before we start our experiment, let us make sure that our hardware is in place. We do this by writing the following code and checking that we are getting high ( or low ) at an IO port of the board we are testing. In out case it is P6.3, but you can use any other port.

Use the following code and make sure that the P6.3 ( or your chosen port) turns high and low before you start experimenting.

#include "msp430x14x.h"

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P6DIR |= 0x08; // P6.3 Set P6.3 to output
P6OUT &= ~0x08; // P6.4 is low
//P6OUT |= 0x08; // Use this if you want to check for high output.
}

In the next page we will write the actual code that will run timer.

Uncategorized