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.

MSP430FR2355: Failure to exit LPM0 using port 1 interrupts

Part Number: MSP430FR2355


Hi,

 I have a nA timer that is generating interrupt outputs. The output is connected to Port 1.1 and Port 1.2. I want the MSP 430 to turn off and enter it's lowest power state and then wake up on an interrupt from the timer. I have proven that the timer is generating interrupts by having a simple LED flash every time there is an interrupt. Now I am trying to enter LPM0 and wake up the device using the same interrupt. This does not work. Could you please help me with understanding what I have done wrong, the code is below.

In the code, you can see the LPM0 code that i have commented out. With this code commented out, the code functions as I expect, with the code executable, the processor stops and remains stopped on the BIS line. It seems like the interrupt is not detected. Do I need to set Port 1 into a different power mode when I am in LPM0 or something like that? The same behavior occurs in all LPM modes not just LPM0.

FYI Port 1 is set as all inputs, all interrupt flags enabled.

Thank you in advance

Richard

    while(1)
    {
    Data_Register=0x06;             //;
    register_data=read_a_byte();    //Communicate with i2C device and read a byte

    if(port_1_interrupt==1)         //If there is an interrupt simply flash an LED
        {
        P6OUT |= 0b1000000;
        _delay_cycles(1000000);
        P6OUT &=0b0000000;
        _delay_cycles(1000000);
        P6OUT |= 0b1000000;
        _delay_cycles(1000000);
        P6OUT &=0b0000000;
        _delay_cycles(1000000);
        port_1_interrupt=0;
        }
    _delay_cycles(100000);          //Wait to slow down communication loop

    //__bis_SR_register(LPM0_bits + GIE); <- if I uncomment this line, the code never sees an interrupt and does not wake up
    //__no_operation();
     }
     
     
     ///////////////////////////////// Port 1 interrupt service routine//////////////////////////////////////////
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
    //port2_interrupt_pending=1;
    P1IFG &=~0b111111110;         // Clear all the interrupt flags

    port_1_interrupt=1;           //Set a global flag

    __bic_SR_register_on_exit(LPM0_bits);// Exit from LPM to make CPU active
    __bis_SR_register(GIE);       //Enable Global Interrupts
}
     
     

  • Excuse the use of binary ! rather than hex! It's just test code.

  • Sorry Richard, did not mean to mark your comment as resolved! Let me look into this and get back to you

  • >  P1IFG &=~0b111111110; // Clear all the interrupt flags

    This looks odd, since it doesn't clear an interrupt on P1.0, so (if P1IE=0xFF) that interrupt will trigger forever. Did you mean

    >  P1IFG &=~0b11111111; // Clear all the interrupt flags

    -----------

    Unsolicited: I recommend you avoid doing this in an ISR:

    >     __bis_SR_register(GIE);       //Enable Global Interrupts

    GIE will be restored (un-stacked) shortly, and this opens up a window which could cause you trouble.

  • Thanks for the response , I 'm using P1.0 for ADC, so I don't need to clear that flag.

  • I didn't know that , I have been writing code where i have been using this in interrupts for a long time - I guess there is a bug waiting to happen!

  • Connecting P1.0 to the ADC (PSEL=3) doesn't disconnect it from the GPIO logic (it just turns off the Schmitt trigger). If you're not interested in P1IFG.0, I suggest you use P1IE=0xFE.

    It's probably enlightening to set a breakpoint in the PORT1 ISR to see whether/why it triggers (for either case).

  • It is unclear to me what the configuration of the timer is. You say it generates interrupt outputs and this is connected to Port 1. Timer interrupts are not the same as the timer output unit so I can't tell what you have going on here without the timer code.

    Actually I have no idea why a port interrupt is involved. You say you want to wake up using the timer interrupt. Why not do that in the timer ISR?

  • There is no MSP timer involved. I have an external timer that provides an interrupt on Port 1. The reason to do this is that the MSP dissipates too much power  for my application with the lowest timer active mode. 

  • I have done this, the interrupt triggers because of an interrupt on port 1 as expected. 

  • When the interrupt triggers, what is the value of P1IFG?

    --------------

    Another thing that may not be obvious: When the ISR clears LPM0_bits (in main's SR), that is only effective if they're set, i.e. when main is sitting in LPM. If it happens to be doing something else at that moment e.g. spinning in __delay_cycles(), the wakeup indication is lost. In that case main will sit in LPM until the next wakeup i.e. GPIO interrupt.

  • It takes work to get a MSP430 to dissipate power in a low power mode. Typically less than 10uW in LPM3.

    Another thing. The declaration for port_1_interrupt isn't shown. If this isn't a volatile then the compiler is going to see that the comparison in your while loop will never be true. And delete all of that bit twiddling code.

  • The P1IFG flag is 0x02 in the interrupt.

  • I like the bit twiddling code! it flashes the led.

  • Hi David,

     I can see what is happening, the first time through the code, the interrupt fires , the LED flashes as expected and the code then stops on     __bis_SR_register(LPM0_bits + GIE); (obviously uncommented) . So this means that the interrupt PORT 1 signal is present and that the processor recognizes it. It seems that when the code then enters     __bis_SR_register(LPM0_bits + GIE); the interrupt is no longer seen which makes me suspicious that I have to enable a power supply for Port 1 before entering LPM0. It looks like the interrupt is just not firing.  Now, to add to the argument, I have entered LPM0 with an MSP timer running and that does work as expected, so it really looks like a port /power down / unrecognized interrupt issue.

  • You say the interrupt fires the first time through the code. Are you sure? You don't show where GIE is set. (If it was previously set, then why do it again?) You also don't show the initialization for the port. That could easily result in an immediate interrupt independent of whatever any signal is doing to the port.

  • No I'm not sure, i think I fooled myself.

  • Any luck in suggesting a possible issue Amruta?

  • David, thanks very much for contributing - it is most appreciated.  I was flashing the LED outside of the interrupt, that's what fooled me.  I have a scope on the P1 pin , the interrupt signal is a low going pulse ~8 seconds period, 10mS width. Without the call to LPM0, I get an expected LED flash every ~8seconds, so I believe that hardware wise the system is correct and though maybe a bit flawed, the code is doing what I expect, however when I run the code with LPM0 enabled the code stops for ever on that line. Do you have any ideas on whether Port 1 is turned off in LPM0?

  • You can't turn port 1 off. It has to be something you haven't shown. Port 1 initialization perhaps.

    Posting a complete listing of the code that shows the problem is the only way to go.

  • I can't list all of the code, there are too many routines, however, here is what I believe to be important, the P1 set up code. 

        ///PORT 1 SET UP
        P1SEL0 |= 0b1;                              // Configure ADC A1 pin 0
        P1SEL1 |= 0b1;
        P1DIR =  0b00000000;                           //Port 1 set as inputs
        P1IE |=  0b11111110;                          // interrupt enabled
        P1IES |= 0b00000000;                          // Lo/Hi edge
        P1IFG &= 0b00000000;                          // IFG cleared
        //P1OUT = 0b00000000;
        PM5CTL0 &= ~LOCKLPM5;

  • Not all the code. Pare it down to the minimum required to demonstrate the problem. As a bonus, there is a good chance that while doing that you will notice the source of the trouble.

    You appear to have missed the initialization sequence described at 8.3.1. You can't clear P1IFG until after clearing LOCKLPM5.

    Your code leaves P1IES unchanged which is a problem because it has no defined state after PUC.

    I sure hope you have all those pins tied either high or low. Otherwise those CMOS inputs will float around and cause trouble. If you only have one signal to create an interrupt, enable the interrupt for that pin only. Doing them all just asks for trouble.

  • Hi David,

     I think I have the solution to the problem and it is remarkably strange. The off board timer chip I am using is the MAX31341B. You communicate with it over I2C to set up the time , read the time, set alarms, set a countdown timer etc.  So I set up the count down timer for 30 seconds.  I then used the I2C to monitor the chip status and I could see that indeed when the chip counted down to zero an interrupt is generated and the LED on the MSP430 flashes as expected. This shows that everything is connected and the interrupts are being called.  

    Then I invoke the LPM0 mode and expect the MSP 430 to wake up when the counter completes, unfortunately, for a reason I don't yet understand, unless there is I2C communication with timer, the timer chip does not produce an interrupt and hence the MSP 430 never wakes up. This is what led me down the path of suspecting my code or some issue with the MSP430. 

    I have also tried disabling the LPM0 mode, putting the MSP in its active state and running the code without I2C comms, I get the same failure. So it looks a this point that the MAX31341B just doesn't produce interrupts unless there is some form of I2C communication present. This behavior is not mentioned in the datasheet and it is surprising (to be frank it doesn't make any sense) and I can't believe this is how the device is meant to work. My next step is to get technical support from Maxim. 

    With the MSP430 in LPM0 mode , I can make the MAX chip produce a 1 second clock, so I can use that to wake up the MSP430 but then I won't meet my power goals, I need more like 30 seconds in between interrupts. 

    Thank you for your help

    Sincerely 

    Richard

  • I am still not sure why you need the external RTC. There is a slight savings in power using it and LPM4.5 versus using just the MSP430 and its RTC and LPM3.5.

    And for the .5 low power modes you get basically a power up reset rather than interrupt sort of action.

  • Do you need to clear TIF (by reading register 0x05) in order to clear the INTx  so you can get another edge? That would imply at least one I2C transaction per cycle. Even so, with TRPT=1 you're supposed to get at least one TIF/INTx trigger.

  • I agree, I should be seeing at least one interrupt. In the code that register is read and I can see on the oscilloscope that the particular bit goes high for an interrupt and then goes low after it is read, which is the expected behavior. The problem is that I don't get any interrupts when the I2C comms has stopped - or at least that's what it looks like ( I just don't believe it, I'm missing something obvious).  There again, I have both alarms working, interrupts generated as normal, but if I stop that I2C read, I get nothing so maybe it really is the case,

  • Is it possible your I2C bus is hung up somehow?

    Does your I2C code use LPM? Another perhaps non-obvious thing about LPM wakeup is that it is anonymous. If there are multiple wakeup sources in your program, it's up to the wakeup-ee to assure that the thing it was waiting for has actually happened. (In the code you posted that's served by the port_1_interrupt global.)

**Attention** This is a public forum