This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Getting MSP430F2013 into interrupt handler using GPIO pins

Other Parts Discussed in Thread: MSP430F2013

Hi all,

I have been trying to get some of the GPIO pins on my MSP430F2013 (specifically P1.2 and P1.3) to lead to an interrupt handler. I have seen another post online that does the same thing, however after copying most of that code into my project, it doesn't seem to be working for me. This is their code:

#include  <msp430x54x.h>
#define Pgreen 0x08
#define Pblack  0x10
int c=0;
void main(void)
{
     WDTCTL = WDTPW+WDTHOLD;  
     P1DIR=0x00;
     P1IE=Pgreen|Pblack;
     P1IES=Pgreen|Pblack;
    // P1OUT=0x00;
     P1IFG=0;
     __bis_SR_register(GIE);
     while(1)
     c=0;
}

#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{  
    if((P1IFG&Pgreen)==1)  c = 1;
    if ((P1IFG&Pblack)==1) c = 2;
    P1IFG =0;
}

There are only a few differences here: One of the defines refers to a different pin than mine, they are using a different MSP430, and they call P1IES, which I believe is used to cause in interrupt on a high-to-low edge instead of a low-to-high one (I took that line out because I want a low-to-high edge detection).

My code does almost the exact same thing, and what I do to test it is to apply an external 3V to either one of the two pins, and check to see if the interrupt handler was called on (which would then blink the LED as a visual verification). However, it never sees to call the interrupt handler, and I am not sure why. Here is my code below:

#define EN_0 0x04
#define EN_1 0x08

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

}

void enable_test()
{
P1DIR = 0x00;
P1IE = EN_0 | EN_1;
//P1IES = EN_0 | EN_1; // Don't need this line, want to detect low-to-high edge.
P1IFG = 0;
__bis_SR_register(LPM0 + GIE); // Other code did not have LPM0, only had GIE (doesn't work either way).
while(1); // IS THIS WHILE LOOP NECESSARY???
}

Can anyone see what the problem is here? Did I make an incorrect change to my code or forgot to add/remove a certain line? Or am I misinterpreting how the GPIO pins and interrupt handlers work (applying a voltage to the pin). I believe that 3V is a good amount for the voltage, as when I apply the voltage to the pin with the LED, the LED lights up (also, I am applying the voltage with ground connected to the MSP430, so that is not the issue). Also, as a side note, what is the purpose of the while(1); statement?

Any help would be greatly appreciated.

Thanks,

