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.

How to awake the MCU from LPM3?

Other Parts Discussed in Thread: CC1150

Dear freinds

You may saw the piece of code that I am inserting below in other discussions, but I really need you help as I am stuck and not making any progress . I am doing using MSP430g3553 to communicate with the accelerometer of BNO055 (via UART), as such I am using the code below which works fine. However this piece will be part of a larger program that is used to run a sensor tag (build from MSP430 MCU and cc1150) to transmit the data. Thus you can see that I am using malloc function. 

Now, when I run the sensor tag program its getting halted in the 1st line of the malloc (acceleration_location = malloc(6)) and thus the sensor tag does not transmit.

I think that the MCU is still in LPM3. So how to get it awake from that state? is it by using while or for? and where to place these as I tried by I may be mistaken in placing them. please advise.

PS1: the sensor tag uses the SPI over USCI B to communicate with the CC1150, and thus I am using thr USCI A to communicate over the UART.

PS2: please note that I have commented out this line in the RX ISR and the code is working fine

// __bic_SR_register_on_exit(LPM3_bits);

Your help is highly appreciated

/*
 * Acceleration.c
 *
 *  Created on: Oct 6, 2016
 *      Author: Murtadha
 */
#include "Acceleration.h"
// the saved value of the previous measurement
uint8_t cached_accelerationXMSB = 0, cached_accelerationXLSB = 0;

uint8_t cached_accelerationYMSB = 0, cached_accelerationYLSB = 0;

uint8_t cached_accelerationZMSB = 0, cached_accelerationZLSB = 0;

uint8_t* acceleration_location;		// pointer to the location used in the transmit buffer for accelerometer data


typedef struct uart                        // UART
{   char *bufTXpnt;                        // UART TX buffer pointer
    unsigned int TXbuflen;                  // the lenght of TX block
    char *bufRXpnt;                       // UART RX buffer pointer

    unsigned int RXbuflen;                  // the lenght of RX block
    char TXbuffer[8];
    char RXbuffer[8];
} uartstruct;

/////  macro to get string and string len
#define   TXSTRING(pnt) (TXdata((pnt), sizeof(pnt)-1))
uartstruct uart;                 // declare a struct from typedef uartstruct

void TXdata( char* pnt, unsigned int len){
  uart.bufTXpnt = pnt;
  uart.TXbuflen = len;
  uart.bufRXpnt = uart.RXbuffer;         // reset it to beginning of ram buffer

  IE2 |= UCA0TXIE + UCA0RXIE;            // enable USCI_A0 TX & RX interrupt
}

///Intilizing the UART////////////////////////////////////////////////////
void uart_init(void){
 IE2 &= ~(UCA0TXIE | UCA0RXIE); // Disable all USCIx0 (A) TX & RX interrupts
  UCA0CTL1 = UCSWRST;           // Set UCSWRST (hold USCI in Reset state)
  UCA0CTL1 |= UCSSEL_2;                     // CLK = SMCLK

//   ------------ Configuring the UART(USCI_A0) ----------------//
//     115200 BAUD, CLK=12MHz
    		  UCA0BR0 = 6;
    		  UCA0BR1 = 0;
//    		//*ours: UCBRF = 8, UCBRS = 0, UCOS16 = 1
//    		  // BITS| 7 6 5 4 | 3 2 1  |   0    |
    		  // UCAxMCTL = | UCBRFx  | UCBRSx | UCOS16 |
    		  UCA0MCTL = 0x81; //this works fine

    UCA0CTL1 &= ~UCSWRST;             // Clear UCSWRST to enable USCI_A0-UART
    UCA0CTL1 &= ~UCSYNC;

  IFG2 |= UCA0TXIFG;            // preset IFG flag always left on

  IE2|=UCA0RXIE;
}

