SparkFun Forums 

Where electronics enthusiasts find answers.

Discussions on how to get your MSP JTAG programmer up and running.
By elliotbriggs
#37970
Hey, any help with this problem will be greatly appreciated.

I am trying to measure frequencies in the range of 300-600kHz with the MSP430F2274 using capture mode in Timer A. As of now I am able to measure up to 400kHz by just interrupting on each rising transition and recording TACCR0 to a variable. Later, out of the interrupt I convert the time between capture numbers to frequency. I'm sure many are familiar with this.

I have my clock running at the full 16MHz, it seems that with higher clock frequencies, the higher speeds I am able to read since the interrupt is able to finish in a shorter amount of time before the next interrupt.

Is there a way to maybe do some sort of pulse counting so the interrupt happens every other rise-time? My PCB has already been fabricated so I can't add any additional hardware to divide the frequency.

Here is my current ISR and timer A register values:

TACCTL0 |= CM_1 + SCS + CCIS_0 + CAP + CCIE;
TACTL |= TASSEL_2 + MC_2;

_BIS_SR(LPM0_bits + GIE);

#pragma vector=TIMERA0_VECTOR
__interrupt void TimerA0(void)
{

capture_array[i++] = TACCR0; //stores TACCR0 to a new array location
if(i == 2)
{
TACCTL0 &= ~CCIE;
LPM0_EXIT;
}
}

thanks in advance.
By riden
#37995
Instead of counting the pulses, measure the period using the timer. Then you could control the number of samples to your hearts content. I'm not a MSP user, so I can't provide actual sample code. However, the technique is to clear a timer, set the chip to start the timer on the rising (or falling) edge of the signal, and stop the timer on the opposite transistion.
By elliotbriggs
#38008
If I understand your response, you're saying just record the time-stamp of each transition each time the signal changes state.

This is actually what I'm doing. Each time TA0 receives a rising edge, the current value of the counter in timer A is recorded to TACCR0, which is stored to an array variable. This works great until you go over 400kHz with a 16MHz clock. It seems that the ISR is taking up too much overhead and can't re-interrupt fast enough.

If my chip had a DMA controller or something of the sort it would be nice. I need to find a better way to do this operation without using too many clock cycles in the process. Again, 600kHz is the goal...almost there.
By riden
#38012
Hmmm, my browser seemed to have reset itself and I lost my post. :( Oh well, always easier the second time around.

There is no need for DMA or a higher powered processor. 600KHz is well within the range of even the low end PIC processors. Some of what you need will depend upon the resolution of the frequency measurement, but it is doable.

Another approach (gated counting, which is similar to the ones discussed), involves counting the number of transitions that occur over a precise period of time (.1 sec, 1 sec, etc.) Since most timers are 8 or 16 bit, you would have an IRQ routine that would only fire on timer overflow and increment a variable. In other words, your total count for a given period of time would be the actual value of the timer after the gate period has ended PLUS any overflow count. This is how my PIC frequency counters work and I can measure 50Mhz+ (even more if I use a prescaler). At 600Khz, 1 Hz resolution is not a problem and I think you could do even better.

I feel a little out of my league as I haven't used the Texas Instruments processors, but the principals are the same.
User avatar
By leon_heller
#38021
You could try the MSP430 Yahoo group, that is where all the MSP430 experts are to be found.

Leon
By OldCow
#38032
(1) You could use TimerB to divide the 300-600 kHz by 2, 3, 4. ..., 65536 and then use TimerA as you did. This involves a small change in hardware.

(2) You could use a tricky assembly ISR to handle TimerA CCR0 interrupt without changing the hardware too.
By elliotbriggs
#38113
I think the next plan of action is to have the signal toggle an interruptible I/O pin instead of throwing the timer A interrupt. Before I was interrupting on every capture. I'll just count I/O toggles and use the compare feature in timer A to interrupt on overflow and disable the I/O interrupt. This will give me how many times the signal toggled the I/O within a precise period of time.

Just as a backup I included a PLL which outputs into an ADC pin. The analog way always seems easier! :wink:
By gm
#38121
Instead of using the interruptible I/O pins (as you will still be servicing interrupts at a 600 KHz rate), just use the TACLK or TAINCLK to count the pulses and use Timer B as the timebase. I've used this method to calculate the DCO frequency by using the 32KHz ACLK as the timebase.

Hope this helps,

Greg
By elliotbriggs
#38233
That's a really good idea. The timer A will just count with every clock in TAINCLK which can be an external signal. Once the timer in timer B overflows, take the current TACCR count and do the math to get frequency.
By elliotbriggs
#45285
I thought this might be useful to somebody. I got this working after I last posted a few months ago and it seems to be working quite well. I can measure up to 600kHz with seemingly little error.

I'm posting this so that someone may find possible improvements. Let me know if anything needs to be clarified. I know the calculations at the end are very inefficient, but it works. I can clean that up later.

The frequency to be measured is a squarewave coming in on P1.0 (TACLK)

Code: Select all
  //Timer B// 
         
  TBCTL |= TBSSEL_2 + ID_3 + TBCLR;         // SMCLK/8 = 2MHz, count to TBCCR0 and interrupt
  TBCTL |= MC_2;

  //Timer A// 

  TACTL |= TACLR;                               // Ext. TACLK on P1.0, Clear timer A
  TACTL |= MC_2;                            // continuous count to 0xFFFF
                     
  while(!(CCIFG & TBCCTL0));                // Poll for interrupt flag from timer B
  TBCCTL0 &= ~CCIFG;                        // Clear flag
  x = TAR;                                // Take snapshot of count in TAR
  TBCTL |= TBCLR;                           // Clear and stop both timers
  TBCTL &= ~MC_2;
  TACTL |= TACLR;
  TACTL &= ~MC_2; 
 
temp = (65535/x);                         // Calculate frequency
 
  frequency = (2000000)/ temp; 
  split = (frequency/1000);                    // Results in kHz