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.

Capture using 2 signals [Code Issues]

Other Parts Discussed in Thread: MSP430F5342

Hello,

I'm using an MSP430F5342 to capture the 16 bit timer A value at 2 different instances which are separated from each other by a few hundred milliseconds. Both captures are triggered respectively by input signals on the Pins 1.3 and 1.4, which i've internally pulled up using software.

I want to test the signal using a simple monoshot input on both pins 1.3 and 1.4.

1) The first issue is - How do i associate the ISR with the particular capture, i.e, i want the first ISR (A0) to be called when CCR0 receives a capture, and the second ISR (A1) to be called when CCR1 gets its capture. 

2) The second issue is - I am unsure whether increment the variable 'i' to get the actual value of the timer is the correct way to do it.

3) Im sure there are multiple other issues with the code, so even little bits of information could help.

#include <msp430.h>

 

double a = 0;

double b = 0;

double i =0;

 

int main(void)

{

   WDTCTL = WDTPW + WDTHOLD;                    //Disable Watchdog Timer           

   P1DIR = 0x03;                                //Output on Pins 1.0 & 1.1

   P1REN = 0x18;                                //Pullup pins 1.3 & 1.4

   P1SEL = 0x18;                                //Special Pin function for 1.3 & 1.4

   TA0CCTL2 = CM_2 + CCIS_0 + SCS + CAP + CCIE; //Setting up Capture on falling edge, Synchronous Capture, and Interrupt Enable for both registers

   TA0CCTL3 = CM_2 + CCIS_0 + SCS + CAP + CCIE;

   TA0CTL = TASSEL_1 + MC_2;                    //Continuous Mode and ACLK Source (32kHz)

   __bis_SR_register(LPM0_bits + GIE);          //LPM0 and General Interrupt Enable

   i++;                                         //Incrementing variable for true timer value

   while(1);

}

#pragma vector=TIMER0_A0_VECTOR

__interrupt void TIMER0_A0_ISR()

{

  a = TA0R + (i*65535);                         // True Timer Value

  P1OUT ^= 0x01;                                // Toggle Output Pin 1.0 to indicate capture

  TA0CCTL2 &= ~(CCIFG);                         // Clear Flag

}

 

#pragma vector=TIMER0_A1_VECTOR

__interrupt void TIMER0_A1_ISR()               

{

  b = TA0R + (i*65535);                         // True Timer Value

  P1OUT ^= 0x02;                                // Toggle Output Pin 1.1 to indicate capture

  TA0CCTL3 &= ~(CCIFG);                         // Clear Flag

}

