Jump to content
43oh

Timer Capture measurement of Period


Recommended Posts

Hello all,
 
I am new to programming in general. I was wondering if you can help me out by explaining a simple concept of timer capture measurement. I am using a launchpad with a msp430g2553. I started out by using the period measurement example from MSP430ware, file msp430g2xx3_ta_21.

 

When I input a 30Hz square wave signal into P1.2, I get period around 3850 on my watch expression. The period is calculated by subtracting the time of one rising edge from the previous rising edge. Can you help explain this number to me? Does it have to do with overheads? The Timer A is set up with SMCLK at 8MHz. I am ignoring the output PWM (Pin2.1) since I don't care about it.
 

 

//  MSP430G2xx3 Demo - Timer_A0, Normal Timer Mode Input Period and Dutycycle
//                     measurement
//  Description: This code example implements input capture in single capture
//  mode using TimerA in normal timer mode. TA1.1 is configured to output PWM
//  of 25% dutycycle, that is used as capture input at TA0.1. TA0.1 is
//  configured as timer input capture that is triggered by both the rising and
//  the falling edges. An external connection between TA1.1 and TA0.1 is
//  required in this example. Rising and Falling edges are captured and the
//  dutycycle is computed. If the measured dutycycle is != 25%, then LED on
//  P1.0 is set.
//
//  ACLK = LFXT1 = 32kHz crystal ; SMCLK = MCLK = 8 MHz;
//
//                 MSP430F51x2
//             -----------------
//         /|\|              XIN|-
//          | |                 | 32kHz
//          --|RST          XOUT|-
//            |                 |
//            |       P1.2/TA0.1|<-- CCI1A <-|
//            |       P2.1/TA1.1|--> CCR1 -->|
//            |                 |
//            |             P1.0|--> LED "ON" when dutycycle != 25%
//            |                 |

//
//  W. Goh
//  Texas Instruments Inc.
//  March 2012
//  Built with CCS v5.2 and IAR Embedded Workbench Version: 5.40.3
//******************************************************************************

#include <msp430.h>
unsigned char Count, First_Time;
unsigned int REdge1, REdge2, FEdge;

int main(void)
{
  unsigned int Period, ON_Period;
  unsigned char DutyCycle;

  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer

//  P1SEL |= BIT0;
  P1DIR |= BIT0;                            // P1.0/LED Output
  P1OUT &= ~BIT0;                           // LED off
  if (CALBC1_8MHZ==0xFF)                    // If calibration constant erased
  {                                            
    while(1);                               // do not load, trap CPU!!    
  }
  DCOCTL = 0;                               // Select lowest DCOx and MODx settings
  BCSCTL1 = CALBC1_8MHZ;                    // Set DCO to 8MHz
  DCOCTL = CALDCO_8MHZ;

  // Configure Port Pins
  P2DIR |= BIT1;                            // P2.1/TA1.1 Output
  P2SEL |= BIT1;                            // TA1.1 Option select
  P1DIR &= ~BIT2;                           // P1.2/TA0.1 Input Capture
  P1SEL |= BIT2;                            // TA0.1 option select

  // Configure TA1.1 to output PWM signal
  // Period = 82/32khz = 2.5ms ~ 400Hz Freq
  TA1CCR0 = 82-1;                          // Period Register
  TA1CCR1 = 21;                            // TA1.1 25% dutycycle
  TA1CCTL1 |= OUTMOD_7;                    // TA1CCR1, Reset/Set
  TA1CTL = TASSEL_1 + MC_1 + TACLR;        // ACLK, upmode, clear TAR

  // Configure the TA0CCR1 to do input capture
  TA0CCTL1 = CAP + CM_3 + CCIE + SCS + CCIS_0;
                                            // TA0CCR1 Capture mode; CCI1A; Both
                                            // Rising and Falling Edge; interrupt enable
  TA0CTL |= TASSEL_2 + MC_2 + TACLR;        // SMCLK, Cont Mode; start timer

  // Variable Initialization
  Count = 0x0;
  First_Time = 0x01;

  while(1)
  {
      __bis_SR_register(LPM0_bits + GIE);   // Enter LPM0
      __no_operation();                     // For debugger
      // On exiting LPM0
      if (TA0CCTL1 & COV)                   // Check for Capture Overflow
          while(1);                         // Loop Forever

      Period = REdge2 - REdge1;             // Calculate Period
      ON_Period = FEdge-REdge1;             // On period
      DutyCycle = ((unsigned long)ON_Period*100/Period);
      if(DutyCycle!= 25)
      {
          P1OUT |= BIT0;
      }
      else
      {
          P1OUT &= ~BIT0;
      }
  }
}

