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.

CCS/MSP430FR2355: LPM3 Current with UART/SPI is High

Part Number: MSP430FR2355

Tool/software: Code Composer Studio

Hello,

I have been using the following code below to test the current drawn when in LPM3. When I comment out the functions set_UART_clk and config_UART, I see the current drawn reduces to about 2uA. These functions are used to initialize UART and set the UART clock but having it initialized seems to increase the power consumption in LPM3. I also tried setting the UCDORM bit before going to sleep and resetting it after waking up but that doesn't seem to help either.

This is just the code used to check for the LPM3 current. In the actual implementation, I wake up from LPM3 after a timer interrupt, reset the UCDORM bit and transmit the next packet. Functionally it works fine but the current drawn is still the same during LPM3. 

Another labmate is using the SPI protocol and he seems to have the same issue. 

Is there any way UART and SPI could be put to sleep before going to LPM3 so that the current consumption could be reduced? 

Please let me know if there's any more information I must provide. 

Here's the UART code I have been using:

#include <msp430.h>
void Software_Trim();                       // Software Trim to get the best DCOFTRIM value
void set_pins_low();
void set_UART_clk();
void config_UART();
void set_xt1_clk();
void set_timer_sleep();
#define MCLK_FREQ_MHZ 1                     // MCLK = 1MHz
unsigned int RXData = 0, TXData_start = 0x55, TXData_stop = 0xAA, TXR1 = 0x11, TXR2 = 0x76;
unsigned int ADC_data[15] = {5000, 100, 200, 200, 500, 500, 1000, 1000, 5000, 5000, 100, 200, 500, 1000, 5000}, i = 0;
int ready, standby = 0, powerdown = 1;
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;                 // Stop watchdog timer
    PM5CTL0 &= ~LOCKLPM5;                     // Disable the GPIO power-on default high-impedance mode
                                              // to activate previously configured port settings
    set_pins_low();
    P1DIR &= ~BIT3;                         // Set P1.3 as input
    // Use pin 4.6 for standby and 4.7 for Powerdown.
    P4DIR |= BIT6 | BIT7;
    // Standby = 0 for normal operation
    P4OUT &= ~BIT6;
    // Powerdown is VCC for normal operation
    P4OUT |= BIT7;
    // Linx Pin 18 is VDD for transmit mode, connect to Pin 1.0 on MSP
    P1DIR |= BIT0;
    P1OUT |= BIT0;
    // Linx Pin 10 and 13 are VDD for appropriate channel select. Connect them to MSP pin 6.0, 6.1 respectively
    P6DIR |= BIT0 | BIT1;
    P6OUT |= BIT0 | BIT1;
    / /Linx Pin 14 is level adj at VDD for max power out. Connect it to Pin 6.2 on MSP
    P6DIR |= BIT2;
    P6OUT |= BIT2;
    // Linx Pin 9 is VDD to choose transparent mode. Connect to MSP Pin 6.3
    P6DIR |= BIT3;
    P6OUT |= BIT3;
    set_UART_clk();
    config_UART();
    set_xt1_clk();
    CSCTL4 = SELA__XT1CLK | SELMS__DCOCLKDIV;    // Select Aux clock as XT1(32kHz) and Main clock as DCO (1MHz)
    TB0CCTL0 |= CCIE;                            // TBCCR0 interrupt enabled
    while (1)
    {
        // Put Linx in Powerdown
        // Pull all VDD pins to 0
        P1OUT &= ~BIT0;
        P6OUT &= ~BIT0;
        P6OUT &= ~BIT1;
        P6OUT &= ~BIT2;
        P6OUT &= ~BIT3;
        P1DIR |= BIT7;
        P1OUT &= ~BIT7;
        UCA0CTLW0 |= UCDORM;
        // Powerdown Pin (4.7) pulled low to put the Linx device in powerdown
        P4OUT &= ~BIT7;
        __bis_SR_register(LPM3_bits | GIE);         // Enter LPM3 w/ interrupt
    }
    P1OUT = BIT0;
}
void Software_Trim()
{
    unsigned int oldDcoTap = 0xffff;
    unsigned int newDcoTap = 0xffff;
    unsigned int newDcoDelta = 0xffff;
    unsigned int bestDcoDelta = 0xffff;
    unsigned int csCtl0Copy = 0;
    unsigned int csCtl1Copy = 0;
    unsigned int csCtl0Read = 0;
    unsigned int csCtl1Read = 0;
    unsigned int dcoFreqTrim = 3;
    unsigned char endLoop = 0;
    do
    {
        CSCTL0 = 0x100;                         // DCO Tap = 256
        do
        {
            CSCTL7 &= ~DCOFFG;                  // Clear DCO fault flag
        }while (CSCTL7 & DCOFFG);               // Test DCO fault flag
        __delay_cycles((unsigned int)3000 * MCLK_FREQ_MHZ);// Wait FLL lock status (FLLUNLOCK) to be stable
                                                           // Suggest to wait 24 cycles of divided FLL reference clock
        while((CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)) && ((CSCTL7 & DCOFFG) == 0));
        csCtl0Read = CSCTL0;                   // Read CSCTL0
        csCtl1Read = CSCTL1;                   // Read CSCTL1
        oldDcoTap = newDcoTap;                 // Record DCOTAP value of last time
        newDcoTap = csCtl0Read & 0x01ff;       // Get DCOTAP value of this time
        dcoFreqTrim = (csCtl1Read & 0x0070)>>4;// Get DCOFTRIM value
        if(newDcoTap < 256)                    // DCOTAP < 256
        {
            newDcoDelta = 256 - newDcoTap;     // Delta value between DCPTAP and 256
            if((oldDcoTap != 0xffff) && (oldDcoTap >= 256)) // DCOTAP cross 256
                endLoop = 1;                   // Stop while loop
            else
            {
                dcoFreqTrim--;
                CSCTL1 = (csCtl1Read & (~DCOFTRIM)) | (dcoFreqTrim<<4);
            }
        }
        else                                   // DCOTAP >= 256
        {
            newDcoDelta = newDcoTap - 256;     // Delta value between DCPTAP and 256
            if(oldDcoTap < 256)                // DCOTAP cross 256
                endLoop = 1;                   // Stop while loop
            else
            {
                dcoFreqTrim++;
                CSCTL1 = (csCtl1Read & (~DCOFTRIM)) | (dcoFreqTrim<<4);
            }
        }
        if(newDcoDelta < bestDcoDelta)         // Record DCOTAP closest to 256
        {
            csCtl0Copy = csCtl0Read;
            csCtl1Copy = csCtl1Read;
            bestDcoDelta = newDcoDelta;
        }
    }while(endLoop == 0);                      // Poll until endLoop == 1
    CSCTL0 = csCtl0Copy;                       // Reload locked DCOTAP
    CSCTL1 = csCtl1Copy;                       // Reload locked DCOFTRIM
    while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // Poll until FLL is locked
}
void set_UART_clk()
{
    __bis_SR_register(SCG0);                // Disable FLL
    CSCTL3 = SELREF__REFOCLK;               // Set REFO as FLL reference source
    CSCTL1 = DCOFTRIMEN_1 | DCOFTRIM0 | DCOFTRIM1 | DCORSEL_0;// DCOFTRIM=3, DCO Range = 1MHz
    CSCTL2 = FLLD_0 + 30;                   // DCODIV = 1MHz
    __delay_cycles(3);
    __bic_SR_register(SCG0);                // Enable FLL
    Software_Trim();                        // Software Trim to get the best DCOFTRIM value
}
void config_UART()
{
    // Configure UART pins
    P1SEL0 |= BIT6 | BIT7;                    // set 2-UART pin as second function
    // Configure UART
    UCA0CTLW0 |= UCSWRST;                     // Put eUSCI in reset
    UCA0CTLW0 |= UCSSEL__SMCLK;
    // Baud Rate calculation
    UCA0BR0 = 6;                              // 1000000/9600 = 104.166666667  which is greater than 16. Hence, (1000000/(16*9600)) = 6.51041666667, decimal portion is 6 and fraction is 0.51.
    UCA0MCTLW = 0x1100 | UCOS16 | UCBRF_2;    // 1000000/115200 - INT(1000000/115200)=0.68 --> done above.
                                              // UCBRSx value = 0xD6 (See UG - see table 22.4 in section 22.3.10, other code example says table 17.4, that's not correct.
    UCA0BR1 = 0;
    UCA0CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
    UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt
}
void set_pins_low()
{
    P1OUT = 0x00;
    P2OUT = 0x00;
    P3OUT = 0x00;
    P4OUT = 0x00;
    P5OUT = 0x00;
    P6OUT = 0x00;
    P1DIR = 0xff;
    P2DIR = 0xff;
    P3DIR = 0xff;
    P4DIR = 0xff;
    P5DIR = 0xff;
    P6DIR = 0xff;
}
void set_xt1_clk()
{
    P2SEL1 |= BIT6 | BIT7;                  // P2.6~P2.7: crystal pins
    do
    {
        CSCTL7 &= ~(XT1OFFG | DCOFFG);      // Clear XT1 and DCO fault flag
        SFRIFG1 &= ~OFIFG;
    } while (SFRIFG1 & OFIFG);              // Test oscillator fault flag
}
void set_timer_sleep ()
{
    TB0CTL = ID__4 | TBSSEL__ACLK | MC__UP;     // Input divider /4, ACLK, UP mode
}
#pragma vector = TIMER0_B0_VECTOR
__interrupt void TB0_ISR(void) {
    __bic_SR_register_on_exit(LPM3_bits | GIE);
}

