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.

Need help with Timer_A

Other Parts Discussed in Thread: MSP430F2618

Hi All,

I am using the MSP430F2618 64 pin chip and the appropriate experimenters board.

  In a nutshell I am developing a metering application that  when a user leaves the threshold (or minimum value) it starts graphing but once they go below the threshold again the program gets stuck in a while loop until the users leaves threshold again. The problem I am currently working on is using Timer_A to find the exact time it takes for one cycle (which we estimate anywhere from 1 second to 6 seconds).  From my understanding we have to use a capture register to capture the clock at the exact moment we need it and than use that register make any calculations we need (e.g. Change the clock cycles into seconds based on HZ of the clock we set it too).  We would also like to at the point after we capture it to reset timer_A back to 0 and continue the counting.  I will put the sections of the code that have this implemented and I hope this community can nudge me in the right directions!

 

I am also setting ACLK (my source for Timer_A) to VLO and trying to get the lowest HZ I can since we need at most 1/100th of a second even that is a bit more precision than we need.

 

Thanks,

Jake G.

void InitFreq(void)
{
  // External oscilator 32kHz

  // Watchdog
  WDTCTL = WDTPW + WDTHOLD;  // Stop watchdog timer
  DCOCTL = CALDCO_8MHZ; 
  BCSCTL1 = CALBC1_8MHZ;
  BCSCTL1|=DIVA_3; // divide ACLK by 8
  BCSCTL3= LFXT1S_2;        // Set the source of ACLK to VLO to be used by Timer A
  TACCTL1 =CAP|CM_3|SCS|CCIS_1; //Initialize channel 1 to capture and syncronize to timer_A
  TACTL = TASSEL_1|ID_3|MC_2|TACLR;    // Initializes Timer A: ACLK, /8, continuous mode, and clearing timer
}

.

.

                if (y_data[0]<THRESHOLD && time_cnt>15) // Setting a minimum threshold
               {
                   TACCTL1^=CCIS0;//toggle the capture bit
                   //TACTL &= ~MC_2;    // Stop Timer A
                   rate = (int)(3.125/TACCR1+.5);    // Store Timer's cycles, get rate by dividing by Hz.
                   TACTL |= TACLR;    // Clear Timer A
                   TACTL = TASSEL_1|ID_3|MC_2;    // Reconfigure Timer A, start it

  • One method which I have used in the past when I needed to keep track of many different events which occured at fairly large time intervals was simple and effective.  I set up the timer so that it is always running with a 1 ms interrupt interval.  Then when the Start event occurred, I cleared the respective Count variable belonging to that process to zero and I would increment the variable at each interrupt.  When the Stop event occured, I would have an accurate time count with an accuracy of 1 ms.  When necessary, the Count variable could be a long int which would take a very long time rollover, and it is handy to have an interrupt which always occurs with a 1 ms period.

    Also, your line    rate = (int)(3.125/TACCR1+.5)    probably will not give you what you are looking for.  The registers of the MSP are read as integer values, so 3.125/TACCR1 will always return 0 when TACCR1 is greater than 3.   The line should probably be written       rate = (int)(3.125/(double)TACCR1+0.5)

    Hope this helps

  • sparkchaser said:
    rate = (int)(3.125/(double)TACCR1+0.5)

    It's generally a bug (regarding efficient code on microcontrollers) to use 1) floatign point and 2) floating point divisions.

    It's easy to replace this formula by soenthign that uses a integer arithmetics. Even integer divisions take a minor eternity to complete (typically >20µs even on the fastest MSPs), but FP divisions take two or three major eternities to complete.

    Try the following:

    rate = ((3200+TACCR1>>1)/TACCR1)>>10;

    It's by some magnitudes faster and gives the same result. Why 3200? Because I did 3.125*1024, which is undone later by >>10, And adding TACCR1>>1 before the division is like adding 0.5 after, yet it avoids FP)

  • Thanks for the quick responses!

     

    The interrupt is a great idea and seems like it could work, but with my program I am not sure it is feasible.  The reason for my doubts is that I have part of the code, which is a section that shows a live graph (or as live as you can get it with a microprocessor) of the users input.  With the constant LCD sends my LCD screen does not like to have an interrupt in between commands, thus I have interrupts disabled for that section.

     

    The question is even if interrupts are disabled for that sections does the flag stay up, thus waiting to do the interrupt until interrupt are enabled? If so I know that it would introduce a bit of error, but if it is 10 ms off or even 100ms off it really does not affect my results

     

    On another note did anyone see anything wrong on how I was calling and setting up of Timer_A?

  • The interrupt is pending until serviced. The flag won't be cleared if not immediately serviced.

    However, if you disable the interrupts for a longer time, it will introduce a 'clock-skew' to your timing. If this is not a problem (you don't need an accurate timing base), you can simply use the proposed approach.

    In my projects, I may not miss a millisecond even if the ISR cannot be executed in time. It would break some global timings. SO I implemented the timer a little bit differently: I let the tiemr running free with 1MHz clock. CCR0 is set to TAR+1000. That means that an interrupt will occur in 1000ms. Inside the ISR, I increment CCR0 by 1000, so the next interrupt will occur 1000ms after the last. Then I check whether the difference between TAR and CCR0 is perhaps >1000. If so, then I have missed at least one, possibly up to 65. So I increment my global counter once more and add another 1000 to CCR0. This way I catch up finally with the really passed time, no matter whether I had disabled intrrupts for up to 65ms. (doing it as a add/compare loop is faster than doing math that includes a division).

    Anyway, there are certainly moments during your main loop execution where interrupts may be enabled for a short moment. The only occasion where I really had to disable interrupts for longer than 1ms is during flash erase. Or when pushing data with 4MBd through an SPI connection. But there it was a performance thing, rather than a neccessity.

**Attention** This is a public forum