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.

MSP432P401R: Interrupt Latching

Part Number: MSP432P401R
Other Parts Discussed in Thread: MSP430FR2433

Hi,

My question is about interrupt handling on the MSP432, and perhaps more specifically to what extent the NVIC latches interrupts. Scenario as follows:

  1. Several Port 4 input interrupts are enabled;
  2. An interrupt occurs on a Port 4 line, and the handler is entered;
  3. While still in the handler, an interrupt occurs on a second Port 4 line - second interrupt is presumably 'pended';
  4. Before the handler exits, the port’s IE bit for the second Port 4 line is cleared;
  5. The handler then exits.

What then happens? It seems to me two possibilities:

  • Either the handler is NOT run again for the second interrupt, because the IE bit is now clear;
  • OR the handler WILL run again, despite the IE bit now being clear, because the IE bit was still set at the time of the second interrupt, so the interrupt went to ‘pending’ and this was latched by the NVIC.

I’ve had a weird bug which I can only really explain if the second answer is correct, but I find it hard to believe that was the design intent…..

Any views appreciated!

Thanks…. Happy Christmas!

John

 

  • John,

     This particular case is covered  in the MSP432 Technical Reference Manual, section 12.2.7 on Port Interrupts describes the expected behavior when a gpio interrupt is asserted while still in the ISR for another port interrupt: (see the section in Red below for answer to your particular question- the short response is that your 2nd answer is correct).

    12.2.7 Port Interrupts

    All Px interrupt flags for a particular port are prioritized, with PxIFG.0 being the highest, and combined to source a single interrupt vector. The highest priority enabled interrupt generates a number in the PxIV register. This number can be evaluated or added to the program counter to automatically enter the appropriate software routine. Disabled Px interrupts do not affect the PxIV value. The PxIV registers are half-word access only.

    Each PxIFG bit is the interrupt flag for its corresponding I/O pin, and the flag is set when the selected input signal edge occurs at the pin. All PxIFG interrupt flags request an interrupt when their corresponding PxIE bit is set. Software can also set each PxIFG flag, providing a way to generate a software-initiated interrupt.

      • Bit = 0: No interrupt is pending
      • Bit = 1: An interrupt is pending

    Only transitions, not static levels, cause interrupts. If any PxIFG flag becomes set during a Px interrupt service routine or after Px interrupt service routine execution is completed, the set PxIFG flag generates another interrupt. This ensures that each transition is acknowledged.

    NOTE: PxIFG flags when changing PxOUT, PxDIR, or PxREN
                Writing to PxOUT, PxDIR, or PxREN can result in setting the corresponding PxIFG flags.

    Any access (read or write) of the PxIV register automatically resets the highest pending interrupt flag. If another interrupt flag is set, another interrupt is immediately generated after servicing the initial interrupt.

    For example, assume that P1IFG.0 has the highest priority. If the P1IFG.0 and P1IFG.2 flags are set when the interrupt service routine accesses the P1IV register, P1IFG.0 is reset automatically. After the completion of P1IFG.0 interrupt service routine, the P1IFG.2 generates another interrupt.

     

    Regards,

      Bob L.

  • Thanks for taking the time to reply, Bob! I'd perused that section of the manual, but had assumed that clearing the second port line's IE bit, even once the second line's IFG bit was set, would prevent the second interrupt from being taken..... You seem to be saying that the manual has to be taken very literally, and that the IE bit is irrelevant in this situation, only the IFG flag is important? That's not what I expected, but I must admit it does appear to be what I'm seeing.....

    Best wishes,
    John
  • I was sufficiently surprised by this result that I had to try it.

    Bob is (as usual) correct, though I would instead reference SLAU356H sec 2.2.2.1-2 (which appears to be adapted from ARM's DUI0553A sec 4.2.9). I always supposed that, due to the intervention of the IV, the GPIO presented a Level interrupt, but apparently it is a Pulse directly from the IFG+IE.

    This Useless Little Program lights both Launchpad LEDs, where for a Level interrupt I would expect only one to light. The debugger confirms that on the second ISR call P1IE.4=0 and P1IV=0 (and yet Here We Are).

    /**
     * main.c
     * This brainless example demonstrates that the GPIO system
     * presents a Pulse rather than a Level interrupt to the NVIC.
     * Pushing the P1.1 Launchpad button results in both LEDs being lit,
     * where for a Level interrupt we would expect only one to light.
     * Stopping in the second ISR call shows (P1IFG&P1IE) == 0, IV=0.
     */
    #include "msp.h"
    void main(void)
    {
    	WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD;		// stop watchdog timer
    	//  LEDs:
        P1->OUT &= ~BIT0;        // Launchpad P1.0 LED off
        P1->DIR |= BIT0;         //    +output
        P2->OUT &= ~BIT0;        // Launchpad P2.0 LED
        P2->DIR |= BIT0;
        //  Buttons:
        P1->OUT |= BIT1|BIT4;    // Launchpad buttons
        P1->REN |= BIT1|BIT4;    //   pullup
        P1->IES |= BIT1|BIT4;    // High->Low
        __no_operation();        // Per PORT32
        P1->IFG &= ~(BIT1|BIT4); // Clear stale
        P1->IE  |= BIT1|BIT4;
        NVIC_EnableIRQ(PORT1_IRQn);
    	while (1)
    	{
    	    __WFI();
    	}
    	/*NOTREACHED*/
    	return;
    }
    
    void
    PORT1_IRQHandler(void)
    {
        if (P1->IFG & BIT1)             // I pushed the (P1.1) button
        {
            __delay_cycles(50000);      // Cheap imitation debounce
            P1->IFG &= ~BIT1;           // I guess it's quiet now
            P1->IFG |= BIT4;            // Trigger P1.4 interrupt
            __delay_cycles(50);         // Just in case of propagation race
            P1->IE  &= ~BIT4;           // Now disable it
            P1->OUT |= BIT0;            // Light LED to show we got here
        }
        else if (P1->IFG & BIT4)        // I Promise I didn't push the (P1.4) button
        {
            P1->IFG &= ~BIT4;           // Thank you, now go away
            P2->OUT |= BIT0;            // Light LED to show we got here
        }
        return;
    }
    

  • Thank you Bruce! Well my word, what a surprise..... and very valuable to know! I'd mulled over doing a trivial-program test myself after Christmas break, but you've beaten me to it.... thanks for your help! And thanks to you too, Bob....

    Best wishes,
    John
  • Having now played about with this myself.... just to add some final clarification to this (I'm sure you knew this, Bruce, but felt it worth saying here):

    When, despite the IE bit being cleared, the interrupt routine is entered the second time, the Interrupt Vector is indeed zero. Reading the Vector Register in this situation does NOT clear the IFG flag - it remains set (as may well have been guessed from the Technical Manual info).

    Assuming the IFG flag is left set: If, in the normal program flow at some time after the interrupt routine has completed, the IE flag for that port line is again set, a further interrupt will be triggered - this rather confirms Bruce's suggestion that this is a 'pulse trigger' into the NVIC being derived from the IE bit AND'd with the IFG bit. In this case (assuming the IE bit was left set) the Vector Register will contain the expected value, and reading it will clear the IFG flag as expected. So provided the interrupt routine correctly handles the "Vector Register = 0" case as a spurious interrupt (which mine sadly didn't), I suspect that in many cases all would be well, albeit with an extra unexpected trip through the interrupt handler...

    Thanks again Bruce, Bob,

    John

  • In case anyone's wondering (I suddenly did): The MSP430 behaves the other way. I translated that program for (in this case) the MSP430FR2433, and only one of the LEDs lights (there is no second ISR call):

    /**
     * main.c
     * This brainless example demonstrates that the MSP430(FR2433) GPIO system
     * presents something more like a Level interrupt to the interrupt controller.
     * Pushing the P2.3 Launchpad button results in only one LED being lit.
     * (There is no second ISR call.)
     */
    #include "msp430.h"         // MSP430FR2433, but mostly its Launchpad
    void main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;    // Stop watchdog timer
        //  LEDs:
        P1OUT &= ~BIT0;         // Launchpad P1.0 LED off
        P1DIR |= BIT0;          //    +output
        P1OUT &= ~BIT1;         // Launchpad P1.1 LED off
        P1DIR |= BIT1;          //    +output
        //  Buttons:
        P2OUT |= BIT3|BIT7;     // Launchpad buttons
        P2REN |= BIT3|BIT7;     //   pullup
        P2IES |= BIT3|BIT7;     // High->Low
        __no_operation();       // Per PORT32
        PM5CTL0 &= ~LOCKLPM5;   // Should be OK now
        P2IFG &= ~(BIT3|BIT7);  // Clear stale
        P2IE  |= BIT3|BIT7;     // Enable
        _EINT();
        P1OUT |= BIT0|BIT1;     // Make sure both LEDs work.
        __delay_cycles(500000); // About a half second
        P1OUT &= ~(BIT0|BIT1);  // End of that exercise
        while (1)
        {
            LPM0;
        }
        /*NOTREACHED*/
        return;
    }
    
    #pragma vector=PORT2_VECTOR
    __interrupt void
    PORT2_IRQHandler(void)
    {
        if (P2IFG & BIT3)             // I pushed the (P2.3) button
        {
            __delay_cycles(50000);    // Cheap imitation debounce
            P2IFG &= ~BIT3;           // I guess it's quiet now
            P2IFG |= BIT7;            // Trigger P2.7 interrupt
            __delay_cycles(50);       // Just in case of propagation race
            P2IE  &= ~BIT7;           // Now disable it
            P1OUT |= BIT0;            // Light LED to show we got here
        }
        else if (P2IFG & BIT7)        // I Promise I didn't push the (P2.7) button
        {
            P2IFG &= ~BIT7;           // Thank you, now go away
            P1OUT |= BIT1;            // Light LED to show we got here
        }
        return;
    }
    

**Attention** This is a public forum