// TA0_A1 Interrupt vector
#pragma vector = TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR (void)
{
  switch(__even_in_range(TA0IV,0x0A))
  {
      case  TA0IV_NONE: break;              // Vector  0:  No interrupt
      case  TA0IV_TACCR1:                   // Vector  2:  TACCR1 CCIFG
        if (TA0CCTL1 & CCI)                 // Capture Input Pin Status
        {
            // Rising Edge was captured
            if (!Count)
            {
                REdge1 = TA0CCR1;
                Count++;
            }
            else
            {
                REdge2 = TA0CCR1;
                Count=0x0;
                __bic_SR_register_on_exit(LPM0_bits + GIE);  // Exit LPM0 on return to main
            }
            if (First_Time)
                First_Time = 0x0;
        }
        else
        {
            // Falling Edge was captured
            if(!First_Time)
            {
                FEdge = TA0CCR1;
            }
        }
        break;
      case TA0IV_TACCR2: break;             // Vector  4:  TACCR2 CCIFG
      case TA0IV_6: break;                  // Vector  6:  Reserved CCIFG
      case TA0IV_8: break;                  // Vector  8:  Reserved CCIFG
      case TA0IV_TAIFG: break;              // Vector 10:  TAIFG
      default:     break;
  }
}

 

 

Link to post
Share on other sites

Timer A is a 16-bit timer, the maximum value you can measure is thus 65,535 (216-1). At 8MHz / 30 Hz the count value would be 266,666, which is greater than 65535. The counter will wrap around to the start value of 0. The resulting counter value would become 4522 at 8MHz clock and 30Hz wave. This value may seem far off, but consider that the actual value was 266,666. If your input wave would be 30.075866Hz the value would match with your measured value.

 

To measure sound numbers, either increase your input wave to above 122.07Hz or lower your timer clock to below 1.966MHz.

Link to post
Share on other sites

I've wondered about this but never attempted it... couldn't you write an ISR that would advance a counter every time CCR0 rolls over....then record both numbers on the timer capture event?  You could then de-alias the period by adding back in <number of roll over events> * 65535 * <clock freq>

Link to post
Share on other sites

Yes you can. Mind that you'd need a 32 bit integer for this (unsigned long). Make sure to set this software counter to 0 at the right moment!

This is common practice in multiple cases. Whenever you need a look during counter this is the way to go.

I once made a clock that only kept track of minutes and hours, no seconds. It turned out that I had to keep track of seconds (or pairs of seconds) anyway, because I could not set my timer a higher interval with the given situation.

I used a 32.768kHz crystal, divided by 8 for the ACLK, divided by 215 by the WDT counter. The resulting frequency was 1/8Hz or 8 seconds per interval. Since I had to keep track of minutes, I could not use this interval; 60/8 is no integer number. 60/4 is not either. So I wound up using 60/2 by using 32.768kHz divided by 2 for the ACLK, then divided by 215 by the WDT counter. The resulting 0.5Hz interrupt enabled me to count up to 30 with a software counter (a variable) to count up to a whole minute.

Link to post
Share on other sites

I've wondered about this but never attempted it... couldn't you write an ISR that would advance a counter every time CCR0 rolls over....then record both numbers on the timer capture event?  You could then de-alias the period by adding back in <number of roll over events> * 65535 * <clock freq>

I think you'd need the overflow interrupt to fire when TA0R rolls over. The CCR0 interrupt would only fire when the capture occurs.

 

That means you'd need to be extra-careful of interrupt priorities, since the capture interrupt could happen at the same time as the TA0R interrupt. In that case the CCR0 interrupt would be processed first, and then the count would be off by 65535.

 

BTW, I haven't tried any of this so I might be wrong :)

Link to post
Share on other sites

Yea, it would be TA0R overflow.

 

I'm sure that could happen, but it shouldn't happen all that frequently.  If the signal you are watching isn't expected to change that fast, you could always store the previous reading and compare it to the current one...and adjust it if it is off by more than 65535.

Link to post
Share on other sites

Timer A is a 16-bit timer, the maximum value you can measure is thus 65,535 (216-1). At 8MHz / 30 Hz the count value would be 266,666, which is greater than 65535. The counter will wrap around to the start value of 0. The resulting counter value would become 4522 at 8MHz clock and 30Hz wave. This value may seem far off, but consider that the actual value was 266,666. If your input wave would be 30.075866Hz the value would match with your measured value.

 

To measure sound numbers, either increase your input wave to above 122.07Hz or lower your timer clock to below 1.966MHz.

Thank You! I lowered the timer clock and now receive measurement readings where I expect them to be.

 

