PDA

View Full Version : Unsolved PASM waitpeq to measure the period of a frequency



StefanL38
10-13-2011, 09:35 AM
Hi,

I would like to know if the following code is measuring the period of a frequency with maximum possible precision.



mov _InputStateM, #0 'load BitPattern ZERO
WaitIRPinLow waitpeq _InputStateM, _IR_Recv_Pin2 'wait until specified bit "_IR_Recv_Pin" is ZERO
'which means pulsetrain starts
mov _FirstPulse, cnt 'take snapshot of free running systemcounter

mov _InputStateM, #8 'load bitpattern that should be matched
WaitIRPinHigh waitpeq _InputStateM, _IR_Recv_Pin2 'wait until INA-registerbit specified in _IR_Recv_Pin2
'has the same state as in _InputStateM
mov _InputStateM, #0 'load BitPattern ZERO
WaitIRPinLow2 waitpeq _InputStateM, _IR_Recv_Pin2 'wait until specified bit "_IR_Recv_Pin" is ZERO

mov _SecondPulse, cnt 'take another snapshot of free running systemcounter

mov _Period, _SecondPulse #calculate difference of systemcounter-snapshots
sub _Period, _FirstPulse 'calculate clockticks of pulsedistance (=carrier-frequency)

I assume if the frequency is not near the maximum that could be measured this way.
The cog is stopped at the waitpeq-cmd until the specified bit matches the specified value.
If it does match - the time it takes to execute the command

move, firstpulse , cnt

is the same as with

move, secondpulse, cnt

so that after calculating the period-time in clockticks with


mov _Period, _SecondPulse #calculate difference of systemcounter-snapshots
sub _Period, _FirstPulse 'calculate clockticks of pulsedistance (=carrier-


the period-time of the pulse is EXACTLY within the precision of clockticks (=12,5 nanoseconds at 80 MHz)?

If this is not exact- is there another way to get in measured with a resolution of one (or maybe 4 clockticks)?

best regards

Stefan

Bean
10-13-2011, 02:00 PM
Stefan,
Here is a frequency counter I wrote in PropBasic. It is well commented and should help.



' Frequency counter (0.5 Hz to 40 MHz)
' Counts frequency on P0, sends ASCII to PC at 115200 Baud
' 1.0 Second gate time (gate time will be longer if frequency is < 2 Hz)
'
DEVICE P8X32A, XTAL1, PLL16X
XIN 5_000_000

BAUD CON "T115200" ' Baud rate for PC communications

Signal PIN 0 INPUT ' Input pin for signal
TX PIN 30 HIGH ' Output pin for PC communications

cntStart VAR LONG ' "cnt" value at start of measurement
cntTime VAR LONG ' elapsed "cnt" clocks
sigCnt VAR LONG ' count of how many input pulses have been received
temp VAR LONG ' loop counter
digit VAR LONG ' current digit
digitSum VAR LONG ' Used for leading zero removal
ascii HUB STRING (20) ' Holds ascii representation of frequency


PROGRAM Start ' Start program at label "Start:"

Start:
COUNTERA 80, 0, 0, 1, 0 ' Count positive edges on pin 0
DO
' Wait for a signal pulse to syncronize to the system counter
WAITPNE Signal, Signal
WAITPEQ Signal, Signal
phsa = 0
cntStart = cnt - 4

' Count input pulses until 1.0 seconds have elapsed
DO
WAITPNE Signal, Signal
WAITPEQ Signal, Signal
sigCnt = phsa
cntTime = cnt - cntStart
LOOP UNTIL cntTime > 80_000_000 ' 1.0 Second gate time
cntTime = cntTime - 4 ' To account for "sigCnt = phsa" instruction

' Calculate frequency if >= 0.5 Hz
IF cntTime <= 160_000_000 THEN

' Since cntTime is in 80MHz units, the frequency is sigCnt / (cntTime / 80_000_000) = Hertz
' Rearranged this can be written as (sigCnt * 80_000_000) / cntTime = Hertz
'
' We want the result in milliHertz (1/1000 of a hertz) so we need to use:
' (sigCnt * 80_000_000_000) / cntTime = milliHertz
'
' Okay, now we have a problem, 80_000_000_000 cannot even be represented in 32 bits. Hmmm
' What if we calculate the answer one digit at a time...
'
' The leftmost digit is 10 MegaHertz and that digit can be calculated as:
' (sigCnt * 8) / cntTime = x0 MegaHertz. This we can do easily.
'
' Now the "trick" is how do we get the next digit ?
' We take the remainder from the division, multiply it by 10 and divide again.
' by repeating this process of taking the remainder and multipling by 10 we
' can get as many digits as we need until we run out of precision.
'
digitSum = 0 ' Sum of all digits so far. Used to create replace leading zeros with spaces
ascii = ""
sigCnt = sigCnt * 8 ' Scale signal count to get MegaHertz digit

