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.

msp430F6721: TIMER0_A0 interrupt handler weirdness

Other Parts Discussed in Thread: MSP430F6721

MSP430F6721
CCS

I’ve created a simple interrupt handler in C that is driven from TIMER0_A0 (driven from SMCLK @32kHz).  The timer is set to interrupt every 0.125 seconds.

When I first wrote this, I intended the variable uiATIV to be used, but the first implementation merely left the variable initialized but otherwise not used.

I’ve since decided it won’t be needed, so I removed it.

With the statement

unsigned int uiTAIV = TA0IV;

commented out, this routine is still triggered, but the switch statement never hits TA0IV_NONE.  Instead it hits TA0IV_TA0IFG which seems strange indeed.

Thinking this is a weird timing issue, I threw some __no_operation() statements in place of the uiTAIV statement, but no luck.

Rather than continue depending upon this interrupt processing code, I’d rather know why before implementing an unintended workaround.  Any ideas out there??

Note: no LPM state is being issued at this time.

 

#pragma vector=TIMER0_A0_VECTOR
#pragma vector=TIMER0_A1_VECTOR
__interrupt void Timer_A(void)
{
    unsigned int uiTAIV = TA0IV;

    // accept only even number vectors up to TA0IV_TA0IFG
    switch (__even_in_range(TA0IV, TA0IV_TA0IFG))    
    {
    // TimerA_0    0.5 second vectors here
    case TA0IV_NONE:
        ReadButtonState();
        ++SYSControl.buttonPhase;
        P1OUT ^= 0x01; // Toggles P1.0 every half second
        DoProcessLoop();
        __no_operation();
        break;
    case TA0IV_TA0CCR1: // TACCR1             TIMERA1_VECTOR
        //P1OUT ^= 0x01; // Toggles P1.0 every half second
        __no_operation();
        break;
    case TA0IV_TA0CCR2: // TACCR2             TIMERA1_VECTOR
        __no_operation();
        break;
    case TA0IV_TA0IFG: // Timer_A3 overflow  TIMERA1_VECTOR
        __no_operation();
        break;
    }
}

  • Reading TA0IV has the side-effect of clearing the relevant interrupt condition. In the general case, you should expect successive reads to return different results. You should (in general) be very surprised if you read TA0IV in an ISR and get "NONE" -- if there's no interrupt condition, what are you doing in an ISR?

    In your case, the fetch into uiTAIV gets the value you really wanted and then the fetch for the switch() gets you either (a) the next interrupt (probably not in your case) or (b) NONE (which is kind of useless). When you remove the initial assignment, the "symptom" you see is actually the behavior you want.

  • Bruce,

    I get it.  Maybe the nomenclature used in the header file has me confused.

    Strange.. this code is now never hit:

    #pragma vector=TIMER0_A0_VECTOR
    #pragma vector=TIMER0_A1_VECTOR
    __interrupt void Timer_A(void)
    {
        //unsigned int uxTAIV = TA0IV;
        //switch (TA0IV)
        switch (__even_in_range(TA0IV, TA0IV_TA0IFG))    // accept only even number vectors up to TA0IV_TA0IFG
        {
        case TA0IV_NONE:
            __no_operation();
            break;
        case TA0IV_TA0CCR1:    //          (0x0002)       /* TA0CCR1_CCIFG */
            LPM3_EXIT;
            ReadButtonState();
            ++SYSControl.buttonPhase;
            P1OUT ^= 0x01; // Toggles P1.0 every half second
            DoProcessLoop();
            __no_operation();
            break;
        case TA0IV_TA0CCR2:    //         (0x0004)       /* TA0CCR2_CCIFG */
            LPM3_EXIT;
            ReadButtonState();
            ++SYSControl.buttonPhase;
            P1OUT ^= 0x01; // Toggles P1.0 every half second
            DoProcessLoop();
            __no_operation();
            break;
        case TA0IV_TA0IFG: // Timer_A3 overflow  TIMERA1_VECTOR
            __no_operation();
            break;
        }

        __bis_SR_register(LPM3_bits + GIE);
    }

    Timer register setup:

    TA0CTL    0x0113    Timer0_A3 Control [Memory Mapped]    
        TASSEL    01 - TASSEL_1    Timer A clock source select 1    
        ID    00 - ID_0    Timer A clock input divider 1    
        MC    01 - MC_1    Timer A mode control 1    
        TACLR    0    Timer A counter clear    
        TAIE    1    Timer A counter interrupt enable    
        TAIFG    1    Timer A counter interrupt flag    

  • Note to self:

    TA0CTL = 0x0000;
    TA0CTL |= TASSEL0; // select ACLK
    TA0CTL |= MC0; // UP Mode
    TA0CTL |= TACLR; // clear
    TA0CTL |= TAIE; // int enabled

    MC0 is not 0x00, it is 0x01.  Selecting MC1 (thinking "mode 1" here) selected continuous mode.

    Now that MC0 is selected, I get an interrupt at TA0IV_TA0IFG which makes sense.

    Stumped by the (perhaps arcane) register naming convention!  Motivates me to edit the header so that it makes some sense to me, but then it would be out of step with the rest of the planet.

  • Mark Richards said:
    MC0 is not 0x00, it is 0x01.  Selecting MC1 (thinking "mode 1" here) selected continuous mode.

    Well, use MC_0 (= 0x00), MC_1 (=0x10), MC_2 (0x20).
    MC0 (without underscore) is actually 0x10, it is bit 0 of the MCx bitfield.

    These namings match the register descriptions which were MCx previously for the MC bits and nowadays have changed to omit the x.

**Attention** This is a public forum