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.

MSP430F249: delay with Timers

Part Number: MSP430F249


Hello!

its my first time working with the msp430.

i started working on a project that uses the MSP430. an older man wrote  the program for this project and i was asked to fix it.

he didn't know how to use timers so he did a very inefficient delay( a function with a "for" loop)

now i want to use a timer and an interrupt to make it more efficient.

but i dont want to change the original program too much(not yet at least) because it is very long and works.

so i need to have a function of a delay that activates the timer and then puts the cpu in LPM0 and wait for interrupt

but then i am unable to return to "main" to the spot where the delay was issued.

how can i do that?    

  • This is one of those things that everyone seems to need but there are no public examples for. Here's a small/simple one.

    It uses Timer A ("TA0" below), but could be changed to use Timer B ("TB0"). I ran this on a G2553 on a Launchpad.

    Standard disclaimer: No warranty, no support and all that.

    [Edit: Fixed typo]

    ///
    //      tddemo.c
    //      Simple delay and clock using Timer A0.
    //      Set DEMO=1 to demonstrate.
    //      No warranty, no support, and all that.
    //
    #define DEMO    1                   // Include the main() program below
    
    #include <stdint.h>
    #include <msp430.h> 
    #define HZ          1000000UL       // Clock is ~1MHz at Reset
    
    //#include "timer.h"                // You'll probably want one of these eventually
    extern void timer_init(void);       // You can
    extern void timer_wait_ms(uint16_t ms); // put these
    extern uint16_t timer_fetch(void);  //        into it
    
    volatile uint16_t timer_ms;
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void
    timer_isr(void)
    {
        ++timer_ms;                     // Clock tick
        LPM0_EXIT;                      // Wake up foreground
        return;
    }
    
    void
    timer_init(void)
    {
        TA0CCR0 = HZ / 1000 - 1;       // 1ms tick
        TA0CCTL0 = CCIE;               // Interrupt up there
        TA0CTL = TASSEL_2 | ID_0 | MC_1 | TACLR; // SMCLK/1, Up mode (,clear)
        return;
    }
    
    uint16_t
    timer_fetch(void)
    {
        return (timer_ms);              // That was easy
    }
    
    void
    timer_wait_ms(uint16_t ms)
    {
        uint16_t start = timer_fetch();
        while (timer_fetch() - start < ms)  // Differencing avoids some races
            LPM0;                           // Wake up every 1ms to look.
        return;
    }
    
    #if DEMO
    ///
    //  main()
    //
    int
    main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
        //  Launchpad P1.0 LED
        P1OUT &= ~BIT0;             // Initially off (active high)
        P1DIR |= BIT0;              // Output
        timer_init();
        __enable_interrupt();
    
        while (1)
        {
            P1OUT ^= BIT0;          // Toggle LED for show
            timer_wait_ms(500);     // 500ms -> 1Hz blink
        }
        /*NOTREACHED*/
        return 0;
    }
    #endif  // DEMO
    

  • I probably should have mentioned: This sort of approach is good for multi-millisecond delays. It is not useful for very small delays.

    The smaller your delay requirement, the more useful is something like __delay_cycles(), which is not low-power but is more reliable than a for-loop.

  • many different ways of doing it.

    i generally have a free-running timer in my applications that returns the current timer ticks. with that, a simple piece of code like below will work:

      if (ticks_now() - ticks_prev > DLY_TICKS) { //if enough ticks have elapsed

        ticks_prev += DLY_TICKS; //update previous tick counter

        do_something(); //execute user code

      }

    this approach allows multiple tasks to be executed from one (free-running) timer. and it is highly portable. its downside is that it is subject to jitter if the main() loop is too long.

    if more real time application is needed, you can install a timer ISR from which to execute your code (if it is short) or raise a flag for its execution in the main() loop - again, subject to jitter - like this:

      if (timer_ovf()) { //if time is up - timer_ovf() clears the flag by itself

        do_something(); //execute user code

      }

  • THX!!! i didnt know LPM0_EXIT command existed... you save me! sorry for the delay!
  • thanks !!! i will try that too!

**Attention** This is a public forum