I have one question though, sorry if this is offtopic. I happen to also have a Fraunchpad, and I tried to perform the same operation (after looking at more example codes and editing the proper pins/registers). It works!!! There is one slight gimmick. I soldered on the 32.768kHz microcrystal that came with the board to use for my timer clock. Would there be any reason, other than the divider, that my crystal is outputting 1/4 of expected 32.748kHz? I outputted the signal from my crystal to an oscilloscope and only get 8.192kHz without dividing it.

Link to post
Share on other sites

First off, I don't own a fraunchpad and haven't ever looked into them.

If you measure the crystal frequency with your oscilloscope you're influencing the frequency of the crystal. The MSP430G2 series accept a 12.5pF capacitance of the crystal, but can switch to 6pF at will. Most oscilloscopes (I've seen) have an input capacitance of about 50pF!

The only way to measure your crystal without influencing it, is to set an output pin to output ACLK or SMCLK (some pins can do that) and set the DIVA_x and/or DIVS_x value to 0 (divide by 1). Now you can measure the observed frequency of your crystal (or crystal clock circuit) without altering its behaviour.

For the MSP430G2 the pins used for the crystal oscillator are set to crystal oscillator function by default, but I'm not sure for the fraunchpad.

Link to post
Share on other sites

Well, I understand why I was reading a freq of around 8-9kHz. There is a failsafe that if there is a fault with the external crystal, VLO (typically between 8-10kHz) is automatically used instead of the external crystal. Thus, the 8-9kHz kicks in. ( -_-) I confirmed this by setting clock from VLO instead and measured from my oscilloscope.

 

Sorry for any misunderstandings, before, I did output the microcrystal to ACLK and then read ACLK from a pin. My oscilloscope shows the correct frequency once in a blue moon.

http://i.imgur.com/R2NeelP.jpg

 

 

As for why such a fault is happening... I don't know. Further testing is required. I am pretty sure that I didn't soldered it on wrong.

Link to post
Share on other sites

Thanks! It's good to learn about such behaviour, one doesn't realise that in fact another oscillator is used than instructed because of such fall back mechanisms. Thank you.

Haha... I read it in the Family User's guide... like others and you have said, it is very useful. It is a learning process.

 

I set a command to clear the fault. Illogically, if I just get a random piece of wire, tap XOUT from the microcrystal pin, the fault clears... yep... sigh.

Link to post
Share on other sites

Maybe you need to load the oscillator more, it is suggested in some app notes to connect a 47k resistor from XOUT to ground to do this. This will increase power consumption but it also increases the safety factor (some measure related to oscillator stability). Also, make sure your crystal capacitance (and connected capacitors together) match the input capacitance of the oscillator match, most times both are 12.5pF.

Link to post
Share on other sites

Video proof, stuck with VLO until... Tap Tap... o_O
The wire I use is just a simple wire lol... nothing is connected on the other end.

I would like to note that I was out of ideas when I decided to tap the XOUT with a random piece of wire to see this change.

 

Microcrystal that came with the board:
http://i.imgur.com/3U3SzqB.jpg

How I soldered it:

http://i.imgur.com/Ay9LMOM.jpg

 

 

 

I wouldn't think that I would need to increase the load. They packaged this crystal with this board, so I was hoping that I could merely use it right off the bat. The following shows the capacitors (12pF) used by the Fraunchpad. I will probably end up re-soldering the crystal.
.

jtPlGHx.jpg

Link to post
Share on other sites

 

 

The following shows the capacitors (12pF) used by the Fraunchpad. I will probably end up re-soldering the crystal.

 

jtPlGHx.jpg

 

Those capacitors aren't actually present on the board. The letters "DNP" alongside them mean "Do Not Populate". The oscillator circuit inside the MSP430 includes software-selectable load capacitors. You'll need to check that you've got the appropriate XCAP (or equivalent) bits set for the supplied crystal.

Link to post
Share on other sites

Those capacitors aren't actually present on the board. The letters "DNP" alongside them mean "Do Not Populate". The oscillator circuit inside the MSP430 includes software-selectable load capacitors. You'll need to check that you've got the appropriate XCAP (or equivalent) bits set for the supplied crystal.

Well, shame on me for not reading DNP. I am embarrassed.

 

Regarding the software-selectable load capacitors, I see that my launchpad (with msp430g2553) has xcap settings, but the fraunchpad (msp430fr5739) does not.

(Family User's guide http://www.ti.com/lit/ug/slau272b/slau272b.pdf)

 

 

Does this mean I should solder the two appropriate surface mount capacitors on c22 and c21?

http://www.ti.com/lit/an/slaa322b/slaa322b.pdf

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.

×
×
  • Create New...