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: LPM0 and TA0

Part Number: MSP430FR5994

I wanted to make a delay using TimerA with SMCLK = 16 MHz. 

The following code works and gives the requested delay, approximately, where the argument of the function is the requested delay in microseconds:

void Delayus(unsigned int delayamt)
{
    // Delay is 0-65535 usec; already initialized to use SMCLK, divide by 16 so timer increments once/usec; upon reaching delayamt, one interrupt is given and the delay is over
        TA0CCR0 = delayamt;                     // Interrupt when up-count to this value
        TA0CTL |= (MC_1 | TACLR);
      __bis_SR_register(LPM0_bits | GIE);       // Go to sleep. Timer0 ISR will wake us up when proper time has elapsed
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
{
    TA0CTL |= MC_0;                             // Stop Timer0
    __bic_SR_register_on_exit(LPM0_bits);       // Wakeup from LPM0 and continue after the Delayus function
}

Having achieved success, I thought that I would expand on it to achieve large, of the order of seconds, delays. It does not work.... the CPU goes to sleep forever.

void Delaysec(unsigned int dela)                 // Delay is 0-65.535 msec
{
    unsigned long i, delas;
     delas = 20*dela;                                        // 1 sec = 20*50,000 usec
    for (i=0; i<delas; i++) Delayus(50000);
}

In the main routine, I had already disabled the watchdog.

    WDTCTL = WDTPW | WDTHOLD;                               // Stop watchdog

Any ideas why this fails?

  • I forgot to include the setup of TimerA in the main routine:
    // Initialize Timer0 for a replacement of __delay_cycles once interrupts are enabled
    TA0EX0 = 0x0001; // Divide by 2
    TA0CTL = TASSEL_2 + MC_0 + TACLR + ID_3; // SMCLK, count up to TA0CCR0, Timer clear, Divide by 8
    TA0CCTL0 = CCIE; // TACCR0 interrupt enabled but no effect until Timer0 is running
    __bis_SR_register(GIE); // Enable all interrupts
  • Hello David,

    Could you please use the code upload tool to upload your source code so that I can recreate the problem and help debug the issue. One thing I can see that could cause a problem is that you are not stopping the timer properly inside of the ISR:

    TA0CTL |= MC_0; // Stop Timer0

    If the Mode Control bits are 01 when inside of the interrupt and you OR them with 0x0000, then nothing has been changed.
    In order to stop the timer, you are going to want to use this line of code (which clears the MC bits in the TA0CTL register):

    TA0CTL &= ~(MC_3); // Stop Timer0


    Some additional debugging could be to add a "__no_operation()" in the "for" loop to help with debugging purposes to see if the interrupts are triggering or if you are looping somewhere.

    Best regards,

    Matt Calvo
  • I don't see your symptom, so the failure is somewhere outside this code.

    Matt provided the correct way to stop the timer, but that's not (in itself) what is causing the trouble.

    How long is "forever"?
  • Thanks to both of you for your comments. The faults are completely mine.
    1. Matt : yes I did not stop TimerA correctly.
    2. Bruce: yes, your comment is insightful. There was confusion in my mind and although I wanted a delay in msec, the code that I actually used (not sent to you in my problem statement) calculated the delay in seconds, so although I wanted 1550 msec, for example, I got 1550 seconds... seeming like forever, although I never actually stared at the circuit until the 1550 sec had expired.

**Attention** This is a public forum