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.

MSP430F2274: Configuring timerA and timerB to extend the time before an interrupt

Part Number: MSP430F2274

Hello,

My goal was was use an interrupt of timerA to start timerB, and have the interrupt of timerB cause an LED to toggle. The idea to double the length of time between interrupts by using both timers working off each other. The code I am working with is provided below:

#include <msp430.h>

void configWDT(void);
void configClocks(void);
void configGPIO(void);
void configTimerA(void);
void configTimerB(void);
void configADC(void);

unsigned volatile int blink_cnt;
int main(void)
{
    blink_cnt = 0;
    configWDT();
    configClocks();
    configGPIO();
    configTimerA();

    while(1)
    {
        __bis_SR_register(LPM3_bits + GIE);             // Enter LPM3
        if(blink_cnt == 0 || blink_cnt > 0)
        {
            P1OUT ^= BIT0;
        }
    }
}


void configWDT(void)
{
    WDTCTL = WDTPW + WDTHOLD;
}


void configClocks()
{
    DCOCTL |= DCO1 + DCO0;
    BCSCTL1 |= XT2OFF + DIVA_3 + RSEL2 + RSEL1 + RSEL0;
    BCSCTL2 |= SELM_3 + SELS;
    BCSCTL3 |= XT2S_3 + XCAP_3;
}


void configGPIO(void)
{
    P1DIR |= 0x03;                            // P1.1 output
    P1SEL |= 0x02;                            // P1.1 option select

    P4DIR |= 0x06;                            // P4.1 and P4.2 output
    P4SEL |= 0x06;                            // P4.1 and P4.2 TB1/2 otions
}


void configTimerA(void)
{
    TACCTL0 |= OUTMOD_4;                       // TACCR0 toggle mode
    TACCR0 |= 0xFFFF;
    TACTL |= TASSEL_1 + ID_3 + MC_3 + TAIE;    // ACLK, up-downmode
}


void configTimerB(void)
{
    TBCCTL0 |= OUTMOD_4;
    TBCCR0 |= 0xFFFF;
    TBCTL |= TBSSEL_1 + ID_3 + MC_3 + TBIE;
}


// Timer_A3 Interrupt Vector (TAIV) handler
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMERA1_VECTOR
__interrupt void Timer_A(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMERA1_VECTOR))) Timer_A (void)
#else
#error Compiler not supported!
#endif
{
    switch(TAIV)        // Efficient switch-implementation
    {
        case  2:
            break;                        // TACCR1 not used
        case  4:
            break;                        // TACCR2 not used
        case 10:
            configTimerB();
            //blink_cnt++;
            break;
    }
    __bic_SR_register_on_exit(LPM3_bits);
}


// Timer_B3 Interrupt Vector (TAIV) handler
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMERB1_VECTOR
__interrupt void Timer_B(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMERB1_VECTOR))) Timer_A (void)
#else
#error Compiler not supported!
#endif
{
    switch(TBIV)        // Efficient switch-implementation
    {
        case  2:
            break;                        // TACCR1 not used
        case  4:
            break;                        // TACCR2 not used
        case 10:
            blink_cnt++;
            break;
    }
    __bic_SR_register_on_exit(LPM3_bits);
}

When testing this, the length of time between interrupts is the same length as it was when just using timerA. My question is if the timer continuously runs even when in an ISR? If so, should the timerA be halted when the time that timerB is running? Another question is if the timers are set up correctly? The specifications would be to have each timer run in up/down mode, off ACLK which is divided by eight. Thanks

  • So why not just use one timer and a flag?

    TimerA ISR would be like the following:

    • If flag is 0
      • just change the flag to 1.
    • If flag is not 0 (else)
      • change flag to 0, and
      • Blink the LED.

    You can make your flag global, or you could use the nice trick of a "static" variable within the ISR to make it remember its previous state.

  • How does this lengthen the time between interrupts though? Instead of triggering the LED to toggle during TAIV, I wanted to double it by having TAIV "kick off" timerB, and have an interrupt of timerB cause it to toggle. From your comment, isn't that already accomplished by having TAIV serve as a flag?
  • Well, if you think about it, the ISR kicks normally. BUT, the "action of blinking" happens every other kick because of the flag. This should double your time.
  • Well the future goal was to have the interrupt occur once an hour or once a day, so doubling the time works for this application, when increasing the complexity (or length of time between interrupts) would not be the best option.
  • Hi Sean,

    Given that you have already maximized the divider on the clock source to the timer (ACLK/8 with DIVA_3) and the TimerA's divider (/8 with ID_3) AND are using Up/Down count mode to generate the interrupt, I do not believe there is any way for you to extend the duration between interrupt events any further.

    But, as Mike points out, you can use software to keep track of how many interrupts have occurred since the last time you toggled the LED or took some action using a counter/flag which will effectively multiply the time between actions.

    Best Regards,

    Mark-
  • Thank you, I figured that to be the case. My current solution was to increment a counter and use the modulo operator (%) to have it trigger after a specific interval.

    Although I don't think it is possible to keep track of any variables or data when the device is switched into low-power mode, as the CPU is off and the debugger does not work.

**Attention** This is a public forum