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.

MSP430FR5994: LPM3 and Timers

Part Number: MSP430FR5994
Other Parts Discussed in Thread: ENERGYTRACE, ADS1220,

Hello,

I'm making a delay function using timers and I came across the following situation:

Without calling the delay function, the current consumption is 10uA in LPM3.

After calling any of the delay functions, the consumption current is high +/- 150uA in LPM3.

Below is a code snippet and configuration attached.

Any suggestions for my setup?

////////////////////////////////////////////////////////////////////////////////
//       Rotina para Gerar Atrasos para Leituras dos Sensores de Pressões     //
////////////////////////////////////////////////////////////////////////////////
void Delay_PRESS(void)
{
   TA4CCTL0 |= CCIE_1;                                                          // Habilita a Interrupção do TIMER4_A0
   TA4CTL = TASSEL_1 + MC_1 + TACLR;                                            // Configura o TIMER4_A0 (ACLK, UP Mode)
   TA4CCR0 = 1966;                                                              // Periodo de Tempo da Leitura dos Sensores de Pressão de Entrada e Saída
   __bis_SR_register(LPM3_bits + GIE);                                          // Entra em LPM3 (Modo de Baixo Co
}
////////////////////////////////////////////////////////////////////////////////
//     Rotina para Gerar Atrasos para Acionamentos das Válvulas Solenóides    //
////////////////////////////////////////////////////////////////////////////////
void Delay_SOLENOIDE(void)
{
   TA3CCTL0 |= CCIE_1;                                                          // Habilita a Interrupção do TIMER3_A0
   TA3CTL = TASSEL_1 + MC_1 + TACLR;                                            // Configura o TIMER3_A0 (ACLK, UP Mode)
   TA3CCR0 = 327;                                                               // Periodo de Tempo de Acionamento das Válvulas Solenóides de Controle
   __bis_SR_register(LPM3_bits + GIE);                                          // Entra em LPM3 (Modo de Baixo Consumo)
}


////////////////////////////////////////////////////////////////////////////////
//              Rotina Principal do Smart Logger VRP Controller               //
////////////////////////////////////////////////////////////////////////////////
void main(void)
{
   WDTCTL = WDTPW + WDTHOLD;                                                    // Desabilita o WDT
  
   // Disable the GPIO power-on default high-impedance mode to activate
   // previously configured port settings
   PM5CTL0 &= ~LOCKLPM5;
  
   // Rotinas para Inicialização das Portas e Pinos do MSP430FR5994
   initPORTS();                                                                 // Inicializa os Ports
  
   // Rotinas para Inicialização do Clock e Oscilador do MSP430FR5994
   //initClockTo1MHz();                                                          // Seleciona o Clock para 1MHz
   //initClockTo8MHz();                                                          // Seleciona o Clock para 8MHz
   initClockTo16MHz();                                                          // Seleciona o Clock para 16MHz     
  
   // TimerA3 configuration
   TA3CTL = 0;                                                                  // Desabilita o TimerA3
   
   // TimerA4 configuration
   TA4CTL = 0;                                                                  // Desabilita o TimerA4
            
   // Habilita os Periféricos RTC e BT
   RTCCTL13 &= ~RTCHOLD;                                                        // Habilita o RTC
  
   // Rotina Principal do Loop
   do                                            
     {
        __bis_SR_register(LPM3_bits + GIE);                                     // Entra em LPM3 (Modo de Baixo Consumo)
        __no_operation ();                                                      // Não Faz Nada    
     }
   while (1);                                                                   // Enquanto While Igual a 1, Garante o LPM3
}


