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.

msp430g2553 Timer 1 vs Timer 2 for frequency input

Other Parts Discussed in Thread: MSP430G2553

New to programming and MSP430.  I'm using an MSP430G2553 on the launch pad.  I'm counting pulses on Pin2 P1.0/TA0CLK/ACLK/A0/CA0 and displaying a frequency on and LCD display.  But I would like to count two different pulses.  And because the chip has two timers, I thought I could do that, but I don't see TA1CLK on this chip.  I do see TA1CLK on the 28 pin version of this chip Pin21 P3.7/TA1CLK/CAOUT.  An I correct that there is no way to use the second timer TA1 to count pulses?  If that's the case I'll have to move off the launch pad onto something else.  Note:  If I had to timers counting, the two timers would often be counting the same signal with some nano second delay.  I don't need to measure the delay, I just need to independent hardware counters like I assume TA0CLK and TA1CLK would be.  Any thought would be appreciated.

Thanks

  • You're right, on the 20 pin package, not all of the possible output and input signals are available. TA1CLK is one of them, and so is P3. You can't have a low pin count and many signals together.

    However, using TA1CLK isn't the only way to count pulses. Depending on pulse frequency, you may set up TA1CCR1 (or even TA0CCR1) for triggering an interrupt on a pulse. And count in software. Then you can use TimerA1 for it main purpose: timing. E.g. for checking the number of pulses during a certain interval (gives the frequency).
    Whole P1 and P2 are also capable of triggering an interrupt on an incoming edge.

  • My highest frequency is about 20KHz which should be fine using interrupts I think.  But I didn't think I could have 2 simultaneous interrupts in software, which is what would happen if  I sent the same signal to two pins (which will often happen).  I'll try the method you described and see how it works.  Any other thoughts, please let me know.  Thanks.

    Eugene

  • Hey it works!  Here's a bit of my code.  I have two pwm outputs and when I send the same pwm output into P1.0 and P1.3 I get two identical increasing counts on the display.  I thought one interrupt would prevent a second interrupt that happens at the same time.  I did read a section in the manual that describes how the chip stores up interrupts and takes care of them next chance it gets.  Makes me wonder how many interrupt it can handle at the same time.  8 maybe?  That would be I could have 8 independent count inputs, which would be fantastic.  Although 4 count inputs would be more that enough.  I've been learning from this e2e blog for a few months now.  It's fun to finally be at a point where I can actually ask an intelligent (so I think) question and maybe even contribute something.  Thanks a bunch for your help.  I'll have to test this further to see what the limitations are, but so far so good.

    void main(void)
    {
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;
    n1=0;
    n2=0;
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

    InitializeLcm();

    ClearLcmScreen();

    // ---------------2 pwm section--------
    P2DIR |= BIT1; // Set P2.1 to output direction
    P2SEL |= BIT1; // P2.1 to TA1.1
    P2DIR |= BIT4; // Set P2.4 to output direction
    P2SEL |= BIT4; // P2.4 to TA1.2

    TA1CCR0 = 4850-1; // PWM Period
    TA1CCTL1 = OUTMOD_7; // CCR1 reset/set
    TA1CCTL2 = OUTMOD_7; // CCR2 reset/set
    TA1CCR1 = 40; // CCR1 PWM duty cycle
    TA1CCR2 = 50;
    TA1CTL = TASSEL_2 + MC_1; // SMCLK, up mode

    P1IE |= BIT0; // P1.3 interrupt enabled
    P1IES |= BIT0; // P1.3 Hi/lo edge
    P1IFG &= ~BIT0; // P1.3 IFG cleared

    P1IE |= BIT3; // P1.3 interrupt enabled
    P1IES |= BIT3; // P1.3 Hi/lo edge
    P1IFG &= ~BIT3; // P1.3 IFG cleared

    _BIS_SR(GIE); // general interrupt enable
    // ------------------------------------------
    }


    void printstuff()
    {
    itoa(n1,num1,20000);
    SendByte(0x80 | 0, FALSE);
    PrintStr("Channel 1");
    SendByte(0x80 | 0x40, FALSE);
    PrintStr("Channel 2");
    }


    // Port 1 interrupt service routine
    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    {
    if ( (P1IFG & BIT0) == BIT0 )
    {
    P1IFG &= ~BIT0; // P1.3 IFG cleared
    printstuff();
    n1++;
    itoa(n1,num1,20000);
    SendByte(0x80 | 0x0B, FALSE);
    PrintStr(" ");
    PrintStr(num1);
    }
    if ( (P1IFG & BIT3) == BIT3 )
    {
    P1IFG &= ~BIT3;
    printstuff();
    n2++;
    itoa(n2,num1,20000);
    SendByte(0x80 | 0x4B, FALSE);
    PrintStr(" ");
    PrintStr(num1);
    }
    }

  • Eugene said:
    Makes me wonder how many interrupt it can handle at the same time.  8 maybe?

    The only limit is the number of IFG bits in the various registers across the whole MSP module range.

    Interrupts are served using a priority encoder. Such an encoder has a nubmer of binary inputs and an output that produces the 'number' of the  highest input line that flags an interrupt.

    As long as the output is >0, interrupts are triggered, the one on the highest line being the next one 'reported' as pending. This is the nubme rof the interrupt vector to call.

    All IFG bits are gated by the matching IE bits (both must be set at the same time, so the encoder will 'see' the interrupt on its input.

    If an IFG (or IE) bti is cleared before its request was forwarded by the priority encoder and accepted by the CPU, the interrupt is lost as if it never happened.

    The individual modules on the MSP (Timer, USCI etc.) have their own internal management. usually, their pending interrupts are ORed together into one signal that arrives at the priority encoder.

    Some modules also have their own priority encoder that feeds the module-specific IV register (if available).

    If you want to know more about priority encoders, see here.

  • Looks like I've got some homework to do!  My previous code is sending data to display after each interrupt which is causing incorrect pulse count.  I'm testing at about 200Hz, but counts on the display are increasing at a rate much slower that 200Hz.  So I made a code change to only display counts when counts reach 200.  Now I'm seeing: 200, 1 second later, 400, 1 second later, 800, etc.  Which is 200Hz.  But again, I need to better understand your interrupt explanation to do things right.  Thanks for the advice and the link to priority encoder info.  I'll click the yes-this-answered-my-question button when I see it again.

    Eugene

  • Eugene said:
    Looks like I've got some homework to do!  My previous code is sending data to display after each interrupt which is causing incorrect pulse count.  I'm testing at about 200Hz, but counts on the display are increasing at a rate much slower that 200Hz.  So I made a code change to only display counts when counts reach 200.  Now I'm

     Hi, Hint from Jean are the first step, to avoid pulse missing or averaging or some other must be done on foreground loop so:

     On interrupt read the pulse value do some small calculation then store to a queue

     On main loop retrieve the values from queue, do presentation calculations then send to display at a low data rate, human can read few value a second so 200 readings to seconds are too fast  to be presented to eye and just some fraction of them can be appreciated.

  • Hi Roberto,

    Thanks for the good advice.  I was just realizing I need to keep code in the interrupt routine as small as possible.  Then, as you said, I'll display the incrementing value on the display at a reasonable rate to view.  No need to post every increment.  I'll post my results when I get it working.

    Thanks,

    Eugene

  •  Hi Again, I edited the previous text to add two missed word and some missing letters.

     TO help time keep write a timing service or add on pwm regular timer interrupt a count down you can use to do action on main loop. Enter LPM on main and exit LPM when timer is fired.

    EXAMPLE:

    -------------------------------------

    volatile int mytimer0=0;

    ------------ usage on some part of code ----------------

    // init timer to value and usage (not on loop that test it !!!)

    mytimer=xxx;

    if(!timer)

      action@timeout

    ------------------------------------------------

    ---- on loop where you need ----

     if( !mytimer)

    {

    // your code to be executed when timer expire

     mytimer=xxx; // reinit timer if regular service needed

    }

    enter LPM if needed

    ---- end loop -----

    --------- On interrupt service ------

    if(mytimer) mytimer--;

    exit LPM if used...

    ------------------------------------------------------------------------

     This way you can save a lot of time and also enter low power with precise timing.

**Attention** This is a public forum