Jump to content
Sign in to follow this  
mavis311

LaunchPad on-board button doesn't trigger interrupt

Recommended Posts

Hi folks. I'm new to a bunch of stuff here. Mostly programming embedded devices like the msp430.

 

I haven't had a lot of time yet to read up on the specifics that I'm asking about, but I am working on it.

 

In the meantime, can someone help me understand why my program isn't working correctly? I'm just trying to flash the leds a bit and show a response to presses of the onboard button. My program works as expected except that after the button has been pressed once the program no longer responds to the button until I reset the board.

 

Why is this happening? I have a feeling I'm not handling the interrupts properly. Any thoughts?

 

I'm withholding my sloppy, hacked-together C code for now, btw.

Share this post


Link to post
Share on other sites
Are you clearing you interrupt flag after it gets triggered?

 

I'm not one of those experienced people @bluehash mentions, but this is the first problem I had with interrupts.

 

BTW: Second problem? Button bounce.

 

Welcome!

 

-Doc

Share this post


Link to post
Share on other sites
Are you clearing you interrupt flag after it gets triggered?

 

Perhaps not... I really don't know what I'm doing with these interrupts, I've just hacked together something that looks like it might work from what little understanding I have and from my intuitions about copy and pasting other code into my program.

 

Speaking of copy/paste, here is the code I'm using. Let me know if there is anything else that I'm doing wrong or if you don't know what I'm trying to do on a line or something.

//******************************************************************************
//  Hello LaunchPad
//  A simple program to get familiar with the MSP430.
//  I just want to flash the LEDs and show a response to the button. 
//******************************************************************************

#include "msp430g2231.h"


#define     DELAY           25000
#define     NUM_FLASHES     3
#define     FLASH_DELAY     750
#define     LED_MASK        (BIT0 | BIT6)            


// code basically stolen from the temp sensor project that came preloaded
void InitializeButton(void)                 // Configure Push Button 
{
   // not really sure what most of this does.
   P1DIR &= ~BIT3;
   P1OUT |= BIT3;
   P1REN |= BIT3;
   P1IES |= BIT3;
   P1IFG &= ~BIT3;
   P1IE |= BIT3;
}


int main(void)
{
   WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer

   InitializeButton();

   // initialize leds
   P1DIR |= LED_MASK;
   P1OUT = BIT6;

   __enable_interrupt(); 

   // quick and dirty main loop
   // just gonna toggle the leds until the cows come home
   unsigned int i;
   for ( ; ; )
   {
       P1OUT ^= LED_MASK;

       // delay alternations
       i = DELAY;
       do 
       {
           i--;
       } 
       while (i > 0);
   }
}


// code also basically stolen from the temp sensor program
#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{   
   P1IFG = 0;  
   P1IE &= ~BIT3;                  /* Debounce */
   WDTCTL = WDT_ADLY_250;
   IFG1 &= ~WDTIFG;                /* clear interrupt flag */
   IE1 |= WDTIE;

   // unstolen code from here down
   // gives a quick 3 flashes of both leds and then resets the leds to the
   // state they were in when the button was pushed
   int counter = (NUM_FLASHES + 1) * FLASH_DELAY - 1;
   int initialState = P1OUT;           // save led state
   int onDuration = FLASH_DELAY / 2;    // on for half the time
   P1OUT = 0;
   do
   {
       if (counter % FLASH_DELAY >= onDuration)
           P1OUT = LED_MASK;           // on for a bit
       else
           P1OUT = 0;                  // off for a bit

       counter--;
   }
   while (counter > 0);

   P1OUT = initialState;               // restore led state
}

Share this post


Link to post
Share on other sites

Mavis,

The following code should work. I commented out

P1DIR &= ~BIT3;

P1OUT |= BIT3;

P1REN |= BIT3;

in your InitializeButton() function. I'm unable to find the MSP430 register definitions, but I think you are configuring it as an output.

 

P1.3 is pulled high according to the schematic. So when you push the button, the line is going to go low.

The below code configures P1.3 as an interrupt and tells it to trigger when the pin goes from high to low.

P1IES |= BIT3; //trigger P1.3 from high to low

P1IFG &= ~BIT3; // Clear the flag

P1IE |= BIT3; // Enable the interrupt

 

 

//******************************************************************************
//  Hello LaunchPad
//  A simple program to get familiar with the MSP430.
//  I just want to flash the LEDs and show a response to the button. 
//******************************************************************************

#include "msp430g2231.h"


#define     DELAY           25000
#define     NUM_FLASHES     3
#define     FLASH_DELAY     750
#define     LED_MASK        (BIT0 | BIT6)            