Thanks in advance :-D

  • You mention CCR0/1, but you're using CCR2/3; this makes a difference in the answer. The A0 interrupt applies only to CCR0, and A1 to all the rest. In this case, you'll be using only A1.

    In the A1 ISR, use TA0IV to distinguish CCR2 from CCR3. If you do this, you don't (shouldn't) manually clear the CCIFG.

    The captured timer values are in CCR2/3, not TA0R.

    Don't do floating point in the ISR; in fact, I recommend you don't do it at all. Instead, enable the overflow interrupt (TAIE), then count these in a 32-bit integer which you increment by 0x10000UL. When you get the capture, just add this overflow counter to the capture value. (There is a minor race here, if the capture and overflow happen close together; worry about this later, after you get the rest running.)

  • Hey,

    Thanks for the reply. I didnt fully understand when A0 and A1 were called, and your answer cleared that up for me. Now, if i only have to use A1, then do i just equate both the variables a and b to CCR2 and CCR3 respectively in the A1 interrupt function? I just want to make sure that the value of CCR2 does not get altered when the timer interrupt A1 is called for CCR3?

    Bruce McKenney47378 said:
    then count these in a 32-bit integer

    Here, when you say count these, i assume you are referring to the 2 variables a and b?

    Also, when you enable the TAIE bit, isnt the A1 interrupt also responsible for this? So, would i have to add the value of TA0R here or TA0CCR0 (Assuming im running it in up mode)?

    Thanks.

  • The 32 bit variable counts overflows (TAIE). In your switch(TA0IV) block you might have:

    case 0x0E:                             // TAIFG (XXX name)

          high_bits += 0x00010000UL;  // Increment high half

          break;

    Then compute the actual value:

    case 0x04:                            // CCR2 CCIFG (XXX name)

          a = high_bits + TA0CCR2;   // Patch in low half

          break;

    case 0x06:                            // CCR3 CCIFG (XXX name)

           b = high_bits + TA0CCR3;   // Patch in low half

           break;

    I think your life will be simpler if you just use Continuous (MC_2) mode, but if you can't get the range/resolution you want there's a variant of this which will work in Up (MC_1) mode.

  • Got it. Thanks a ton for the help. Cleared up a couple of my fundamental doubts as well.

    Cheers.

  • Hey,

    This is a test code with the method suggested -

    #include <msp430.h>

     

    float a = 0;

    float b = 0;

    int j,k=0;

    float i =0;

     

    int main(void)

    {

      while(j!=1)                                                                   //Exit once 1 capture has been obtained

      {

       WDTCTL = WDTPW + WDTHOLD;                    //Disable Watchdog Timer           

       P1DIR = 0x87;                                //Output on Pins 1.0,1.1&1.7

       P1REN = 0x18;                                //Pullup pins 1.3 & 1.4

       P1SEL = 0x18;                                //Special Pin function for 1.3 & 1.4

       TA0CCR0 = 50000;

       TA0CCTL0 = CCIE;

       TA0CCTL2 = CM_2 + CCIS_0 + SCS + CAP + CCIE; //Setting up Capture on falling edge, Synchronous Capture, and Interrupt Enable for both registers

       TA0CCTL3 = CM_2 + CCIS_0 + SCS + CAP + CCIE;

       TA0CTL = TASSEL_1 + MC_2 + TAIE;                    //Continuous Mode and ACLK Source (32kHz)

       __bis_SR_register(LPM0_bits + GIE);          //LPM0 and General Interrupt Enable                                       

      }

      TA0CCR0 = 0;

      TA0CTL = 0x0000;

    }

     

    #pragma vector=TIMER0_A0_VECTOR

    __interrupt void TIMER0_A0_ISR()

    {

      P1OUT ^= 0x84;

    }

     

    #pragma vector=TIMER0_A1_VECTOR

    __interrupt void TIMER0_A1_ISR()               

    {

      switch(__even_in_range(TA0IV,14))

      {

        case  0: break;                       

        case  2: break;                         

        case  4:

          {

            a = TA0CCR2 + i;

            P1OUT  ^= 0x01;

            j=1;

            break;

          }

        case  6:

          {

            b = TA0CCR3 + i;

            P1OUT ^= 0X02;

            k = 1;

            break;

          }

        case  8: break;                          

        case 10: break;                          

        case 12: break;                         

        case 14:

          {

            i += 1;

            break;

          }

                

        default: break;

      }

    }


    I've encountered a couple of issues in the execution of the code. For one, the program does not seem to exit once a capture has been performed. Instead, the variable i is incremented a multiple number of times, depending on the length i keep the program running. Also. the voltage on the pins continues to toggle, when the timer ought to be shut down. Thanks.

  • Aditya Shanker1 said:
    However, the code does not exit the while loop, with the variable 'i' incremented multiple times, regardless of the value of the variable 'j'

    The compiler doesn't know that there is an ISR that magically changes the content of j outside of the program flow.
    So it might keep a copy of j in a processor register and the CPU never notices that the loop exit condition ahs magically changed.

    To tell the compiler that it shall physically access a global variables location each tiem it is use din the code, and not make any optimizations, you need to declare this variable volatile.

    Generally, every global variable that is used in both, main code and an ISR, needs to be declared volatile, to tell the compiler that it may change without any apparent reason (from the code flow - remember that the compielr doesn't knwo wht might ehrn trigger an interrupt  adn the ISR might as well be in a completely different source file) and that writing to it may have side-effects, so it must be done exactly when and as often as it appears in the source code.

    All hardware registers are volatile variables to the compiler.

  • Hey,

    Thank you for the reply. So i changed all the globally declared variables, including the ones controlling the loop exit to volatile, but it doesn't seem to have any effect. The program still refuses to exit the loop, while 'i' continues to be incremented.

    Just for reference, i is intended as an overflow counter, to add the overflow value to the variables a & b. In the real code, I've used the value 0xFFFF in 'i' in place of 1, and changed all the data types to double.

    Also, another problem i seem to have encountered is that the value of i is larger than it should be. For example, for 4 captures, the value of i is either 6 or 7. Any idea why this happens?

  • The bottom of your loop does LPM0 (equivalent) but there's no corresponding LPM0_EXIT to wake it up, so you only loop once (ever). Your timer (A1) ISR might be a good spot for it.

  • Hey,

    That seems to have sorted the multiple capture issue and most of the other ones. So thank you both for that :). There's still a few small kinks, but let me try sorting those out by myself. 

    Thanks for all the help.

  • Aditya Shanker1 said:
    i changed all the globally declared variables

    Don't declare all as volatile. Only those which are used outside the normal program flow (used in main as well as inside an ISR).
    It won't break your code when you declare all globals as volatile, but it will cripple compiler optimization, so the resulting code size will grow and execution speed fill decrease.

**Attention** This is a public forum