Jump to content
Sign in to follow this  
geralt1114

MSP430 frequency meter

Recommended Posts

Hello guys,i have a question for my project im using the msp430g2231 microcontroller and i want to measure frequencies up to 10Mhz.Im new to microcontrollers(not programming),and im not sure how to make the overflow work

void main(void)
{

WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
BCSCTL1 = CALBC1_1MHZ;          // Set range
DCOCTL = CALDCO_1MHZ;           // Set DCO step + modulation
delay(100);     // delay 100mS until next screen refresh


/*** Timer_A Set-Up ***/
    TA0CCR0 = SampleTuneTime;
    TA0CCTL0 |= CCIE;                       // Interrupt enable
    TA0CTL |= TASSEL_1 + ID_3;              // SMCLK
    TA0CCTL1 |= CCIE + CCIS_0 + CM_1 + CAP; // Interrupt enable, capture select CCIxA, Positive edge, capture mode
    TA0CTL |= TASSEL_1;                     //SMCLK

    _BIS_SR(GIE);               // Enter LPM0 with interrupts enabled
    
             
                        
    while(1)
    {

    TA0CTL |= MC0;              // Start timer up mode.Timer counts up to TACCR0
    TA0CTL |= MC1;              // Start timer
    //while(CounterValue != 400); // Wait while CounterValue is not equal to 400
    TA0CTL &= ~MC0;             // Stop timer mode
    TA0CTL &= ~MC1;             // Stop timer

    Result >>= 2;               // Divide Result by 4
            calc_freq();

            //convert long into frequency
            char buffer[8]= { 0, };
            unsigned long toLCD = Frequency;
       //     int Base = 10;
            itoa(toLCD,buffer);     //convert decimal
                       
              lcd_init(); 
              send_string("FREQUENCY IS");
              send_command(0xC0);
              send_string(buffer);
              send_command(0xC8);
              send_string("HZ");

                    Result = 0;                 // Zero Result
                    CounterValue = 0;           // Zero CounterValue
                    StoredCount = 0;            // Zero StoredCount
                    TA0R = 0;                   // Zero Timer_A0 register
   }
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer0_A0(void)
{
    TA0CTL &= ~MC0;             // Stop timer
    TA0CTL &= ~MC1;             // Stop timer
    CounterValue++;             // Increment CounterValue
        if (CounterValue >= (NumberSamples +1)) // Reset values if NumberSamples +1 is reached
            {
            CounterValue = 0;   // Zero CountValue
            StoredCount = 0;    // Zero StoredCount
            }
    Result += StoredCount;      // Store accumulated count in Result
    StoredCount = 0;            // Zero StoredCount
    TA0CTL |= MC1;              // Start timer
    TA0CTL |= MC0;              // Start timer
    StoredCount++;      // Increment StoredCount
}
 

this is the main code of the program im using custom made function for the itoa and the communication with the LCD.I have two questions

1.) Can i make the frequency meter up to 10Mhz  cuz the g2231 has one timer and 1Mhz calibration available.

2.)Can i somehow check if the code is working cuz i dont have any way to send frequency right now,like counting the internal frequency or something like that.

Thank you for your time.

Share this post


Link to post
Share on other sites

Several things here:

where are/what are the declarations for the variables you are using? The types matter here.

You seem to be using the capture mode, but you are not ever pulling the captured value from the TACCRx in the interrupt handler. A capture event copies the value from the count register to the CCR

 

Please explain a bit about what your method is here. (as an aside, much of the documentation you have is not useful- it should express what the statements mean in terms of the solution. For example: "CounterValue++;             // Increment CounterValue" What does countervalue represent? What are you counting? The next line, same. and so on. Good docs make it a LOT easier to help)

 

As to the questions:

What do you mean "make overflow work"?

