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.

LPM3 long sleep mode

Other Parts Discussed in Thread: MSP430G2452, MSP430G2553

Hi,

I am writing a code with MSP430g2452 for an infrared obstacle detector device, in which a ring of IR transmitters and receivers create 360° detection area. I want to use LPM3 sleep mode and therefore I use the ACLK with no dividers. The idea is to to send a transmission pulse to each emitter one after the other. In order to do so, I set a compare interrupt so the when the timer counts to 5 (I need to create about 3 KHz pulses, so (2*5)/32768 gives me 3276Hz), the interrupt is called and I set the transmission flag. If the transmission flag is not set, the system goes to sleep mode and wakes up when the interrupt is called. In this way, i have the system operate constantly with sleep mode breaks between the interrupts. It all works fine with this approach. 

But my problem is this: I want to have much more efficient sleep mode in which i activate the system once in every minute or even an hour, send one full circle of transmission pulses and go to sleep again for another hour, rather that just sleep between interrupts.

but how do I do that? can I set 2 compare interrupts? I need the first interrupt for a short time in order to create the 3KHz pulses and a long one to activate the all system once in a certain time. i have been struggling with this for days and so far I failed to succeed so and I will really  appreciate any help!

Thanks in advance,

Levi

#include <msp430.h> 

int count = 0;
int flag = 0;

#define LED_150_OUT	P1DIR |= BIT1;
#define LED_210_OUT	P1DIR |= BIT3;
#define LED_270_OUT	P1DIR |= BIT4;
#define LED_330_OUT	P1DIR |= BIT5;
#define LED_30_OUT	P1DIR |= BIT7;
#define LED_90_OUT  P2DIR |= BIT0;
#define BRASS_OUT   P2DIR |= BIT1;
#define IO_OUT      P2DIR |= BIT2;
#define EN_OUT      P2DIR |= BIT3;

#define OUT_IN      P1DIR &= ~BIT2;
#define TEST_IN     P1DIR &= ~BIT6;

#define LED_150_OFF P1OUT &= ~BIT1;
#define LED_210_OFF P1OUT &= ~BIT3;
#define LED_270_OFF P1OUT &= ~BIT4;
#define LED_330_OFF P1OUT &= ~BIT5;
#define LED_30_OFF  P1OUT &= ~BIT7;
#define LED_90_OFF  P2OUT &= ~BIT0;
#define BRASS_OFF   P2OUT &= ~BIT1;
#define IO_OFF      P2OUT &= ~BIT2;
#define EN_OFF      P2OUT &= ~BIT3;

#define TOG_LED_150 P1OUT ^= BIT1;
#define TOG_LED_210 P1OUT ^= BIT3;
#define TOG_LED_270 P1OUT ^= BIT4;
#define TOG_LED_330 P1OUT ^= BIT5;
#define TOG_LED_30  P1OUT ^= BIT7;
#define TOG_LED_90  P2OUT ^= BIT0;

#define BRASS_ON    P2OUT  |= BIT1;
#define EN_ON  		P2OUT  |= BIT3;

int main(void)
{




	WDTCTL = WDTPW | WDTHOLD;		// Stop watchdog timer


    // Set up 32768Hz crystal

    BCSCTL1 |= DIVA_0;  			 // divide by 8
    BCSCTL3 |= XCAP_3;   			 // select 12pF caps


    TA0CCR0 = 5;    				 // set up terminal count for 3276 Hz
    TA0CTL = TASSEL_1 + MC_1;		 // configure and start timer ACLK, Count up



    LED_150_OUT 					// Set P1.1 to output direction
    LED_210_OUT 					// Set P1.3 to output direction
    LED_270_OUT						// Set P1.4 to output direction
    LED_330_OUT 					// Set P1.5 to output direction
    LED_30_OUT						// Set P1.7 to output direction


    LED_90_OUT; 					// Set P2.0 to output direction
    BRASS_OUT; 						// Set P2.1 to output direction
    IO_OUT; 						// Set P2.2 to output direction
    EN_OUT; 						// Set P2.3 to output direction

    OUT_IN							// Set P1.2 to input direction
    TEST_IN							// Set P1.6 to input direction

    LED_150_OFF
    LED_210_OFF
    LED_270_OFF
    LED_330_OFF
    LED_30_OFF

    LED_90_OFF
    BRASS_OFF
    IO_OFF
    EN_OFF





	  CCTL0 = CCIE;                            // CCR0 interrupt enabled


//	  __enable_interrupt();    // set GIE in SR


		while(1)
		{


			if (flag == 1){

					flag = 0;


							EN_ON							 // enable in high



							if ((count > 0) && (count <= 2))
								TOG_LED_150					// Toggle P1.1

							if ((count > 1) && (count <=3 ))

								TOG_LED_210					// Toggle P1.3

							if ((count > 2) && (count <= 4))

								TOG_LED_270					// Toggle P1.4

							if ((count > 3) && (count <= 5))

								TOG_LED_330					// Toggle P1.5

							if ((count > 4) && (count <= 6))

								TOG_LED_30					// Toggle P1.7

							if ((count > 5) && (count <= 7))

								TOG_LED_90					// Toggle P2.0

							if (count == 7)

								count=0;






							if ((P1IN & 0x04) == 0x04)
								{ 	//if P1.2 is high

									BRASS_OFF				//Buzzer off
								}


							else	{

									BRASS_ON				//Buzzer on
								}

				}

			//sleep mode
	 _BIS_SR(LPM3_bits + GIE);

		}

}

