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.

MSP430 timer instead delay

Hi all ! Trying to play with ultra low power consumption (g2553). Now trying figure it out how to use timer instead delay. Now i'm using SMCLK at 1Mhz, my code is :

void main(void) {


WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

P1DIR |= BIT0; // Set P1.0 to output direction
P1OUT &= ~BIT0; // Set the red LED on

//MCLK=SMCLK=1Mhz
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
//----------------------


TA0CTL = TASSEL_2+ID_3 + MC_0; // SMCLK + /3 + up mode 125 kHz


TA0CCR0 = 125    ; // 1ms


TA0CCTL0 = CCIE; // Enable counter interrupts, bit 4=1

_BIS_SR(GIE);
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer0_A0 (void) { // Timer0 A0 interrupt service routine
P1OUT ^= BIT0;
}

1. Why LED toggles not perfectly 1ms everytime ? I see on osciloscope how it varies from 498ms to 502ms)

2. How to make function ( like _delay_cycles() ) where i can use this timer for different delays ? i.e timerdelay(100) for 100ms etc. 

i think it shoulb be somethink like this, but i can't do it right:

when i call timerdelay(100);

it goes to:

void timerdelay(unsigned int time_ms)

{


TA0CTL|=TACLR;               //clear timer
TACTL|=MC_1;                   //start timer

while(time_ms!=0)

{
//decrease time_ms value every 1ms ( in the interrupt?? )


}

if (time_ms==0)

TACTL|=MC_0 ;  //stop timer

}

}

PLEASE HELP ! :)

  • >498ms to 502ms
    ±10 µS is understandable, but 400µS is a little to off if mcu is sleeping and no other IRQ's are active.
    But as you are not going to sleep change to this: _BIS_SR(LPM0+GIE);

    You should let the TA0 toggle the output and not let it be done in software ISR.

    Using a time as a delay,
    You can get 3 independent delay timers from each TAx, so 3 different task can wait for a different amount of time.
    Just copy the current TAcxCNT to CCRx and add the delay, enable its IRQ then go to sleep (lpm0)
    Have the CCRx Isr wake up the main routine by: bic_on_exit (lmp0)
    if there are more than one task, set a flag so the main routine can figure out what task it should start running.

    But as you can see with multiple delays it does not work if you program in a while() style,
    you need to program in a state-machine way. Where each task does what it has to do and return to main.
    As sort of micro real-time OS that figures out whose delay that was over and jump to that part.

  • Darius Baronas said:
    TA0CTL = TASSEL_2+ID_3 + MC_0; // SMCLK + /3 + up mode 125 kHz

    Are you sure?

    Darius Baronas said:

    void main(void) {
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

    ... ... ... ...

    _BIS_SR(GIE);
    }


    This main() will falloff the cliff when it reaches the closing "}".

  • Yesterday i edited my code, now is :

    void timer_init() {

    TA0CTL = TASSEL_2+ID_3 + MC_0; // SMCLK + /8 + disabled 125 kHz
    TA0CCTL0 = CCIE; // Enable counter interrupts, bit 4=1
    _BIS_SR(LPM0+GIE);

    }

    void delay_time_ms(volatile unsigned int TIME) {


    TA0CCR0 = TIME*125; // how many ms
    TA0CTL = TASSEL_2+ID_3 + MC_1; // SMCLK + /8 + up mode 125 kHz
    }

    void main(void) {

    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

    P1DIR |= BIT0|BIT6; // Set P1.0 to output direction
    P1OUT &= ~(BIT0|BIT6); // RESET LED's

    //MCLK=SMCLK=1Mhz
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;


    timer_init();

    while(1) {


    delay_time_ms(100);
    //P1OUT ^= BIT6;


    }
    }

    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void Timer0_A0_ISR (void) { // Timer0 A0 interrupt service routine
    //P1OUT ^= BIT0;

    P1OUT ^= BIT6; //1ms

    TACTL&=~MC_0; //stop timer
    }

    Now i got delay depending on delay_time_ms() time, in this example 100ms. But i should toggle led in the ISR, but i don't want to do like this. Because i need to use that timer as nop() function, where nothing is happened, only delay.. Like this

    while(1) {

    P1OUT &=~ BIT6;

    delay_time_ms(100);


    P1OUT ^= BIT6;

    delay_time_ms(400);

    }

  • Somewhere you need to wait until the timer expires.
    You may enter LPM0 inside the delay function and exit LPM0 inside the ISR when the timer has expired.
    And be aware that the maximum delay you can do with this setup is 524ms (65535/125).
    For longer delays, you need to count down a 500ms counter in the ISR - or do multiple delays inside the delay function.

**Attention** This is a public forum