//**********************************************
//Configure clocks and clock sources
void set_UCS() {
	/* DCO Frequency selected */
	/* SCLK=SMCLK  P1.5  */
	/*	Maximum SPI frequency for burst mode is 6.5 MHz	*/
	//Set DCO to 12 MHz calibrated and use DCO/2 for SMCLK
	//Note that this is technically a bit too high for operation at 2.2Volts (end of battery life).  8 MHz is maximum recommended.
	//Does not seem to be a problem at room temperature.
	DCOCTL = CALDCO_12MHZ;		//0x7A  01111010
								//DCOx  011
								//MODx	11010

	/* External Crystal OFF, LFEXT1 is low frequency, ACLK is Divided by 1, RSELx=1110 */
	// Set range  0x8E  10001110
	BCSCTL1 = CALBC1_12MHZ;

	// DCO -> SMCLK (Default), SMCLK / 2; DCO -> MCLK, MCLK / 2; DCOR Internal Resistor select
	BCSCTL2 = DIVS_1 + DIVM_1 + SELM_0; // 0x52 = 00010010

	/* 0.4 to 1MHz crystal , Using VLO for ACLK, Cap selected 1pF */
	BCSCTL3 = LFXT1S_2;

	IE1 &= 0xFD; /* Disable UCS interrupt */

	return;
}
//********************************************************************

//------------------- Configure the UART Clock source -------------------//
void set_UARTUCS() {
	     WDTCTL = WDTPW + WDTHOLD; // Stop the Watch dog
	     DCOCTL  = 0;             // Select lowest DCOx and MODx settings
	     BCSCTL1 = CALBC1_12MHZ;   // Set range
	     DCOCTL  = CALDCO_12MHZ;   // Set DCO step + modulation

	     // DCO -> SMCLK (Default)
	     IE1 &= 0xFD; /* Disable UCS interrupt */

	     return;
   }

//--------- Setting the UART function for P1.1 & P1.2 --------//
void setUARTPins() {

	        //    P2DIR = 0xFF; // All P2.x outputs<
	            //P2OUT &= 0x00; // All P2.x reset
	            P1SEL |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
	            P1SEL2 |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD

	         //   P1OUT &= 0x00;
	         return;
}

//¦----------------------------- Delay Function  ---------------------------------------¦

// This function will give us 1ms wait time, so for getting 10 ms,
// then delay_ms(10) will give 10ms and delay_ms(100) will give 100ms
void delay_ms(unsigned int ms)
{
    unsigned int i;
    for (i = 0; i<= ms; i++)
       __delay_cycles(6000); // 6000 will give us 1ms
}

//¦----------------------------- US0TX ISR  ---------------------------------------¦
#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCIAB0TX(void)                    // Shared A0/B0 TX IRQ vector
{
  if (IFG2 & UCA0TXIFG){                            // check for UART TX

    if (uart.TXbuflen){                               // if not zero
      UCA0TXBUF = *uart.bufTXpnt++;
      --uart.TXbuflen;
    }
    else IE2 &= ~UCA0TXIE;                          // suspend IE if zero
  }
  else IFG2 &= ~UCA0TXIFG;                          // clear a false UCB0 trigger
}

//¦----------------------------- US0RX ISR  ---------------------------------------¦
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCIAB0RX(void)                     // A0/B0 RX IRQ vector
{
 if (IFG2 & UCA0RXIFG){                              // check for UART RX

   *uart.bufRXpnt++ = UCA0RXBUF;                     // copy data byte
//   if (uart.bufRXpnt == uart.RXbuffer+8 && uart.RXbuffer[0]==0xBB)           // got 8 bytes in yet?  <<<<
//	   uart.RXbuflen=uart.RXbuffer[1];
//   __bic_SR_register_on_exit(LPM3_bits);


  // if (!--uart.RXbuflen){

   //commneted 10/14/2016
   //   if (uart.bufRXpnt == uart.RXbuffer+uart.RXbuffer[1]) //uart.RXbuffer[1] includes the length of the received string from the BNO055
//   {
//	   __bic_SR_register_on_exit(LPM3_bits);
//   }
   }
 else IFG2 = ~UCA0RXIFG;
}