// code basically stolen from the temp sensor project that came preloaded
void InitializeButton(void)                 // Configure Push Button 
{
   // not really sure what most of this does.
   #if 0
    P1DIR &= ~BIT3;
    P1OUT |= BIT3;
    P1REN |= BIT3;
   #endif

   P1IES |= BIT3;
   P1IFG &= ~BIT3;
   P1IE |= BIT3;
}


int main(void)
{
   WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer

   InitializeButton();

   // initialize leds
   P1DIR |= LED_MASK;
   P1OUT = BIT6;

   __enable_interrupt(); 

   // quick and dirty main loop
   // just gonna toggle the leds until the cows come home
   unsigned int i;
   for ( ; ; )
   {
       P1OUT ^= LED_MASK;

       // delay alternations
       i = DELAY;
       do 
       {
           i--;
       } 
       while (i > 0);
   }
}


// code also basically stolen from the temp sensor program
#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{   
   P1IFG = 0;  
   P1IE &= ~BIT3;                  /* Debounce */
   WDTCTL = WDT_ADLY_250;
   IFG1 &= ~WDTIFG;                /* clear interrupt flag */
   IE1 |= WDTIE;

   // unstolen code from here down
   // gives a quick 3 flashes of both leds and then resets the leds to the
   // state they were in when the button was pushed
   int counter = (NUM_FLASHES + 1) * FLASH_DELAY - 1;
   int initialState = P1OUT;           // save led state
   int onDuration = FLASH_DELAY / 2;    // on for half the time
   P1OUT = 0;
   do
   {
       if (counter % FLASH_DELAY >= onDuration)
           P1OUT = LED_MASK;           // on for a bit
       else
           P1OUT = 0;                  // off for a bit

       counter--;
   }
   while (counter > 0);

   P1OUT = initialState;               // restore led state
}

 

Hope this helps.

Share this post


Link to post
Share on other sites
I'm unable to find the MSP430 register definitions, but I think you are configuring it as an output.

 

Where do you think I would find the register definitions?

 

P1.3 is pulled high according to the schematic. So when you push the button, the line is going to go low.

 

What schematic are you referring to?

 

 

Interestingly, your suggested modifications both did and didn't work. Using CCS4, if I Debug the project and choose "Run", it works as expected. However, if I choose "Free Run" or if I just power up the board with my program on the msp430, the button only responds once until I hit reset, as before.

Share this post


Link to post
Share on other sites

Hello,

 

I think there is an issue with you using the WDT as an Timed interrupt source.

in:

// code also basically stolen from the temp sensor program
#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{   
   P1IFG = 0;  
   P1IE &= ~BIT3;                  /* Debounce */
   WDTCTL = WDT_ADLY_250;
   IFG1 &= ~WDTIFG;                /* clear interrupt flag */
   IE1 |= WDTIE;

In order to correctly accept for the Debouce you need to exit the interrupt or use the TimerA or a simple For loop.

Have a look at my post. I have come across this problem earlier and got it resolved. Also the code if available for your trial.

I have it working on MSP430F2013 but should work fine for any MSP430G series also.

 

Have a look at:

http://www.43oh.com/forum/viewtopic.php?f=8&t=29#p132

Share this post


Link to post
Share on other sites

@Mavis311: You can find a lot of info, like aliases for registers and common values, in the header file (in this case: msp430g2231.h); though it doesn't tell you exactly what the values do. That said...

 

@bluehash: I think the lines you commented do the following:

 

P1DIR &= ~BIT3; // set P1.3 as an input (0)
P1OUT |= BIT3; // just guessing, but I think this ties the input high (rather than ~BIT3, which would make it tied low)
P1REN |= BIT3; // enable internal pull-up/down resistor on P1.3

 

I'll have to get into the data sheet, etc. to be sure, but I think I saw this info in my documentation travels.

 

-Doc

Share this post


Link to post
Share on other sites

Well, I seem to have solved this problem.

 

There were a number of problems with the code I was using and the solution leaves me somewhat perplexed.

 

@boseji: There was no issue with the WDT, although I still don't really know what that is. I test my program with and without the code you pointed out, and it works the same both ways. I removed it since I don't know what it does yet. I had just been overlooking it until you mentioned it; thanks.

 

@GeekDoc: from what I've discovered thanks to beretta's tutorials, you are correct in your comments.

 

The thing that is puzzling me right now is P1REN, the resistor enable. Uncommenting the line that refers to P1REN causes the problem that caused me to seek help on this matter. With the line commented, the interrupt code is executed every time the button is pressed.

 