FOR temp = 0 TO 13 ' 7 digits + decimal point + 3 digits = 11 digits

digit = sigCnt / cntTime ' Calculate this digit of result
sigCnt = __remainder ' Keep remainder for next digit

' Scale signal count for next digit
__temp1 = sigCnt * 2 ' sigCnt = sigCnt * 10 using powers of two
sigCnt = sigCnt * 8
sigCnt = sigCnt + __temp1


INC digitSum, digit ' Add this digit's value to sum
digit = digit + "0" ' Convert digit to an ascii digit


' If this is a leading zero, make it a space
IF temp < 9 AND ' Only use leading spaces for digits higher than the units digit
digitSum = 0 THEN ' If the sum is zero, then we have only had "0" digits so far
digit = " " ' so use a space instead of a "0" for this digit.
ENDIF

WRBYTE ascii(temp), digit ' Put digit into the result string

' Insert a comma if needed
IF temp = 1 OR
temp = 5 THEN
INC temp
IF digitSum = 0 THEN
WRBYTE ascii(temp), " "
ELSE
WRBYTE ascii(temp), ","
ENDIF
ENDIF

' Insert decimal point at proper place
IF temp = 9 THEN ' If we just processed the units digit,
INC temp ' move pointer to the next character in the result string
WRBYTE ascii(temp), "." ' and make it a decimal point
ENDIF

NEXT ' Process all digits

WRBYTE ascii(14), " ", "H", "z", 13, 0

ELSE
ascii = "Too low (< 0.5Hz)"
ascii = ascii + 13
ENDIF

SEROUT TX, BAUD, ascii ' Send frequency to terminal

LOOP ' Repeat forever
END



Bean

pgbpsu
10-13-2011, 02:32 PM
Hi Stefan-

Are you sure you are trying to measure the period? Period of a frequency is 1/frequency. From the comments in your code it seems like you want to measure the time between two waveforms or pulse trains. Measuring frequency can be done with the counters. I'm pretty sure there's an example in the AN001 App Note. But if my suspicion is correct, that won't help you. Are you timing the arrival of consecutive pulse trains, or simply measuring the period of a consecutive pulses?

I think the solutions are very different- the latter being much easier.

Peter

Mark_T
10-13-2011, 06:43 PM
Hi,

I would like to know if the following code is measuring the period of a frequency with maximum possible precision.



mov _InputStateM, #0 'load BitPattern ZERO
WaitIRPinLow waitpeq _InputStateM, _IR_Recv_Pin2 'wait until specified bit "_IR_Recv_Pin" is ZERO
'which means pulsetrain starts
mov _FirstPulse, cnt 'take snapshot of free running systemcounter

mov _InputStateM, #8 'load bitpattern that should be matched
WaitIRPinHigh waitpeq _InputStateM, _IR_Recv_Pin2 'wait until INA-registerbit specified in _IR_Recv_Pin2
'has the same state as in _InputStateM
mov _InputStateM, #0 'load BitPattern ZERO
WaitIRPinLow2 waitpeq _InputStateM, _IR_Recv_Pin2 'wait until specified bit "_IR_Recv_Pin" is ZERO

mov _SecondPulse, cnt 'take another snapshot of free running systemcounter

mov _Period, _SecondPulse #calculate difference of systemcounter-snapshots
sub _Period, _FirstPulse 'calculate clockticks of pulsedistance (=carrier-frequency)

I assume if the frequency is not near the maximum that could be measured this way.
The cog is stopped at the waitpeq-cmd until the specified bit matches the specified value.
If it does match - the time it takes to execute the command

move, firstpulse , cnt

is the same as with

move, secondpulse, cnt

so that after calculating the period-time in clockticks with


mov _Period, _SecondPulse #calculate difference of systemcounter-snapshots
sub _Period, _FirstPulse 'calculate clockticks of pulsedistance (=carrier-
the period-time of the pulse is EXACTLY within the precision of clockticks (=12,5 nanoseconds at 80 MHz)?

If this is not exact- is there another way to get in measured with a resolution of one (or maybe 4 clockticks)?

best regards

Stefan

I think one of the things you are asking is "what is the resolution/accuracy of waitpeq/waitpne" - yes its 1 system clock (12.5ns if 80MHz).

And the other thing "is this the most accurate way to measure frequency?" - to which the answer is a resounding NO....

The accurate way is to measure the time for _many_ periods and divide this by the number of periods timed. So if measuring 100kHz the above way the resolution of 12.5ns out of a period of 10us is 0.125%. Measuring 100,000 periods gives a precision of 0.00000125% (beyond the accuracy of your crystal!).