///////////////getAcceleration will make the MSP430 talks to the BNO055
void getAcceleration() {

	// Enable intterupts
//////commented on 10/12/2016 //intterupts enabled in the main function below
//	 IE2 |= UCA0TXIE;                  // Enable the Transmit interrupt
//	 IE2 |= UCA0RXIE;                  // Enable the Receive  interrupt
//	 _BIS_SR(GIE);                     // Enable the global interrupt


	 //Put BNO055 in CONFIG mode********required (do not change)
	    TXSTRING("\xAA\x00\x3D\x01\x00");    // Send this to the BNO055 to set up the CONFIG mode
	    delay_ms(10); // do not change (80)
	    while (IE2 & UCA0TXIE);

	 //Put BNO055 in NORMAL power mode********required (do not change)
		 TXSTRING("\xAA\x00\x3E\x01\x00");    // NORMAL power mode
		 delay_ms(20); // do not change (20)  delay_ms(2000)
		 while (IE2 & UCA0TXIE);

		//Put BNO055 in AMG mode********selecting operating mode is required (do not change)
		TXSTRING("\xAA\x00\x3D\x01\x07");    // Send this to the BNO055 to set up the ACC ONLY mode
		delay_ms(80); // do not change (80) delay_ms(2000)
		while (IE2 & UCA0TXIE);

		TXSTRING("\xAA\x01\x08\x06");
		delay_ms(10); //this delay is required..do not change (10) // delay_ms(10000)
		while (IE2 & UCA0TXIE);

		/*
		 * ACC_DATA_X_LSB 0x08=RXbuffer[2];
		 * ACC_DATA_X_MSB 0x09=RXbuffer[3];
		 * ACC_DATA_Y_LSB 0x0A=RXbuffer[4];
		 * ACC_DATA_Y_MSB 0x0B=RXbuffer[5];
		 * ACC_DATA_Z_LSB 0x0C=RXbuffer[6];
		 * ACC_DATA_Z_MSB 0x0D=RXbuffer[7];
		 */

		cached_accelerationXLSB = uart.RXbuffer[2];
		cached_accelerationXMSB = uart.RXbuffer[3];
		cached_accelerationYLSB = uart.RXbuffer[4];
		cached_accelerationYMSB = uart.RXbuffer[5];
		cached_accelerationZLSB = uart.RXbuffer[6];
		cached_accelerationZMSB = uart.RXbuffer[7];

		// Send this to the BNO055 to set up the CONFIG mode....DO NOT CHANGE or DELETE
//		TXSTRING("\xAA\x00\x3D\x01\x00");    // Send this to the BNO055 to set up the CONFIG mode
//	    delay_ms(10); // do not change (80) delay_ms(2000)
//		while (IE2 & UCA0TXIE);
//
//		// Send this to the BNO055 to set up the SUSPEND mode....
//		TXSTRING("\xAA\x00\x3E\x01\x02");    // SUSPEND power mode
//	    delay_ms(20); // do not change (20)  delay_ms(2000)
//		while (IE2 & UCA0TXIE);

///////commented on 10/12/2016 //LP
		//		__bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ int until Byte RXed

		return;
    }

