Jump to content
43oh

Measuring time in clocks between edges


Recommended Posts

Hello,

 

I want to measure the time between the both edges of clock signal.

The Purpose of the project is to build a shift light with the MSP430 and the TLC5940 LED driver.

The RPM signal to the tachometer comes in a 12V HIGH/LOW signal and the higher the RPM is the higher the frequency of the signal is. Instead of using a frequency counter I measure the time the signal is on HIGH.

Capturing the signal with the Open Logic Sniffer gave me a straight and continuous signal.

 

2 MSP430s are used. One to generate the signal and the other to measure it.

 

MSP430 #1 P1.0 -> MSP430 #2 P2.1

 

This is the code for generating the clock:

void main(void)
{
WDTCTL = WDTPW + WDTHOLD;

DCOCTL = CALDCO_16MHZ;
BCSCTL1 = CALBC1_16MHZ;

P1DIR = BIT0;
P1OUT = 0x00;

TACTL = TASSEL_2 | MC_1 | ID_0;
CCR0 = 8000;
CCTL0 = CCIE;

_enable_interrupts();

_bis_SR_register(LPM0 | GIE);
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
P1OUT ^= BIT0;                            // Toggle P1.0
}

 

This is the code for measuring it:

void main()
{
   /* Clock Setup */
   WDTCTL = WDTPW + WDTHOLD; // Stop WDT

   // Set Clock Frequency to 16Mhz
   BCSCTL1 = CALBC1_16MHZ;
   DCOCTL = CALDCO_16MHZ;

P2SEL = BIT1;
P1DIR = 0x00;

TA1CTL = TASSEL_2 + MC_2;
TA1CCTL1 = CM_3 | SCS | CCIS_0 | CAP | CCIE;
_enable_interrupts();
for(;
	;
}

#pragma vector=TIMER1_A1_VECTOR
__interrupt void TimerA1(void)
{
timer = TA1CCR1;
TA1CTL |= TACLR;
TA1CCTL1 &= ~(COV | CCIFG);
}

(I even tried to set the check to positive edge and in the ISR set the check to negative edge so its only measuring the HIGH signal time.)

 

Sometimes I get values around CCR0 (8048, 8079, ..) but mostly its trash (0, 33152, 5000, 6915, ...).

 

Whats wrong?

 

Thank you

Link to post
Share on other sites

Since I have been working in assembly recently, it makes sense

 

lets say input signal is on pin 1.3

*interrupt vector (low to high transition)*
	push		R10				;save R10 to the stack
	mov.w	#0x00,	R10		;set R10 to 0

LoopStart 							;Label to jump to for loop restart
	inc.w		R10				;add 1 to R10 word length (max 65535 counts)
	bit.b		#0x08,	&P1In	;test P1In against bit mask 00001000
	jc		LoopStart 			;Jump to "LoopStart" if it is still high

	mov.w	R10, TimeOut		;Move the register to your variable
	pop		R10				;Restore value to R10

 

the loop will take

 

inc.w - 1 cycle

bit.b - 4 cycles

jc - 2 cycles

 

7 cycles per loop

 

using your 16MHZ setting for the CPU that works out to a resolution of just under .0004375 ms per loop

 

5000 RPM is .2 ms per RPM i don't know how many times the signal pulses per RPM but that is 460 loops per RPM.

 

i hope this helps if you want to use the Timer circuitry to get finer resolution i can piddle with code for that tomorrow, but this might be easier for you

 

in C is would be something like

 

*interrupt vector - low to high transition*
int TimeOut = 0;
while (P1In & #0x08){
TimeOut++;
}

 

but Im not in front of my computer so i can't see what assembly that will compile into to predict its loop time

Link to post
Share on other sites

- Don't reset the capture register - defeats the purpose of using it

- No need to reset interrupt flag - using an ISR does that (in most cases)

- Save an array of captures to see a trend

 

unsigned cn = 0;   // Timer capture number
unsigned ca[16];  // Timer capture array

#pragma vector=TIMER1_A1_VECTOR
__interrupt void TimerA1(void)
{
 static unsigned tl;  // Last timer capture
 const unsigned tc = TA1CCR1;  // Current timer capture
 const unsigned te = tc - tl;  // Elapsed time
 tl = tc;  // Update last timer capture
 ca[cn++ & 15] = te;  // Save captured time in array
}

Link to post
Share on other sites

Oh, forget code to read TAIV.

 

Overflow in handled properly by unsigned subtraction - it will wrap around.

 

__interrupt void TimerA1(void)
{
 static unsigned tl;  // Last timer capture
 volatile unsigned n = TA1IV;  // Read interrupt vector to reset interrupt flag
 const unsigned tc = TA1CCR1;  // Current timer capture
 const unsigned te = tc - tl;  // Elapsed time
 tl = tc;  // Update last timer capture
 ca[cn++ & 15] = te;  // Save captured time in array
}

Link to post
Share on other sites

You might take a look at the code for my RC car project. I used the timer to measure the length of a pulse coming back from an ultrasonic sensor. That code is based on this post on letsmakerobots. The code is written to pick up the signal on P2.1 as well.

 

//Timer1_A Capture
//P2.0 ends up triggering this timer
#pragma vector=TIMER1_A0_VECTOR
__interrupt void Timer1A0(void)
{
  if(up) //is this the rising edge?
  {
     measure_1=TA1CCR0;  // take first time measure
  }
  else //is this the falling edge?
  {
     measure_2=TA1CCR0; //take second time measure
     measure=(measure_2-measure_1)/58; // microseconds / 58 = centimeters
  }
  up=!up; //if this was the rising edge, the next one will be a falling edge, and vice-versa
  TA1CTL &= ~TAIFG; //clear timer A interrupt flag, so the chip knows we handled the interrupt
}

Link to post
Share on other sites

Here is tested code that uses a single G2553. Connect a jumper wire from P1.6 (timer A0 output) to P2.1 (timer A1 capture input)

 

The output is 400 cycles on and then 600 cycles off.

The ca[] array will have alternating values of 400 and 600. (run, halt, watch)

 

#include 

void main()
{
   WDTCTL = WDTPW | WDTHOLD;
   BCSCTL1 = CALBC1_16MHZ;
   DCOCTL = CALDCO_16MHZ;

   P1DIR = BIT6;
   P1SEL = BIT6;

   P2DIR = 0;
   P2SEL = BIT1;

   TA0CCR0 = 1000 - 1;
   TA0CCR1 = 400; 
   TA0CTL = TASSEL_2 | MC_1;
   TA0CCTL1 = OUTMOD_6;

   TA1CTL = TASSEL_2 | MC_2;
   TA1CCTL1 = CM_3 | SCS | CCIS_0 | CAP | CCIE;

   _enable_interrupts();

   for(;;
}

unsigned cn = 0;                        // Timer capture number
unsigned ca[16];                        // Timer capture array

#pragma vector=TIMER1_A1_VECTOR
__interrupt void TimerA1(void)
{
   static unsigned tl;                 // Last timer capture
   volatile unsigned n = TA1IV;        // Read interrupt vector to reset interrupt flag
   const unsigned tc = TA1CCR1;        // Current timer capture
   const unsigned te = tc - tl;        // Elapsed time
   tl = tc;                            // Update last timer capture
   ca[cn++ & 15] = te;                 // Save captured time in array
}

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...