I still have a lot to learn, but I've only been at it for a couple of days now.

 

Working code:

//******************************************************************************
//  Hello LaunchPad
//  A simple program to get familiar with the MSP430.
//  I just want to flash the LEDs and show a response to the button. 
//******************************************************************************

#include "msp430g2231.h"

#define     DELAY           25000
#define     NUM_FLASHES     3
#define     FLASH_DELAY     750
#define     LED_MASK        (BIT0 | BIT6)            

void initializeButton(void);
void initializeLEDs(void);

int main(void)
{
   WDTCTL = WDTPW + WDTHOLD;                               // Stop watchdog timer

   initializeButton();
   initializeLEDs();

   __enable_interrupt(); 

   // quick and dirty main loop
   // just gonna toggle the leds until the cows come home
   unsigned int i;
   for ( ; ; )
   {
       P1OUT ^= LED_MASK;

       // delay alternations
       i = DELAY;
       do 
       {
           i--;
       } 
       while (i > 0);
   }
}


// code also basically stolen from the temp sensor program
#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{   
   P1IE &= ~BIT3;                                          // disable p1.3 interrupt
   P1IFG &= ~BIT3;                                         // clear interrupt flag
//    P1IES |= BIT3;                                          // reset edge select

// watchdog timer code has no effect in this instance, but removed anyway    
//    WDTCTL = WDT_ADLY_250;
//    IFG1 &= ~WDTIFG;                                        /* clear interrupt flag */
//    IE1 |= WDTIE;

   // unstolen code from here down
   int initialState = P1OUT & (BIT0 | BIT6);               // save led state

   // give a quick 3 flashes of both leds and then resets the leds to the
   // state they were in when the button was pushed
   int counter = (NUM_FLASHES + 1) * FLASH_DELAY - 1;
   int onDuration = FLASH_DELAY / 2;                       // on for half the time
   P1OUT &= ~LED_MASK;                                     // turn both LEDs off to begin
   do
   {
       if (counter % FLASH_DELAY >= onDuration)
           P1OUT |= LED_MASK;                              // on for a bit
       else
           P1OUT &= ~LED_MASK;                             // off for a bit

       counter--;
   }
   while (counter > 0);

   P1OUT = (P1OUT & ~LED_MASK) | initialState;             // restore initial LED state, don't molest other bits

   P1IE |= BIT3;                                           // reenable interrupt
}


void initializeButton(void)
{
//    P1DIR &= ~BIT3;                                         // set p1.3 direction to 0 - input
//    P1OUT |= BIT3;                                          // sets p1.3 high   
//    P1REN |= BIT3;                                          // Resistor Enable up for p1.3, uncomment this line for only one button press
//    P1IES |= BIT3;                                          // Interrupt Edge Select - 0: trigger on rising edge, 1: trigger on falling edge  
   P1IFG &= ~BIT3;                                         // Clear the flag
   P1IE = BIT3;                                            // PxIE - Interrupt Enable Register
}


void initializeLEDs(void)
{
   P1DIR = 0x41;                                           // (BIT0 | BIT6)
   P1OUT = BIT6;                                           // begin with only green led on
}

Share this post


Link to post
Share on other sites

Ahhh! I had forgotten; this was my second problem (bounce was third).

 

The P1REN enables the internal "pull-up" (or pull-down) resistor. Basically, you're trying to sense when the pin is connected to ground (low), which happens when the buitton is pushed. But while the pin isn't connected to anything (button not pressed), the voltage on the pin "floats" in between low (0v) and Vcc (the chip's power, +3.3v). It may float low enough to be read as low, triggering your interrupt.

 

To prevent this we use a high-value resistor (10K ohms+) to keep the pin high without drawing much current. When the button is pushed, the electrical path of least resistance from the pin is to ground. I prefer to use external resistors, "just-in-case".

 

Here's a pic I found on http://www.seattlerobotics.org while Googling (I suggest you search the term "pull-up resistor"):

 

basics1.gif

 

-Doc

Share this post


Link to post
Share on other sites
Geekdoc,

According to the schematic, there already a pull-up resistor attached to port P1.3

So even if the internal pull up is not enabled, you should be good.

Oh yeah, there is. I have seen that schematic, but I forgot they had that in there. Makes sense.

 

Still, important info if using any of the other pins as inputs, or using the MSP430 off of the LaunchPad (which is how I learned about pull-up resistors. :) ).

Share this post


Link to post
Share on other sites

So... how is it that enabling the pull-up resistor for p1.3 causes the interrupt not to occur more than once?

 

And does enabling P1REN for p1.3 use a resistor other than R34 (from bluehash's schematic)?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×