"Can i make the frequency meter up to 10Mhz". Sure. With high enough system clock. It will have poor resolution at the high end if you are doing it by timing from edge to edge (what capture mode will let you do). At low frequency, this is very effective. At higher frequency, it is better to count edges for a fixed period, but that needs to be done with hardware counting, as the interrupt latency, even at 16MHz system clock, will limit you to less than about 1MHz counting in software, and that is tough to hit. This would require a device that has two timer modules (one to time an interval, the other to count using INCLK (TASSEL_3-not available on the g2231)

"Can i somehow check if the code is working" Easiest if you find a means to provide a test signal to the input pin. There are a lot of ways (555 timer circuit, leach a 32768Hz signal if that is available on board, 50 or 60Hz grid frequency with the appropriate signal conditioning, a phototransistor in front of a flickering light source, like a PWM'd LED,and so on), but without knowing more about what you have available, I really can't tell you any more than that.

 

Share this post


Link to post
Share on other sites

Hello,thank you for the reply

#define DR P1OUT = P1OUT | BIT4          // define RS high
#define CWR P1OUT = P1OUT & (~BIT4)      // define RS low
#define READ P1OUT = P1OUT | BIT5        // define Read signal R/W = 1 for reading
#define WRITE P1OUT = P1OUT & (~BIT5)    // define Write signal R/W = 0 for writing
#define ENABLE_HIGH P1OUT = P1OUT | BIT6 // define Enable high signal
#define ENABLE_LOW P1OUT = P1OUT & (~BIT6) // define Enable Low signal
unsigned int i;
unsigned int j;
volatile unsigned int CounterValue = 0;
volatile unsigned int StoredCount = 0;
unsigned int Result = 0;
const int NumberSamples = 4;
unsigned int Frequency = 0;
unsigned int SampleTuneTime = 10000;

 

so these are the values i have declared,about the code my idea was that on the rising edge of the signal i turn on the counter i store it in a variable and on falling edge i stop it and read it.I load a value into  TA0CCR0 so that TA0 can count up to it,after that TA0CCR0 intrerrupt triggers and increments CounterValue.StoredCount  is the number of positive edges seen in the desired frequency.Im havent set a fixed frequency yet because i was still experimenting

 float SampTime = 0.03;      // 30mS sample time
    Frequency = Result / SampTime;   // Divide the averaged sampled result by the sample time to gain the frequency

i calculate the frequency like this i convert the value stored in Frequency to a string with the itoa function and send it to the LCD like this 

And about the overflow thing,sinse i think the SMCLK is only 1 MHz and i need 10 from what i understanded the overflow lets you go higher but i need to read more about it.

void send_string(char *s) 
{
while(*s)
{
send_data(*s);
s++;
}
}

Of course what i did could be completely wrong sinse its my very first msp430 project and things are still confusing for me/

Share this post


Link to post
Share on other sites

Lets work through a few things here...

Frequency is the number of complete cycles per second. This can be determined a number of ways. The scheme you seem to be going for is to time a cycle. This would be from an edge to the next instance of the same type edge- rising to rising, for example.

This will produce a count that is a time. The base unit may be microseconds at a 1MHz clock, but it is a time- the period of the signal. The frequency unit will be the reciprocal of this. Lets say that the count is 140. This means that 140microseconds (140E-6 seconds) lapsed from one rising edge to the next rising edge. The frequency will be 1000000/140 (1E6 clocks/second / 140 clocks to get the unit 1/second, or Hz) = 7143Hz.

 

That's the concept. The code you have does not do this.

When the interrupt occurs in CAPture mode, the count in the timer is copied to the CCR. This is what you need to pull. As long as this has not rolled over, the count tells you the period of the measured signal. You never read this.

You have:

    Result += StoredCount;      // Store accumulated count in Result
    StoredCount = 0;            // Zero StoredCount
    TA0CTL |= MC1;              // Start timer
    TA0CTL |= MC0;              // Start timer
    StoredCount++;      // Increment StoredCount

This has several issues, including: you set storedcount to zero every interrupt, then increment it. The net result is that the value will be 1 at the end of the handler, every time, and 1 when the handler is entered, every time except if it has be set elsewhere..

Also, you generally would not want to stop and start the timer in the handler like this. The external signal goes on. The timer stops. The acquired time will be wrong.

 

An outline of what you might do (copied directly from the documents for a system I implemented last year. The system is safety critical in a manufacturing plant and was reviewed and tested exhaustively)

 

Up count the timer

interrupt on overflow: this is so you can detect the overflow and deal with it, either  with an overflow count or as an out-of-range. This interrupt is hardware supported for just such a purpose

Interrupt on capture: grab the value of the CCR and store  it in your volatile. Exit sleep mode so your loop in main can grab the stored value and do it's thing. If counting overflows, the overflow counter gets copied at the same time, and reset.

No need to reset the CCR. You don't look at it anywhere else. You do NOTHING on overflow except increment the overflow count.

 

There are several ways to go about maintaining the counter. You can reset it when the CCR capture occurs, or you can let it free run, and the ACTUAL value to use is the difference between the current capture and the prior one. There is a little more work if you are counting overflows. Resetting in code introduces synch error. If it is not supported by hardware- I can't remember (and am too lazy to look up)  if the 2231 can do the reset  of the timer count on CAPture events- the differencing option is the better choice.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...