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.

Port interrupts.

Hello!


I have a problem with port interrupts. I'm trying to catch remote control signals.
The problem is that the interrupt routine gets hit twice for every interrupt.

The code is below (for simplicity purposes, I configured only the port interrupt
and no other stuff like low power mode.
On top of that, the function loader_exit() is always called the first time I press
on the remote control. After that, it's never called, but the Port3ISR is still called
twice.
Any idea of what may be wrong?

Thanks,

Pascal

#include <msp.h>

void ConfigIR(void);
#define IR_BIT 0x04
#define	LED_BIT 0x01

void main(void) {
	WDTCTL = WDTPW | WDTHOLD;         	//	Stop watchdog timer
	P1DIR = LED_BIT;
	P1OUT = 0;
	__disable_interrupt();
	ConfigIR();
	__enable_interrupt();
	__sleep();
}

void ConfigIR(void) {
	P3DIR &= ~IR_BIT;
	P3OUT = IR_BIT;
	P3REN = IR_BIT;
	P3SEL0 = 0;
	P3SEL1 = 0;
	P3IFG = 0;
	P3IE = IR_BIT;
	P3IES = IR_BIT;
	NVIC_ISER1 = 1 << ((INT_PORT3 - 16) & 31);
}

void Port3ISR(void) {
	P3IFG = 0;
	P1OUT ^= LED_BIT;
	__nop();
}


  • Hi Pascal!

    You should always tell the hardware you are using. From this line

    NVIC_ISER1 = 1 << ((INT_PORT3 - 16) & 31);

    I assume you are using the MSP432P401R, most likely on the MSP-EXP432P401R LaunchPad.

    Your main

    void main( void )
    {
      WDTCTL = WDTPW | WDTHOLD;  // Stop watchdog timer
      P1DIR = LED_BIT;
      P1OUT = 0;
      __disable_interrupt();
      ConfigIR();
      __enable_interrupt();
      __sleep();
    
      while( 1 )                 // <== Add an endless loop (main program)
      {
      }
    }

    is missing an endless loop, so after your processor is woken up by the interrupt, your program simply ends. You could set the controller to sleep mode again, but something must happen.

    And I would change the order of your statements here:

    P3IFG = 0;
    P3IE  = IR_BIT;
    P3IES = IR_BIT;

    In general, I would always do the following sequence:

    P3IES = IR_BIT;
    P3IFG = 0;
    P3IE  = IR_BIT;

    Enabling the interrupt is the last thing you do, but right before you should clear any pending flags and every other stuff should be done previously. The reason for this: Changing PxIES can set the flag, look here:

    This does not mean that changing PxIES will necessarily set PxIFG, but it could. Anyway - this is more a general thing and my personal opinion.

    Dennis

  • Do not know what kind of IR remote detector you are using.
    Could it pick generate another pulse when you turn on your LED inside your ISR?
    Try block the light (IR or visible) from reaching (directly or by reflection) the IR remote detector.
  • Hello Dennis!

    > You should always tell the hardware you are using

    Yes, sorry, it's the 432 evaluation board.

    > is missing an endless loop, so after your processor is woken up by the interrupt, your program simply ends.

    No, it doesn't simply end. As explained, it works fine except that every interrupt happens twice.

    > You could set the controller to sleep mode again, but something must happen.

    Something does happen. On MSP430, you don't necessarily need a while loop. For example this code
    works perfectly fine on a F5529 launchpad, and there is no while loop. I was simply assuming MSP432 could
    do the same.

    #include <msp.h>

    int main(void) {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    P2DIR |= 0x03; // P2.0 output + P2.1 output (oscillo)
    TA0CCTL0 = CCIE; // CCR0 interrupt enabled
    TA0CCR0 = 50000;
    TA0CTL = TASSEL_2 + MC_1 + TACLR; // SMCLK, upmode, clear TAR
    __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, enable interrupts
    }

    // Timer0 A0 interrupt service routine
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void TIMER0_A0_ISR(void) {
    P2OUT |= 0x02;
    P2OUT ^= 0x01; // Toggle P1.0
    P2OUT &= ~0x02;
    }

    Pascal
  • Pascal4275 said:
    No, it doesn't simply end.

    In your initial question you posted:

    Pascal4275 said:
    On top of that, the function loader_exit() is always called

  • Hello!

    My explanation wasn't accurate enough.
    The Loader_exit() appars in the debugger, but if I press continue, then it works (except the problem of the
    double interrupt), and if I set a breakpoint in the interrupt (at __nop()), then the debugger stops and the
    LED is at the proper state (once ON, once OFF).

    Thanks,

    Pascal
  • What is the value of P3IFG in each interrupt?

    What do you see on the pin with an oscilloscope or logic analyzer?

  • Hello!

    The interrupt has the proper value. The output of the IR sensor is wired on P3.2, and I get 00000100
    which looks quite normal.
    BUT: there is a strange behavior.
    Here is the ISR:
    void Port3ISR(void) {
    P3IFG = 0;
    P1OUT ^= LED_BIT;
    __nop();
    }

    Let's assume I put a breakpoint on the first line (P3IFG = 0;).
    In this case, when it stops, the register indicates 00000100
    If I step once, it indicates 00000000, which is normal.
    If I press continue, then there is no second interrupt.

    Now: If I put the breakpoint on __nop(); then the first time the program stops
    on the breakpoint, the value of P3IFG is still 00000100 although I have just set it to 0.

    To summarize very accurately :
    - I didn't mention it this time, but I have configured the program as "treat all files as C++" and I have modified
    the startup_ccs.c file accordingly as mentioned here:
    e2e.ti.com/.../1753842
    - I have set one single breakpoint on __nop();)

    Here are the various actions and states:
    - Press debug (the green bug icon)
    The program loads and waits on main();
    - Press continue (the green arrow). When running, press the remote control key.
    The program stops at __nop();
    The P3IFG value is 00000100 (0x40 in hexa)
    - Press continue
    The program stops again at __nop();
    This time, the P3IFG value is 0
    - Press continue
    The program stops on the open bracket of loader_exit() in exit.c
    - Press continue, then press again the remote control key
    The program stops at nop() as previously P3IFG is 0x04 as before
    - Press continue again -> P3IFG is now 0 and it works fine except this double interrupt.

    OK, I got something: when progressing step by step, it finishes in an abort() function which
    is an infinite loop. If I ad an infinite loop as suggested above, there is no more step into the
    loader_exit() function, but still this double interrupt...

    Any hint is welcome...

    Pascal
  • I think the value of P3IFG in each interrupt is 0x04.

    P3IFG is cleared by line #30 of the code.

    Line #31 will turn on the LED. The light emitted is picked up by the IR-receiver and causes it to generate another pulse, which sets the P3IFG to 0x04 again.

    Thus the ISR will be entered again. But this time it will turn off the LED instead. Thus it will not set P3IFG again until an external IR pulse is detected.

    This is why an external IR signal will fire the ISR twice. The first one is real, the second one is caused by the ISR turning on the LED.
  • Hello!

    Indeed, it's a very smart explanation that I didn't think about. However I have commented out the P1 related
    lines, and it does not solve the problem. Still 2 interrupts.

    And again, on the first pass of the "interrupt pair", although P3IFG should be cleard, it's still 0x04. On the second
    pass however, it's 0 as expected.

    BUT: if I set a breakpoint on P3IFG = 0 instead of _nop() and go step by step, then there is no second interrupt.

    Pascal
  • If this is the case, may be the IR remote is always sending a double pulse. The first pulse will set the IFG and trigger an interrupt. If the ISR responding to the first pulse clears the IFG before the second pulse comes in, the IFG will be set again and causes a second interrupt. But if the ISR responding to the first pulse is slowed down (by the break-point) and clears the IFG after the second pules comes in, the IFG will no be set again and will not cause a second interrupt.
  • To confirm that the double pulse ,as mentioned by old_cow_yellow, is the rootcause, you could add a delay in the ISR before clearing the IFG. And play around with the delay to see, if the issue disappears with a higher delay.
  • Hello!

    I pulled a wire out of the board with the LED jumper removed, in order to observe
    the LED level only, and everything at runtime, without debugger.
    What happens now is that there is only one interrupt (i.e. the falling and rising
    edge count of the LED are exactly half of the remote control signal count.

    Now according to what you say, there shoudl even be more interrupts because
    the remote control sends sequences of 32 pulses. Or 33 with the header.
    This also means that the debugger is extremely slow because ine the case of the
    remote control I am using, the second falling edge comes 2.5ms after the first one.
    2.5ms means about 3000 clocks of the default clock (about 1.2 MHz). If it's really
    that slow, I wonder if it can be useful...

    Pascal
  • Hello Pascal,

    "(i.e. the falling and rising

    edge count of the LED are exactly half of the remote control signal count. "

    Do you mean that now you do not see the original problem of 2 interrupts?

         And to answer your question on speed , the execution of ISR, doesn't take 3000 clocks. Nor does the debugger connection slow down the device. If you have a breakpoint inside the ISR(and then press continue), as you had mentioned earlier, the pulses coming in during the time when the device is in a halt state, would be missed anyway.

    Did you already try adding a delay before clearing IFG to confirm that a second pulse doesn't happen until 2.5ms?

  • Hello!

    Thanks for your reply!
    Yes, in this case, I don't have the 2 interrupts.
    I have tried __disable_interrupts() as soon as I enter the ISR, and __enable_interrupts() before leaving,
    but it doesn't solve the problem.
    I had tried already to add delays, it doesn't change the problem. Except of course if I add a delay longer
    than my key press.
    I made another experiment: I used another launchpad, and I generate a 38 kHz wave when a button is
    pressed. Therefore I'm sure that the output of the IR decoder gernerates a single pulse. In this case, I
    don't have double interrupts, even at debug time.

    >> And to answer your question on speed , the execution of ISR, doesn't take 3000 clocks

    No, I guess it takes about 20 clocks. I remember that it was something like 17 on MSP430, but I may be wrong.
    If the debugger doesn't slow down the device, how do you explain that it works without debugger but doesn't
    work with it?

    I will try to isolate this behavior with a 1-page program. But it will need something to gernerate IR-like
    patterns.

    Pascal

**Attention** This is a public forum