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.

Problem with _BIC_SR(LPM3_EXIT);

Other Parts Discussed in Thread: MSP430G2553

Hi!

I am new to the MSP430. I asked a question month before and you told me there where a lot of errors in the code. I could not find it, because CCS dont tell it to me. But i wanted to make it good, so i used the command line tool on the Raspberry pi to program for the MSP430 and then a lot of errors where shown.

So i wrote the whole new code again step by step modified to be error free. Our project (an alarm clock) works now but it got some issues. But that is not the reason for my question. I want to modify the Interrupt handling and there is a thing i do not understand.

I use _BIC_SR(LPM3_EXIT); to leave the LPM3 in the interrupt and compile with CCS = no error and working blinking LED.

I use the command line on the Pi = error, invalid use of void expression.

The error is caused by the _BIC_SR(LPM3_EXIT); i think, because the error does not occur if i comment it out. What means the button cant wake up the MSP from sleep.


What can i do?


Enclosed the code. I use the clock crystal that came with the Lauchpad. The Button i use is an external, because Button2 on the Launchpad does not work here.

#include <msp430g2553.h>
int i;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;
BCSCTL1 |= DIVA_3; // ACLK/8
BCSCTL3 |= XCAP_3; //12.5pF cap- setting for 32768Hz crystal
P1DIR |= (BIT0 + BIT6);
P1OUT &= ~(BIT0 + BIT6);
P1IE |= BIT4;
P1IFG &= ~BIT4;
P1OUT |= ~BIT4;
P1IES |= BIT4;
P1REN |= BIT4;
CCTL0 = CCIE; // CCR0 interrupt enabled
CCR0 = 512; // wenn man den Wert auf 512 setzt taktet er jede 1 sec, bei 30720 jede 1 min, bei 1-> 256 mal pro sekunde
TACTL = TASSEL_1 + ID_3 + MC_1; // ACLK, /8, upmode
__enable_interrupt();
_BIS_SR(LPM3_bits + GIE);