#pragma vector=TIMER0_A0_VECTOR
   __interrupt void Timer0_A0 (void)
   {		// Timer0 A0 interrupt service routine

	   	   	   count++;

			   flag = 1;


	   _BIC_SR(LPM3_EXIT); // wake up from low power mode

}

  • Shahar Levi said:

    But my problem is this: I want to have much more efficient sleep mode in which i activate the system once in every minute or even an hour, send one full circle of transmission pulses and go to sleep again for another hour, rather that just sleep between interrupts.

    but how do I do that?

    On particular chip you don't have option of RTC, so shall use timer. With 32768 Hz clock 16-bit timer overrun will occur once every 2 seconds. If you need to sleep for longer time like one hour, in timer ISR you just count time and continue to sleep while time to do something comes.

  • You can DIV8 the ACLK and further DIV8 TA0 timer = a very long sleep (128Seconds) with under 0.5uA power usages.
  • but with this divided clock how would I create the 3 KHz pulses? it is too slow
  • div aclk at least some, like /4= 8192KHz, CCR0=2, CCR=1 for a 2.73KHz (66/33 duty)

    Or upgrade to a Gxxxx that have two timers, one can be sourced from smclk while the other is from aclk/8/8

  • actually, if I'm not mistaken, MSP430g2452 has only one timer but maybe i should get the MSP430g2553 which has two timers and try your suggestion. Thanks for you help!
  • While CPU uses timer to generate scanning pulses, it does not need to count sleep time. While CPU is sleeping - it does not generate pulses. What's the problem to reuse timer?
  • I am not sure I understand. Since I want low-power mode LPM3 I am using the ACLK, and because I need 3 KHz pulses i cannot divide the ACLK but to leave it with 32768 Hz frequency. but that frequency gives me only 2 second overflow with the 16 bit counter. If I want longer sleep I need to divide the ACLK. am I missing something? can I use ACLK for the sleeping time and different clock (SMCLK) for generating the pulses. I am not sure, but I think that with the MSP430g2452 its not possible cause it only has one timer. i believe it is possible with the MSP430g2553. right? or you meant something else?
  • When is the 3KHz used?, while deep sleeping?
    What he say is while sleeping (a long pause) you switch /8 and /8 and when need to do the 3KHz you switch to /1 and /1

  • The 3 KHz is used not while sleeping but to generate the transmission pulses for the LEDs.

    Tony Philipsson said:


    What he say is while sleeping (a long pause) you switch /8 and /8 and when need to do the 3KHz you switch to /1 and /1

    but how can I do that? how do I switch to /8 and back?

    i mean if i divide the ACLK with BCSCTL1 |= DIVA_3 or/and with TACTL = TASSEL_1 + ID_3 + MC_1

    can i return later to /1 ? just write BCSCTL1 |= DIVA_0 and its back to 32768 Hz?

  • > BCSCTL1 |= DIVA_0
    Nope, common blunder DIVA_0 and ID_0= 0
    You can not do or/andn with 0, you have to over write values instead (or at least:  BCSCTL1 &= ~DIVA_3; // set DIVA_0 mode)
     
    TACTL = TASSEL_1 + ID_3 + MC_1;   // div by 8
    TACTL = TASSEL_1 + ID_0 + MC_1;   // div by 1 (ID_0 is not really needed as it's zero, e.g a placeholder)

    The last line could be replaced with TACTL |= TACLR;
    TAR may be cleared by setting the TACLR bit.
    Setting TACLR also clears the clock divider and count direction for up/down mode.

  • "Setting TACLR also clears the clock divider and count direction for up/down mode."
    Clearing the divider, which is a down-counter with underrun, also means that the next clock pulse will increment the timer once, independently of the divider setting (documented erratum). So the next tick will effectively 'ignore' the ID setting. On the long run (128s delay) it won't make a difference, though.

    "The last line could be replaced with TACTL |= TACLR;"
    Last line?
    TAR=0 can be replaced with TACTL|=TACLR. However, this will not clear the divider counter, so you don't know the length of the next tick. And IIRC, changing IDx doesn't change the divider counter too - if you switch from ID_8 to ID_1, you may still have the next 7 ticks swallowed by the divider. It's just on underrun, that it is set to 0..7 depending on IDx. So setting TACLR at least gives you a defined start.

**Attention** This is a public forum