////////////////////////////////////////////////////////////////////////////////
//    Rotina de Tratamento da Interrupção do Timer3_A0 de Ciclos Periódicos   //
////////////////////////////////////////////////////////////////////////////////
// Timer3_A0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMER3_A0_VECTOR
__interrupt void TIMER3_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER3_A0_VECTOR))) TIMER3_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
   __bic_SR_register_on_exit(LPM3_bits);                                        // Sai do Modo de Baixo Consumo
   TA3CCTL0 |= CCIE_0;                                                          // Desabilita a Interrupção do TIMER3_A0
   TA3CTL = 0;                                                                  // Desabilita o TIMER3_A0
}
////////////////////////////////////////////////////////////////////////////////
//    Rotina de Tratamento da Interrupção do Timer4_A0 de Ciclos Periódicos   //
////////////////////////////////////////////////////////////////////////////////
// Timer4_A0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMER4_A0_VECTOR
__interrupt void TIMER4_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER4_A0_VECTOR))) TIMER4_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
   __bic_SR_register_on_exit(LPM3_bits);                                        // Sai do Modo de Baixo Consumo
   TA4CCTL0 |= CCIE_0;                                                          // Desabilita a Interrupção do TIMER4_A0
   TA4CTL = 0;                                                                  // Desabilita o TIMER4_A0
}

  • I don't see the behavior you describe when running on a Launchpad. EnergyTrace reports about 1.5uA in the while(1) with or without a call to Delay_PRESS().

    I had to fill in some gaps -- I defined initGPIO() to do (mostly) input/pull-downs, and initClockTo16MHz() to start the LFXT. I called Delay_PRESS() just before the while(1) loop in main().

    Can you describe your test case further?

  • //******************************************************************************
    //  MSP430FR69xx Demo - RTC in real time clock mode
    //
    //  Description: This program demonstrates the RTC mode by triggering an
    //  interrupt every second and minute. This code toggles P1.0 every second.
    //  This code recommends an external LFXT crystal for RTC accuracy.
    //  ACLK = LFXT = 32768Hz, MCLK = SMCLK = default DCO = 1MHz
    //
    //                MSP430FR6989
    //             -----------------
    //        /|\ |              XIN|-
    //         |  |                 | 32768Hz
    //         ---|RST          XOUT|-
    //            |                 |
    //            |            P1.0 |--> Toggles every second
    //            |                 |
    //
    //   William Goh
    //   Texas Instruments Inc.
    //   August 2014
    //   Built with IAR Embedded Workbench V5.60 & Code Composer Studio V6.0
    //******************************************************************************
    
    #include <msp430fr6989.h>
    
    void delay_timer(int timer)
    {
       TA1CCR0 = (int)(10 * timer);                                                 // Set count target
       TA1CTL |= MC__UP;                                                            // Set count mode to up (Changed from TA1CTL = MC__UP;)
       __bis_SR_register(LPM3_bits | GIE);                                          // Enter LPM3
    }
    
    int main(void)
    {
       WDTCTL = WDTPW | WDTHOLD;                                                    // Stop WDT
    
       // Configure GPIO
       P1OUT = 0;                                                                   // Reseta Todos os Pinos da Porta P1
       P1DIR = 0xFF;                                                                // Define Todos os Pinos da Porta P1 como Saídas
       P1OUT &=~ 0xFF;                                                              // Inicializa Todos os Pinos da Porta P1 com Nível Lógico "0" Baixo
       P1DIR &=~ (BIT1);                                                            // Define Todos os Pinos da Porta P1 como Entradas
       P1REN |= (BIT1);                                                             // Habilita os Resistores de Pull Up dos Pinos da Porta P1  
       P1OUT |= (BIT1);                                                             // Inicializa Todos os Pinos da Porta P1 com Nível Lógico "1" Alto
       P1IE |= (BIT1);                                                              // Habilita as Interrupções para os Pinos da Porta P1
       P1IES |= (BIT1);                                                             // Habilita Interrupções como Borda Descida para os Pinos da Porta P1
       P1IFG &=~ (BIT1);                                                            // Limpa as Flags das Interrupções dos Pinos da Porta P1
      
       P2OUT = 0;
       P2DIR = 0xFF;
    
       P3OUT = 0;
       P3DIR = 0xFF;
    
       P4OUT = 0;
       P4DIR = 0xFF;
    
       P5OUT = 0;
       P5DIR = 0xFF;
    
       P6OUT = 0;
       P6DIR = 0xFF;
    
       P7OUT = 0;
       P7DIR = 0xFF;
    
       P8OUT = 0;
       P8DIR = 0xFF;
    
       P9DIR |= BIT7;                                                               // LED interrupt
       P9OUT |= BIT0;
       
    
       P10OUT = 0;
       P10DIR = 0xFF;
    
       PJOUT = 0;
       PJSEL0 = BIT4 | BIT5;                                                        // For XT1
       PJDIR = 0xFFFF;
       
       // Disable the GPIO power-on default high-impedance mode to activate
       // previously configured port settings
       PM5CTL0 &= ~LOCKLPM5;
    
       // XT1 Setup
       CSCTL0_H = CSKEY >> 8;                                                       // Unlock CS registers
       CSCTL1 = DCOFSEL_0;                                                          // Set DCO to 1MHz
       CSCTL2 = SELA__LFXTCLK | SELS__DCOCLK | SELM__DCOCLK;                        // Set ACLK = XT1; MCLK = DCO
       CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;                                        // Set all dividers to 1
       CSCTL4 &= ~LFXTOFF;
       do
        {
           CSCTL5 &= ~LFXTOFFG;                                                     // Clear XT1 fault flag
           SFRIFG1 &= ~OFIFG;
        }
       while (SFRIFG1&OFIFG);                                                       // Test oscillator fault flag
       CSCTL0_H = 0;                                                                // Lock CS registers
      
       TA1CCTL0 = CCIE;                                                             // TACCR0 interrupt enabled
       TA1CTL = TASSEL__ACLK | MC__UP;                                              // ACLK, up mode
       TA1CCR0 = 0;                                                                 // Set count target to 0 by default
       
       do
        {
           P9OUT &= ~(BIT7);                                                        // LED OFF
           __bis_SR_register(LPM3_bits | GIE);                                      // Enter LPM3 w/ interrupt
           __no_operation ();                                                       // Não Faz Nada
        }
       while(1);
    }
    
    // Timer A1 interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = TIMER1_A0_VECTOR
    __interrupt void Timer1_A0_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(TIMER1_A0_VECTOR))) Timer1_A0_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
       //TA1CTL &= ~MC_3; // Para o cronômetro para evitar a repetição da contagem 
       TA1CTL |= MC__STOP; //  Stop timer to prevent repeat counting (Changed from TA1CTL = MC__STOP;)
       __bic_SR_register_on_exit(LPM3_bits);
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    //               Rotina de Tratamento da Interupção do Port 1                 //
    ////////////////////////////////////////////////////////////////////////////////
    //#pragma vector=PORT1_VECTOR
    //__interrupt void Port1_ISR (void)
    // Port 1 interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void)
    #else
    #error Compiler not supported!
    #endif
    {   
       // Rotina de Monitoramento dos Estados e Acionamentos dos Botões SW1, SW2, SW3, SW4, ADS1220 e USB
       switch (__even_in_range(P1IV, P1IV_P1IFG7))
         {
            // Vector  P1IV_NONE:  No Interrupt pending
            case  P1IV_NONE: break;                                                 //0x000
    
            // Vector  P1IV_P1IFG0:  P1IV P1IFG.0
            case  P1IV_P1IFG0: break;                                               //0x002
             
            // Vector  P1IV_P1IFG1:  P1IV P1IFG.1
            case  P1IV_P1IFG1:                                                      //0x004
                  P9OUT |= (BIT7);                                                  //LED ON
                  delay_timer(1000);                                                       //Delay
            break;
            // Vector  P1IV_P1IFG2:  P1IV P1IFG.2
            case  P1IV_P1IFG2: break;                                               //0x006
               
            // Vector  P1IV_P1IFG3:  P1IV P1IFG.3
            case  P1IV_P1IFG3: break;                                               //0x008
                  
            // Vector  P1IV_P1IFG4:  P1IV P1IFG.4
            case  P1IV_P1IFG4: break;                                               //0x010
    
            // Vector  P1IV_P1IFG5:  P1IV P1IFG.5
            case  P1IV_P1IFG5: break;                                               //0x012
    
            // Vector  P1IV_P1IFG1:  P1IV P1IFG.6
            case  P1IV_P1IFG6: break;                                               //0x014
    
            // Vector  P1IV_P1IFG7:  P1IV P1IFG.7                                   
            case  P1IV_P1IFG7: break;                                               //0x016
    
            // Default case
            default: break;
         }
       
      P1IFG &=~ (BIT1);                                                             // Limpa as Flags das Interrupções de Todos os Pinos da Porta P1
    }

    Hello Bruce!

    I also did this test with the FR6989 and noticed a variation of high current consumption from a 3.6V battery. Around 32uA.

  • >  TA1CTL |= MC__STOP; // Stop timer to prevent repeat counting (Changed from TA1CTL = MC__STOP;)

    This doesn't stop the timer, since MC__STOP==0. Try instead:

    > TA1CTL &= ~MC_3;        // Set MC=0 to stop the timer

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

    >  delay_timer(1000); //Delay

    Enabling GIE (via delay_timer) in an ISR is generally hazardous. It's even more so here since I don't see any de-bouncing for the P1.1 button. I suggest you wake up main using "__bic_SR_register_on_exit(LPM3_bits);" and let it do the delay.

  • Hi Bruce,

    I suggest you wake up main using "__bic_SR_register_on_exit(LPM3_bits);" and let it do the delay.

    I didn't quite understand your suggestion. Can you give me more details please?

    Any examples for study and testing?

  • I'm not sure which part is missing. You were using __bic_SR_register_on_exit in your original example to push work (such as it was) from the ISR back into main. 

    In a simple demonstration program like this one, things can appear to work even in though there are hazards. How do you intend to use these delay functions in your final application? I'm suggesting you avoid using them in an ISR.

  • ////////////////////////////////////////////////////////////////////////////////
    //    Rotina de Tratamento da Interrupção do Timer2_A1 de Ciclos Periódicos   //
    ////////////////////////////////////////////////////////////////////////////////
    // Timer2_A1 Interrupt Vector (TAIV) handler
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=TIMER2_A1_VECTOR
    __interrupt void TIMER2_A1_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(TIMER2_A1_VECTOR))) TIMER2_A1_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {  
       switch(__even_in_range(TA2IV, TAIV__TAIFG))
         {
            case TAIV__NONE:    break;                                              // No interrupt
            case TAIV__TACCR1:  break;                                              // CCR1 not used 
            case TAIV__TACCR2:  break;                                              // CCR2 not used                                             
            case TAIV__TACCR3:  break;                                              // reserved
            case TAIV__TACCR4:  break;                                              // reserved
            case TAIV__TACCR5:  break;                                              // reserved
            case TAIV__TACCR6:  break;                                              // reserved
            case TAIV__TAIFG:                                                       // overflow
                 Monitora_Pressoes = Monitora_Pressoes + 1;                         // Monitoramento das Pressões de Entrada e Saída a Cada 1 Segundo                                  
                 Monitora_Solenoides = Monitora_Solenoides + 1;                     // Monitoramento das Válvulas Solenóides a Cada 1 Segundo     
                 Monitora_Controle = Monitora_Controle + 1;                         // Monitoramento do Controle da VRP a Cada 1 Segundo
            break;
            default: break; 
         }
       // Monitoramento das Pressões de Entrada e Saída
       if ((((uint32_t)PRESS1 <= ((uint32_t)Pressao_Entrada_MIN)))||((uint32_t)PRESS2 >= (uint32_t)PRESS1)) // Se a Pressão de Referencia < PRESS2 de Saída - 1 AND Maior que ZERO?
       //if ((((uint32_t)PRESS1 <= ((uint32_t)Pressao_Entrada_MIN - 1)) && Positivo((uint32_t)Pressao_Entrada_MIN) == 1)||((uint32_t)PRESS2 >= (uint32_t)PRESS1)) // Se a Pressão de Referencia < PRESS2 de Saída - 1 AND Maior que ZERO?  
         {
            Controle_Baixa = 0;                                                     // Desabilita Acionamento da Válvula Solenóide de Entrada
            Controle_Alta = 0;                                                      // Desabilita Acionamento da Válvula Solenóide de Saída
         }
       // Monitoramento das Válvulas Solenóides de Entrada e Saída                               
       if (Monitora_Solenoides == Intervalo_Controle)                               // Se Acionamentos Habilitados e Temporiza 1 Segundo = Intervalo Controle?
         {                     
            if (Controle_Baixa == 1)                                                // Se Controle de Pressão Baixa?
              {
                 PORTA_P8OUT |= G2012_S32;                                          // Habilita o Circuito da Válvula Solenóide de Entrada
                 //delay_ms(10);
                 Delay_SOLENOIDE();                                                 // Periodo de Tempo da Válvula Solenóide de Entrada Aberta
                 PORTA_P8OUT &=~ G2012_S32;                                         // Desabilita o Circuito da Válvula Solenóide de Entrada
              }
            else
              {
                 if (Controle_Alta == 1)                                            // Se Controle de Pressão Alta?
                   {
                      PORTA_P8OUT |= G2012_S31;                                     // Habilita o Circuito da Válvula Solenóide de Saída
                      //delay_ms(10);
                      Delay_SOLENOIDE();                                            // Periodo de Tempo da Válvula Solenóide de Saída Aberta
                      PORTA_P8OUT &=~ G2012_S31;                                    // Desabilita o Circuito da Válvula Solenóide de Saída
                   }
              }
            Monitora_Solenoides = 0;                                                // Reseta a Variável Temporiza 1 segundo
         }
    }

    Hi Bruce,

    I'm using the delay function in a Timer interrupt.

    I need it to be checked every 1 sec (from time to time) and to activate the solenoid with intervals of 10 milliseconds between ON/OFF.

    I'm on a project where we'll absorb the MSP430FR5994 and two ADS1220 plus other peripherals.

    Bruce, do you have an email where I can send you all the code for your understanding?

  • The canonical method would be for the TA2 ISR you posted to set a flag somewhere that says "pulse the solenoid now", and wake up main; then main would do the set/delay/clear sequence.

    An alternate plan might be to use the delay-timer ISR to turn off that (P8?) GPIO directly, rather than indirectly through a wakeup. In the meantime you could return from the TA2 ISR and go do something else. Since you're already dedicating the timer to this function, this would be a fairly small coding change.

    Another would be to move the solenoid to a timer output pin (e.g. P1.3=TA1.2) and use OUTMOD to generate the entire pulse (in the background) each second.

    Sorry, I'm not in a position to take on any one-on-one consulting. Discussing a design question on the Forum makes available all the smart people who wander through, and potentially helps someone with the same question in the future.

**Attention** This is a public forum