for(;;)
{
//P1OUT^=BIT6;
for( i = 0; i < 1000; i++){
__delay_cycles(100000);
P1OUT^= BIT0;
}
P1OUT &= ~BIT0;
_BIS_SR(LPM3_bits + GIE);
}
}
// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
P1OUT^= BIT6;
}
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
P1IFG &= ~BIT4;
P1IES ^= BIT4;
_BIC_SR(LPM3_EXIT);
}


  • I found something here:

    http://develissimo.com/forum/topic/2837/

    There is written it is a bug in the header file common.h

    Could this be true?

    I have replaced _BIC_SR(LPM3_EXIT); with _BIC_SR_IRQ(LPM3_bits) and it works.

    What a trap. How to figure this out as a beginner?

  • I'm always using "LPM4_EXIT;" to leave LPM after execution of an ISR.

    H.

  • Do you use CCS or msp-gcc?

  • Steffen Müller said:
    ..

    What a trap. How to figure this out as a beginner?

    c is so easy to use, you can use it with eyes closed. Keep your eyes closed any there is no problem.

  • try using  the "LPM3_EXIT" OR "LPM4_EXIT" without any other syntax.

    because in the header file of the associated MCU "LPM3_EXIT" defined as below:

    #define LPM0_bits (CPUOFF)
    #define LPM1_bits (SCG0+CPUOFF)
    #define LPM2_bits (SCG1+CPUOFF)
    #define LPM3_bits (SCG1+SCG0+CPUOFF)
    #define LPM4_bits (SCG1+SCG0+OSCOFF+CPUOFF)

    #include "in430.h"

    #define LPM0 _BIS_SR(LPM0_bits) /* Enter Low Power Mode 0 */
    #define LPM0_EXIT _BIC_SR_IRQ(LPM0_bits) /* Exit Low Power Mode 0 */
    #define LPM1 _BIS_SR(LPM1_bits) /* Enter Low Power Mode 1 */
    #define LPM1_EXIT _BIC_SR_IRQ(LPM1_bits) /* Exit Low Power Mode 1 */
    #define LPM2 _BIS_SR(LPM2_bits) /* Enter Low Power Mode 2 */
    #define LPM2_EXIT _BIC_SR_IRQ(LPM2_bits) /* Exit Low Power Mode 2 */
    #define LPM3 _BIS_SR(LPM3_bits) /* Enter Low Power Mode 3 */
    #define LPM3_EXIT _BIC_SR_IRQ(LPM3_bits) /* Exit Low Power Mode 3 */
    #define LPM4 _BIS_SR(LPM4_bits) /* Enter Low Power Mode 4 */
    #define LPM4_EXIT _BIC_SR_IRQ(LPM4_bits) /* Exit Low Power Mode 4 */

    I wish it could help

  • Thank you that was the Thing i did not understand. That the LPM4_Exit that HardyGriech told me means that i have to write LPM3_EXIT without any other Syntax.

    It works, thank you both!

     

  • Jsut to add some clarification:

    teh BIS_SR intrinsics set bits in the status register. When the LPM bits are set there, the CPU is halted (and cannot execute code that clears the bits again).

    So when an ISR is entered, the current SR is saved to the stack and the bits are cleared, allowing the CPU to execute the ISR. On ISR exit, teh copy of the SR is loaded byck from teh stack and teh CPu halts again.

    So to stay aout of LPM when exiting the ISR, you need to modify the copy of the SR on the stack, and not the SR directly.
    Thsi is why there are two sets of interinsices, the BIx_SR() and BIx_SR_IRQ()

    LPMx and LPMx_EXIT are only alias defines for them that include the proper bit selection.

  • If i use 

    __enable_interrupt();
    LPM3;

    to enter the low power modus 3 i would be correct to use

    LPM3_EXIT;

    without any other syntax for exiting the LPM3 as goodarz kashian told me, right?

  • Steffen Müller said:
    If i use 

    __enable_interrupt();
    LPM3;

    You shouldn't. LPM3 already contains GIE bit. IT doesn't hurt to set it twice, but setting it in a separate instruction before entering LPM may cause a racing condition. What if the itnerrutp that shall wake you happens between setting GIE and entering LPM? Then exiting from LPM in the ISR won't do anything (you're not in LPM yet) and when you return from ISR, you'll enter LPm and no ISR will wake you again, as the interrupt already happened and was handled.

    You should always disable interrupts, set the IE bits that enable the interrupt source, then enter LPM by setting the LPM bits and the GIE bit simultaneously. "LPM3;" does this.

    Howeve,r using LPM3_EXIT inside the ISR when you want the LPM3 to end, is correct.

    For advanced players:
    It is possible to transition between LPMs without exiting LPM/continuing main, by individually setting or clearing specific LPM bits using the __BIx_SR_on_EXIT or similar intrinsics.
    So you can enable the clocks when a port event made it necessary to enable a data transfer, but main will remain stopped until the transfer happened. Or not at all, if not necessary.

  • It seems that LPM3; does not contain this for the MSP430G2553.

    In the msp430g2553.h file there is defined:

    #else /* Begin #defines for C */
    #define LPM0_bits (CPUOFF)
    #define LPM1_bits (SCG0+CPUOFF)
    #define LPM2_bits (SCG1+CPUOFF)
    #define LPM3_bits (SCG1+SCG0+CPUOFF)
    #define LPM4_bits (SCG1+SCG0+OSCOFF+CPUOFF)

    #include "in430.h"

    #define LPM0 _bis_SR_register(LPM0_bits) /* Enter Low Power Mode 0 */
    #define LPM0_EXIT _bic_SR_register_on_exit(LPM0_bits) /* Exit Low Power Mode 0 */
    #define LPM1 _bis_SR_register(LPM1_bits) /* Enter Low Power Mode 1 */
    #define LPM1_EXIT _bic_SR_register_on_exit(LPM1_bits) /* Exit Low Power Mode 1 */
    #define LPM2 _bis_SR_register(LPM2_bits) /* Enter Low Power Mode 2 */
    #define LPM2_EXIT _bic_SR_register_on_exit(LPM2_bits) /* Exit Low Power Mode 2 */
    #define LPM3 _bis_SR_register(LPM3_bits) /* Enter Low Power Mode 3 */
    #define LPM3_EXIT _bic_SR_register_on_exit(LPM3_bits) /* Exit Low Power Mode 3 */
    #define LPM4 _bis_SR_register(LPM4_bits) /* Enter Low Power Mode 4 */
    #define LPM4_EXIT _bic_SR_register_on_exit(LPM4_bits) /* Exit Low Power Mode 4 */
    #endif /* End #defines for C */

    I think it makes no sense that it does not contain it, but maybe i am too much beginner to say that. What should you do with a Sleepmode that never wakes up?

    So i have to use the 

    __enable_interrupt();

    or am i wrong?

    I can write 

    _bis_SR_register(LPM3_bits+GIE)

    but i dont know if that makes a difference to the version with __enable_interrupt(); and LPM3;.

  • The MSP430 itself pushes on entry of an interrupt service routine (ISR) the current PC and status register on the stack, then clearing all bits in SR except SCG0.

    This implies, that low power modes are turned off and further interrupts are disabled.

    LPM3_EXIT actually clears the LPM3-bits of the SR saved on the stack on interrupt entry.

    Thus leaving the ISR via RETI restores a manipulated version of SR, but also reenables interrupts (because they were already enabled on interrupt entrance).

    __enable_interrupt(); is actually only required once during system initialization.

    Read more in slau208, chapter 1.3.4

    Hardy

  • Steffen Müller said:
    I think it makes no sense that it does not contain it, but maybe i am too much beginner to say that.

    You're completely right. Entering LPM without setting GIE makes no sense, as it will effectively send the MSP to sleep until a hard reset. No further code will be executed ever.
    Maybe you have already set GIE before, but then it wouldn't hurt to set it again.
    So I'd consider this a bug in the header file.

    It also depends on the current application whether exiting LPM should also clear GIE or not. It could be necessary to ensure that main is executed before any further interrupt is handled.

    Steffen Müller said:
    So i have to use the __enable_interrupt(); or am i wrong?

    Again, it depends. If you want to enter LPM to wait for a sepecific event, you mus tnot enable interrupts before entering LPM. Or the event might happen after enablign interrupts but before entering LPM. Then the ISR will exit an LPM that hasn't been entered yet, and then you enter LPM and nobody will wake you.
    _bis_SR_register(LPMx_bits | GIE); is the proper way to do it then.

    But if you just want to enter LPM because main has nothing more to do, or if you jsu twant to wait for the next occurrence of a periodical event (the ISR will be called periodically and will exit LPM each time), then you can enable interrupts at start of your applciaiton (or after setting up the hardware) and enter LPM whenever you want.

  • Okay, thank you. So i will use it once in the system setup. that seems to work good for me.

    The next step for me is to figure out the possibilities of timer interrupts and PWM.

**Attention** This is a public forum