Matt 

  •    if((P1IFG&Pgreen)==1)  c = 1;
     

    This if() condition will never be true, since (<anything>&0x08) can be 0x08 or 0x00, but never 0x01. Try:

       if(P1IFG&Pgreen)  c = 1;
     

  • Hi Bruce,

    Sorry, that was the problem from his previous question, I was just too lazy to change it on his code when I copied it over here. I believe that my code makes the correct change in the interrupt handler, however the problem is still that the interrupt handler is never reached. Does anyone know why that is?

    Matt

  • Matthew Wasko said:
    however the problem is still that the interrupt handler is never reached. Does anyone know why that is?

    You modified teh code so the interrupt happens on the rising edge. Now chances are that due to leakage currents, teh high-impedance input is already high from reset on. So if you apply 3V it doesn't raise from 0 to 3V, No risign edge, no interrupt.

    You need to apply a pulldown resistor, either externally, or with P1REN, if available. THis way the input is pulled low and will trigger on the rising edge.

  • I don't think that is the case, as I have checked it out on the oscilloscope and it shows the voltage clearly starting at 0V and jumping up to 3.1V as soon as I apply the 3V source to the GPIO pin. I also tried setting the right pins for P1REN and that still did not work.

    Can anyone look at the specific code I wrote for setting up the interrupt conditions and starting the low power mode to see if I am missing anything important? Because it seems like that is where I am going wrong here, as I have verified that the GPIO pin goes from low-to-high as I would expect for an interrupt to occur.

    Matt

  • 1) If you changed the ISR, where is the new code?

    2) In " __bis_SR_register(LPM0 + GIE);" the LPM0 part expands into a call to __bis_SR_register (by golly); that (intrinsic) function returns something, but I don't know what it is, so  you're actually setting who-knows-what bits. I suspect you'd do better with "__bis_SR_register(LPM0_bits + GIE);"

    3) The while(1) is to keep you from "falling out the bottom" of main(). Different runtime systems do different things when that happens. Since you have no LPM0_exit, it is true that this program will never reach the while(); I (personally) don't like to count on that as the program grows.

  • Bruce McKenney47378 said:
    the LPM0 part expands into a call to __bis_SR_register (by golly); that (intrinsic) function returns something, but I don't know what it is,

    Good catch.

    IIRC, the function expands to __bis_SR_register(LPM0_bits). It returns a void value, probably the value of LPM_bits, perhaps something different. However, the return value is never returned as this inner call will already enter LPM0 - with GIE not set. So it is an eternal sleep.

    Matthew Wasko said:
    I have checked it out on the oscilloscope and it shows the voltage clearly starting at 0V and jumping up to 3.1V as soon as I apply the 3V source to the GPIO pin.

    Doesn't mean anything. The input is high impedance. And the scope will show 0V even if you don't touch anything with the probe, due to its limited input impedance. As a result, the I/O port may see a high level while the scope sees a low level. You won't believe how different things look on a scope when using a low-capacitance ultrahigh input impedance active $600 FET probe. :)
    A scope is a really useful tool (like a multimeter or a logic analyzer, or debugger) but as usual, one has to know its limits.

    Matthew Wasko said:
    I also tried setting the right pins for P1REN and that still did not work.

    Well, P1REN.x=1 and P1OUT.x = 0 should do.

    I just looked into the port pin schematics. I wonder why there is a P1SEL.2 register bit into the edge select logic (as P1SEL.2 will directly disable or enable the interrupt logic too). It doesn't make sense. However, I don't see anything that would prevent the interrupt.

    Things you can try:

    - manually set P1IFG.2 THis shoudl immediately trigger the ISR once GIE is set.
    - set P1.2 to output (P1DIR.2=1) and toggle P1OUT.2. Thsi too should trigger the interrupt.
    - when you stop the CPU in the debugger, where does it stop? (well, if it doesn't enter the interrupt, it should stop at the _bis_SR.

  • My biggest problem was definitely the writing LPM0, instead of LPM0_bits. The two lines of P1REN |= (EN_0 | EN_1); and P1OUT &= ~(EN_0 | EN_1); ended up not being necessary, so this is what I ended up with:

    int main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
    while(1) enable_test();
    }
    void enable_test()
    {
    P1DIR = 0x00; // WHAT DOES THIS LINE TWO
    P1IE = EN_0 | EN_1;
    __bis_SR_register(LPM0_bits + GIE);
    }

    void test0()
    {
    unsigned int i, j;
    P1DIR |= 0x01;
    for(i = 0; i < 8; i++) { P1OUT ^= 0x01; for(j = 0; j < 15; j++) __delay_cycles(65535); }
    }

    void test1() { SAME AS VOID TEST1 EXCEPT FOR __delay_cycles(32767) }

    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    {
    if(P1IFG & EN_0) test0(); // blinks the LED at a certain rate four times.
    else if(P1IFG & EN_1) test1(); // blinks the LED at a faster rate four times.
    P1IFG &= ~(EN_0 | EN_1);
    __bic_SR_register_on_exit(LPM0_bits+GIE); // Clear LPM bits upon ISR Exit
    }

    I have one quick question about the first line of enable_test(). With line the LED goes on AND off four times. However, when I comment the line out, the LED stays on after the fourth time, until I probe one of the two pins again, in which it will do another sequence of four LED things, always leaving the LED on with the fourth flash. Can anyone see why this is?

    Thanks again,

    Matt

  • Matthew Wasko said:
    P1DIR = 0x00; // WHAT DOES THIS LINE TWO

    This line switches all P1 ports to input, effectively switching off the LED, independently of the P1OUT state.

  • That makes sense. Thanks!

**Attention** This is a public forum