Shop OBEX P1 Docs P2 Docs Learn Events
PASM waitpeq to measure the period of a frequency — Parallax Forums

PASM waitpeq to measure the period of a frequency

StefanL38StefanL38 Posts: 2,292
edited 2011-10-13 11:43 in Propeller 1
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

Comments

  • BeanBean Posts: 8,129
    edited 2011-10-13 07:00
    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
  • pgbpsupgbpsu Posts: 460
    edited 2011-10-13 07:32
    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_TMark_T Posts: 1,981
    edited 2011-10-13 11:43
    StefanL38 wrote: »
    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!).
Sign In or Register to comment.