//¦----------------------------- Main Function-------------------------------------------¦
void doAccelerationSense() {
	// void doAccelerationSense(bool update) {

	// If called with update=true, perform a measurement
		//if (update) {
			cached_accelerationXMSB = 0;  // Considered an "invalid" value
	        cached_accelerationXLSB = 0;  // means the sensor did not work

	        cached_accelerationYMSB = 0;
	        cached_accelerationYLSB = 0;

	        cached_accelerationZMSB = 0;
	        cached_accelerationZLSB = 0;

	// *** Save state of all registers modified by the acceleration sensing code ***
	        uint16_t original_P1DIR = P1DIR;
	        uint16_t original_P1IE = P1IE;
	        uint16_t original_P1OUT = P1OUT;
	        uint16_t original_P1REN = P1REN;
	        uint16_t original_P1SEL = P1SEL;
	        uint16_t original_P1SEL2 = P1SEL2;

	        setUARTPins();
	        uart_init();
	        set_UARTUCS();

	    	// Enable intterupts
	        IE2 |= UCA0TXIE;                  // Enable the Transmit interrupt
	        IE2 |= UCA0RXIE;                  // Enable the Receive  interrupt
	        _BIS_SR(GIE);                     // Enable the global interrupt


	        ///////////////getAcceleration will make the MSP430 talks to the BNO055
	        getAcceleration();

	        // *** Restore all registers modified by the acceleration sensing code back to their previously saved state ***
       		P1IE = original_P1IE;
       	    P1DIR = original_P1DIR;
       		P1REN = original_P1REN;
       		P1SEL = original_P1SEL;
       		P1SEL2 = original_P1SEL2;
       		P1OUT = original_P1OUT;

       		set_UCS();
    		__bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ int until Byte RXed

}
//Acceleration.c (main function ends here)
/////////////////////////////////////////////////////////////////////////////
		// Save value to transmit buffer
