Avalon 5 Posted April 9, 2013 Share Posted April 9, 2013 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; } } Quote Link to post Share on other sites
roadrunner84 466 Posted April 9, 2013 Share Posted April 9, 2013 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. bluehash and Avalon 2 Quote Link to post Share on other sites
mbeals 74 Posted April 9, 2013 Share Posted April 9, 2013 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> Quote Link to post Share on other sites
roadrunner84 466 Posted April 9, 2013 Share Posted April 9, 2013 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. Avalon 1 Quote Link to post Share on other sites
tripwire 139 Posted April 9, 2013 Share Posted April 9, 2013 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 Avalon 1 Quote Link to post Share on other sites
mbeals 74 Posted April 9, 2013 Share Posted April 9, 2013 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. Quote Link to post Share on other sites
Avalon 5 Posted April 10, 2013 Author Share Posted April 10, 2013 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. Quote Link to post Share on other sites
roadrunner84 466 Posted April 10, 2013 Share Posted April 10, 2013 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. Avalon and tripwire 2 Quote Link to post Share on other sites
Avalon 5 Posted April 17, 2013 Author Share Posted April 17, 2013 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. roadrunner84 1 Quote Link to post Share on other sites
roadrunner84 466 Posted April 17, 2013 Share Posted April 17, 2013 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. Quote Link to post Share on other sites
Avalon 5 Posted April 17, 2013 Author Share Posted April 17, 2013 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. Quote Link to post Share on other sites
roadrunner84 466 Posted April 17, 2013 Share Posted April 17, 2013 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. Avalon 1 Quote Link to post Share on other sites
Avalon 5 Posted April 17, 2013 Author Share Posted April 17, 2013 Video proof, stuck with VLO until... Tap Tap... o_OThe 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.. Quote Link to post Share on other sites
tripwire 139 Posted April 17, 2013 Share Posted April 17, 2013 The following shows the capacitors (12pF) used by the Fraunchpad. I will probably end up re-soldering the crystal. 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. Avalon 1 Quote Link to post Share on other sites
Avalon 5 Posted April 17, 2013 Author Share Posted April 17, 2013 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 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.