Any help regarding this would be appreciated.

Thanks,

Yaman

  • Hi Yaman,

    May I know the value of the high current you got?

    In the code set_UART_clk configuration code, the REFO is selected as the FLL clock reference. When the device in LPM3, the REFO is still enabled, and the REFO is consuming ~15uA (tpy.) current. You can make a minor change to the code and check it again.

    1. Move the set_xt1_clk() pripor to the set_UART_clk().

    2. Select the XT1 as the the FLL and ACLK clock source, then the REFO is disabled.

    Best regards,

    Jovi He

    If the post helped solve your issue, please click on the  'This resolved my issue'  button.

  • Hi Jovi,

    Thanks for the advice on changing the FLL clock reference. The current previously was around 22uA, it is now 6uA. The ACLK source is already XT1 so I didn't have to do anything there.

    However, if I don't initialize UART at all, the current is 2uA - the current right now is still 4uA more than what I expect. What would be the reason behind that and how can I reduce it further to around 2-3uA?

    Thanks,

    Yaman

  • Yaman,

    I think the extra current is caused by the eUSCI module, it's optional ON in LPM3.

    The timer is used in your code, if you use the timer to wake up the device from LPM and do the communication, you can set the device to LPM4 mode. The current should be lower then.

    Best regards,

    Jovi He

  • Ah I see. Is it possible to turn eUSCI module off before sleeping and on right after?
    I'll try the LPM4 mode as well and see what I get. I don't remember exactly but I think some of the configurations of ADC have to be redone after coming out of LPM4 - I'll check on that and try to implement it.
    Thanks,
    Yaman
  • I essentially reset eUSCI before going to sleep and re-initialize on waking up. That seems to give me a much lower current.

    Thank you for all the help with this. 

    I do have a follow-up question - can I expect the sleep mode current to rise significantly when there is a timer running in the background (Aclk is set to XT1). The current goes up to about 300uA when I have a timer running but is just about 1uA when there isn't a timer running - is that to be expected?

    Thanks,

    Yaman

  • Hi Yaman,

    The timer itself should not consume that high curent (300uA). Did you check the device really entered the sleep mode? What's the timer wakeup time interval?

    Best regards,

    Jovi He

  • Hi Jovi,

    I got this figured out - the MSP device was alright, it was an issue with another device I was using in the system. 

    Thanks for all the help!

    Best,

    Yaman

**Attention** This is a public forum