//		    acceleration_location = malloc(6);
//			acceleration_location[0] = ((uint8_t*) &cached_accelerationXMSB)[0]; //check this (the order)
//			acceleration_location[1] = ((uint8_t*) &cached_accelerationXLSB)[0]; // see line 196~
//			acceleration_location[2] = ((uint8_t*) &cached_accelerationYMSB)[0];
//			acceleration_location[3] = ((uint8_t*) &cached_accelerationYLSB)[0];
//			acceleration_location[4] = ((uint8_t*) &cached_accelerationZMSB)[0];
//			acceleration_location[5] = ((uint8_t*) &cached_accelerationZLSB)[0];
//}

  • Your current code will get stuck at line# 274. The CPU will sleep in LPM3 most of the time. Occasionally, an ISR may be executed. But since none of your ISRs has a "__bic_SR_register_on_exit(LPM3_bits);"instruction inside, the CPU will go back to line# 247 and sleep again.

    In a sense, you are lucky that no ISR tries to wake up the CPU. Because line# 247 is at the end of the road (main), if one of the ISRs wakes up the CPU, it will roll off the end of road (main) and fall into a cliff.

    Your line# 276 is the end. Beyond that, there are only comments and the CPU will not do anything for you.
  • Thank you for your reply,

    But I am just commenting the code after line #276 in this version of code. I need it to continue (please ignore these comments) as the data should be taken care of the malloc function. For doing that, should I clear the LPM3 in both ISRs?

    Thank you

  • Usually, you go to a LPM to wait for a certain event before you want to proceed. In the mean time you also want to have interrupts serviced. When the interrupt indicating the event you are waiting for happens, that ISR should should clear the LPM bits on exit.
  • thank you for the replay, old_cow_yellow

    but seems I am stuck with these interrupts. I un commented the following in the RX ISR

      if (uart.bufRXpnt == uart.RXbuffer+uart.RXbuffer[1]) //uart.RXbuffer[1] includes the length of the received string from the BNO055
       {
    	   __bic_SR_register_on_exit(LPM3_bits);
       }

    but still stuck. So would you please help me by applying the recommended changes into my code? I appreciate your help

    here is my main as well:

    #include <msp430.h> 
    
    /*
     * main.c
     */
    void main(void) {
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
        doAccelerationSense();
    return;
    }
    

  • Murtadha A said:

    but seems I am stuck with these interrupts. I un commented the following in the RX ISR

      if (uart.bufRXpnt == uart.RXbuffer+uart.RXbuffer[1]) //uart.RXbuffer[1] includes the length of the received string from the BNO055
       {
    	   __bic_SR_register_on_exit(LPM3_bits);
       }

    but still stuck. So would you please help me by applying the recommended changes into my code?

    I do not know (a) if RX interrupt is generated during LPM3, (b) if RX ISR is invoked during LPM3, (c) if the first line you quoted is reached, (d) if the condition in that line is met. Only when all (a), (b), (c), and (d) are met, LPM3 will be awaken.

    Murtadha A said:

    here is my main as well:

    #include <msp430.h> 
    
    /*
     * main.c
     */
    void main(void) {
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
        doAccelerationSense();
    return;
    }

    I have no idea what "doAccelerationSense();" does. You have never shown that before. Was it stuck? What does that got to do with LMP3?

  • doaccelereationsense() is this code.

    //¦----------------------------- Main Function-------------------------------------------¦
    void doAccelerationSense() {
         {
                cached_accelerationXMSB = 0;  // Considered an "invalid" value
                cached_accelerationXLSB = 0;  // means the sensor did not work
    
                cached_accelerationYMSB = 0;
                cached_accelerationYLSB = 0;
    
                cached_accelerationZMSB = 0;
                cached_accelerationZLSB = 0;
    
        // *** Save state of all registers modified by the acceleration sensing code ***
                uint16_t original_P1DIR = P1DIR;
                uint16_t original_P1IE = P1IE;
                uint16_t original_P1OUT = P1OUT;
                uint16_t original_P1REN = P1REN;
                uint16_t original_P1SEL = P1SEL;
                uint16_t original_P1SEL2 = P1SEL2;
    
                setUARTPins();
                uart_init();
                set_UARTUCS();
    
                // Enable intterupts
                IE2 |= UCA0TXIE;                  // Enable the Transmit interrupt
                IE2 |= UCA0RXIE;                  // Enable the Receive  interrupt
                _BIS_SR(GIE);                     // Enable the global interrupt
    
    
                ///////////////getAcceleration will make the MSP430 talks to the BNO055
                getAcceleration();
    
                // *** Restore all registers modified by the acceleration sensing code back to their previously saved state ***
                P1IE = original_P1IE;
                P1DIR = original_P1DIR;
                P1REN = original_P1REN;
                P1SEL = original_P1SEL;
                P1SEL2 = original_P1SEL2;
                P1OUT = original_P1OUT;
    
                set_UCS();
                __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ int until Byte RXed
    
    }
    

    And I would like to ask: is it possible to use interrupts with out going to any LPM? if so, in this case should I keep the RX & TX ISR but remove the _bic_SR_register(LPM3) from them?

  • Line #34 of your doaccelereationsense() puts the CPU in LPM3. If nothing wakes it up, it will be stuck there and nothing else will happen. If something DOES wake it up, it will proceed from there and reaches line #45 of your doaccelereationsense() which means the call to doaccelereationsense(); in line #8 of your main() will be returned to line #9 of your main() -- that means main() will "return" and nothing else will happen.

    Thus either way nothing else will happen.

    Murtadha A said:
    And I would like to ask: is it possible to use interrupts with out going to any LPM? if so, in this case should I keep the RX & TX ISR but remove the _bic_SR_register(LPM3) from them?

    LPM is neither necessary nor sufficient for interrupts to work. LPM is not the eye of newt in a witches brew.

    In any good code, every single statement should have a rational reason for its existence and a well defined function it serves.

    The c-compiler is just a primitive piece of software. You need to write c-code in exactly the way it expects. It does not have any intelligence to guess your real intend. I think your way of writing c-code is too sloppy and will not carry you very far.

    As for "removing the _bic_SR_register(LPM3)", I do not know how to remove something that does not exist to begin with.

  • You are right, I am not good in programming
    I am going to not use interrupts or sleep modes, I just want to read the accelerometer registers for now. One thing to ask you to help me in is by providing me or referring me to a macro/ function (that is clear to understand) that takes care of sending and receiving multiple Bytes. I am asking for this since I know that the UART handles a Byte after anothern(1 Byte at time)

    Thank you

**Attention** This is a public forum