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.

General questions concerning timers and their corresponding interrupts

Other Parts Discussed in Thread: MSP430F5438A

Hey guys,

if I use timers, I can initialize them without troubles, but when it comes to the ISRs, I don't know the exact usage of them. I always google for some code examples, but now I want to know how they work ;)

Before coming back to the topic, just some background information about my programming environment: 

I use the MSP430F5438A in combination with IAR Workbench. 

Ok, now back to my problem:

Let's say I'm using TimerA0 with CCR0 and CCR1. What are the correct ISR I have to handle?

At the moment I'm using 

#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR (void){}

for TimerA0 CCR0.

Concerning syntax: Is "TIMER0" the CCR0 flag of "A0" or is it the general vector of TIMERA0, means that I can switch through all available flags of TA0? Or is there a complete other meaning behind this code?

How do I write the ISR for CCR1? Is it

#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_ISR (void){}

Any explanations appreciated ;)

  • The interrupt for TA0CCR0 goes to interrupt vector 55, all the other interrupts of TA0 go to vector 54. (This is specified in the datasheet, but note that the priority is not the same as the number because the vector numbers start at 1.)

    The <msp430f5438a.h> file defines the symbols TIMER0_A0_VECTOR and TIMER0_A1_VECTOR for these two numbers.

    The #pragma vector= command tells the compiler that the following function should be linked to that interrupt vector number.

    The name of the interrupt function does not matter to the compiler.

    To use another interrupt: look up the interrupt number in the datasheet, then look up what symbol the <msp430f5438a.h> file defines for it, then use that in the #pragma. (And change the name of the function to something that makes sense for you.)

  • Your MSP430F5438A has

    • TimerA0 with five capture compare registers
      • TA0CCR0
      • TA0CCR1
      • TA0CCR2
      • TA0CCR3
      • TA0CCR4
    • TimerA1 with three capture compare registers
      • TA1CCR0
      • TA1CCR1
      • TA1CCR2
    • TimerB0 with seven capture compare registers
      • TB0CCR0
      • TB0CCR1
      • TB0CCR2
      • TB0CCR3
      • TB0CCR4
      • TB0CCR5
      • TB0CCR6

    This leads to six interrupt service routines, two for every Timer. CCR0 always has it's own ISR - I have marked it in red. And all the blue ones for one timer share the second ISR. Since there are those multiple sources for the second ISR there is a vector that can be read to determine the capture compare register that has caused the interrupt. And the TxIFG for the timer overflow is handled by this vector, too. There are three of those vectors - one for TimerA0, one for TimerA1 and one for Timer B0.

    For TimerA0 these are the two interrupts:

    // Timer0 A0 interrupt service routine
    #pragma vector = TIMER0_A0_VECTOR
    __interrupt void Timer0_A0_ISR( void )
    {
      // TA0CCR0
    }

    and

    // Timer0 A1 interrupt service routine
    #pragma vector = TIMER0_A1_VECTOR
    __interrupt void Timer0_A1_ISR( void )
    {
      switch( TA0IV ) // Read interrupt vector for TA0
      {
        case 0: // No interrupt pending
        {
          break;
        }
    
        case 2: // TA0CCR1
        {
          break;
        }
    
        case 4: // TA0CCR2
        {
          break;
        }
    
        case 6: // TA0CCR3
        {
          break;
        }
    
        case 8: // TA0CCR4
        {
          break;
        }
    
        case 14: // Overflow - TA0IFG
        {
          break;
        }
      }
    }

    For TimerA1 there are these two ISRs:

    // Timer1 A0 interrupt service routine
    #pragma vector = TIMER1_A0_VECTOR
    __interrupt void Timer1_A0_ISR( void )
    {
      // TA1CCR0
    }

    and

    // Timer1 A1 interrupt service routine
    #pragma vector = TIMER1_A1_VECTOR
    __interrupt void Timer1_A1_ISR( void )
    {
      switch( TA1IV ) // Read interrupt vector for TA1
      {
        case 0: // No interrupt pending
        {
          break;
        }
    
        case 2: // TA1CCR1
        {
          break;
        }
    
        case 4: // TA1CCR2
        {
          break;
        }
    
        case 14: // Overflow - TA1IFG
        {
          break;
        }
      }
    }

    And for TimerB0 there are:

    // Timer0 B0 interrupt service routine
    #pragma vector = TIMER0_B0_VECTOR
    __interrupt void Timer0_B0_ISR( void )
    {
      // TB0CCR0
    }

    and

    // Timer0 B0 interrupt service routine
    #pragma vector = TIMER0_B0_VECTOR
    __interrupt void Timer0_B0_ISR( void )
    {
      switch( TB0IV ) // Read interrupt vector for TB0
      {
        case 0: // No interrupt pending
        {
          break;
        }
    
        case 2: // TB0CCR1
        {
          break;
        }
    
        case 4: // TB0CCR2
        {
          break;
        }
    
        case 6: // TB0CCR3
        {
          break;
        }
    
        case 8: // TB0CCR4
        {
          break;
        }
    
        case 10: // TB0CCR5
        {
          break;
        }
    
        case 12: // TB0CCR6
        {
          break;
        }
    
        case 14: // Overflow - TB0IFG
        {
          break;
        }
      }
    }

    You can see the individual names for the interrupt vectors in the header file for your processor. They are located at the end of the file (at least for the CCS headers). Here are all the names for your MSP430F5438A:

    /************************************************************
    * Interrupt Vectors (offset from 0xFF80)
    ************************************************************/
    
    #pragma diag_suppress 1107
    #define VECTOR_NAME(name)             name##_ptr
    #define EMIT_PRAGMA(x)                _Pragma(#x)
    #define CREATE_VECTOR(name)           void * const VECTOR_NAME(name) = (void *)(long)&name
    #define PLACE_VECTOR(vector,section)  EMIT_PRAGMA(DATA_SECTION(vector,section))
    #define PLACE_INTERRUPT(func)         EMIT_PRAGMA(CODE_SECTION(func,".text:_isr"))
    #define ISR_VECTOR(func,offset)       CREATE_VECTOR(func); \
                                          PLACE_VECTOR(VECTOR_NAME(func), offset) \
                                          PLACE_INTERRUPT(func)
    
    
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define RTC_VECTOR              ".int41"                     /* 0xFFD2 RTC */
    #else
    #define RTC_VECTOR              (41 * 1u)                    /* 0xFFD2 RTC */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define PORT2_VECTOR            ".int42"                     /* 0xFFD4 Port 2 */
    #else
    #define PORT2_VECTOR            (42 * 1u)                    /* 0xFFD4 Port 2 */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define USCI_B3_VECTOR          ".int43"                     /* 0xFFD6 USCI B3 Receive/Transmit */
    #else
    #define USCI_B3_VECTOR          (43 * 1u)                    /* 0xFFD6 USCI B3 Receive/Transmit */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define USCI_A3_VECTOR          ".int44"                     /* 0xFFD8 USCI A3 Receive/Transmit */
    #else
    #define USCI_A3_VECTOR          (44 * 1u)                    /* 0xFFD8 USCI A3 Receive/Transmit */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define USCI_B1_VECTOR          ".int45"                     /* 0xFFDA USCI B1 Receive/Transmit */
    #else
    #define USCI_B1_VECTOR          (45 * 1u)                    /* 0xFFDA USCI B1 Receive/Transmit */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define USCI_A1_VECTOR          ".int46"                     /* 0xFFDC USCI A1 Receive/Transmit */
    #else
    #define USCI_A1_VECTOR          (46 * 1u)                    /* 0xFFDC USCI A1 Receive/Transmit */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define PORT1_VECTOR            ".int47"                     /* 0xFFDE Port 1 */
    #else
    #define PORT1_VECTOR            (47 * 1u)                    /* 0xFFDE Port 1 */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define TIMER1_A1_VECTOR        ".int48"                     /* 0xFFE0 Timer1_A3 CC1-2, TA1 */
    #else
    #define TIMER1_A1_VECTOR        (48 * 1u)                    /* 0xFFE0 Timer1_A3 CC1-2, TA1 */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define TIMER1_A0_VECTOR        ".int49"                     /* 0xFFE2 Timer1_A3 CC0 */
    #else
    #define TIMER1_A0_VECTOR        (49 * 1u)                    /* 0xFFE2 Timer1_A3 CC0 */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define DMA_VECTOR              ".int50"                     /* 0xFFE4 DMA */
    #else
    #define DMA_VECTOR              (50 * 1u)                    /* 0xFFE4 DMA */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define USCI_B2_VECTOR          ".int51"                     /* 0xFFE6 USCI B2 Receive/Transmit */
    #else
    #define USCI_B2_VECTOR          (51 * 1u)                    /* 0xFFE6 USCI B2 Receive/Transmit */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define USCI_A2_VECTOR          ".int52"                     /* 0xFFE8 USCI A2 Receive/Transmit */
    #else
    #define USCI_A2_VECTOR          (52 * 1u)                    /* 0xFFE8 USCI A2 Receive/Transmit */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define TIMER0_A1_VECTOR        ".int53"                     /* 0xFFEA Timer0_A5 CC1-4, TA */
    #else
    #define TIMER0_A1_VECTOR        (53 * 1u)                    /* 0xFFEA Timer0_A5 CC1-4, TA */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define TIMER0_A0_VECTOR        ".int54"                     /* 0xFFEC Timer0_A5 CC0 */
    #else
    #define TIMER0_A0_VECTOR        (54 * 1u)                    /* 0xFFEC Timer0_A5 CC0 */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define ADC12_VECTOR            ".int55"                     /* 0xFFEE ADC */
    #else
    #define ADC12_VECTOR            (55 * 1u)                    /* 0xFFEE ADC */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define USCI_B0_VECTOR          ".int56"                     /* 0xFFF0 USCI B0 Receive/Transmit */
    #else
    #define USCI_B0_VECTOR          (56 * 1u)                    /* 0xFFF0 USCI B0 Receive/Transmit */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define USCI_A0_VECTOR          ".int57"                     /* 0xFFF2 USCI A0 Receive/Transmit */
    #else
    #define USCI_A0_VECTOR          (57 * 1u)                    /* 0xFFF2 USCI A0 Receive/Transmit */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define WDT_VECTOR              ".int58"                     /* 0xFFF4 Watchdog Timer */
    #else
    #define WDT_VECTOR              (58 * 1u)                    /* 0xFFF4 Watchdog Timer */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define TIMER0_B1_VECTOR        ".int59"                     /* 0xFFF6 Timer0_B7 CC1-6, TB */
    #else
    #define TIMER0_B1_VECTOR        (59 * 1u)                    /* 0xFFF6 Timer0_B7 CC1-6, TB */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define TIMER0_B0_VECTOR        ".int60"                     /* 0xFFF8 Timer0_B7 CC0 */
    #else
    #define TIMER0_B0_VECTOR        (60 * 1u)                    /* 0xFFF8 Timer0_B7 CC0 */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define UNMI_VECTOR             ".int61"                     /* 0xFFFA User Non-maskable */
    #else
    #define UNMI_VECTOR             (61 * 1u)                    /* 0xFFFA User Non-maskable */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define SYSNMI_VECTOR           ".int62"                     /* 0xFFFC System Non-maskable */
    #else
    #define SYSNMI_VECTOR           (62 * 1u)                    /* 0xFFFC System Non-maskable */
    #endif
    #ifdef __ASM_HEADER__ /* Begin #defines for assembler */
    #define RESET_VECTOR            ".reset"                     /* 0xFFFE Reset [Highest Priority] */
    #else
    #define RESET_VECTOR            (63 * 1u)                    /* 0xFFFE Reset [Highest Priority] */
    #endif

    When placing an ISR it is always like this:

    #pragma vector = <INTERRUPT VECTOR NAME FROM HEADER FILE>
    __interrupt void <ANY NAME YOU WANT>( void )
    {
      // Code for ISR
    }

    Hope this helps.

    Dennis

  • Dennis and Clemens, thanks for your effort!

    That was exactly what I wanted to know! Now I understand the behaviour behind the code snippets I copied!
  • You are welcome! No problem at all.
  • It should be added that the ISRs for CCR0 (as there is only one reason for the interupt) automatically clear the CCTL0.CCIFG bit. So the TIMERx_y0_VECTOR interrupts are only executed once per interrupt event.
    The other ISRs need to do it manually (or implicitly by reading the TyxIV register), or the interrupt remains pending and the ISR is called again and again.
  • Very Good Explanation

**Attention** This is a public forum