Time between edges

I try to get the time between variable edges of a square wave.
The minimum time are 240us, the maximum 1_020us.
I only need to detect value 250us or 1_000us, it is "Biphase marque"


I try in spin
 ctra := %01110<<26 + pin       'ctra for neg edge detection
  frqa := 1
  ctrb := %01000<<26 + pin       'ctrb for pulstime high 
  frqb := 1

...

  repeat i from 0 to 80                        'main loop detection
      phsa := phsb := 0                        'clr edge and pulstime

           repeat until (phsa OR phsb)       'wait for neg edge OR pos edge

      pulses[i] := (phsb+phsa)              ' I expect to get the time between edges => A can be 0; or b can be 0. So sum would be edge time


Is this to simple ?
I do not get the expected timings, compare to my scope

Comments

  • yisiguroyisiguro Posts: 49
    edited 2020-04-28 - 02:31:44
    The edge detector mode of cog counter counts only number of edges.
    So, in your code, PHSA is always 0, and PHSB is almost same some small value each time.

    If you don't need accuracy and quickness, below might work:
      ctra := %01110<<26 + pin
      frqa := 1
      ctrb := %01000<<26 + pin
      frqb := 1
    
    ...
    
      repeat i from 0 to 80
        phsa := phsb := 0
    
        repeat until phsa       'wait for next edge
    
        pulses[i] := phsb
        ctra ^= |<28                   ' toggle counter mode between neg edge detection and pos edge detection
        ctrb ^= |<28                   ' toggle counter mode between pulsetime high and pulsetime low
    

    Also you can use WAITPxx command, instead of REPEAT UNITIL command:
      ctrb := %01000<<26 + pin
      frqb := 1
    
    ...
    
      WAITPEQ( 0, |<pin, 0 ) ' to assume ina[pin] to be  low
      repeat i from 0 to 80
        prevstat := ina & |<pin                ' prevstat is LONG variable
        phsb := 0
    
        WAITPNE( prevstat, |<pin, 0 )       'wait for next edge
    
        pulses[i] := phsb
        ctrb ^= |<28                   ' toggle counter mode between pulsetime high and pulsetime low
    

    And also you can use system counter CNT to measure time, instead of cog-counters:
      WAITPEQ( 0, |<pin, 0 ) ' to assume ina[pin] to be  low
      repeat i from 0 to 80
        prevstat := ina & |<pin                ' prevstat is LONG variable
        prevcnt := CNT                           ' prevcnt is LONG variable
        
        WAITPNE( prevstat, |<pin, 0 )       'wait for next edge
    
        pulses[i] := CNT - prevcnt
    

    (Sorry I did not test these yet but I'll later.)
  • JonnyMacJonnyMac Posts: 6,661
    edited 2020-04-27 - 16:29:16
    Can you go leading edge leading edge? If yes, this will give you the period of your square wave.
    pub edge2edge : ticks
    
      waitpne(EDGE_MASK, EDGE_MASK, 0)                              ' wait for gap
      waitpeq(EDGE_MASK, EDGE_MASK, 0)                              ' look for edge
      ticks := cnt                                                  ' start timing
      waitpne(EDGE_MASK, EDGE_MASK, 0) 
      waitpeq(EDGE_MASK, EDGE_MASK, 0) 
      ticks := cnt - ticks                                          ' end timing
    
    It's best to use a constant for your pin mask. Spin already has some overhead and you don't want to add any more by creating a mask in place.

    If you just want the next complete half cycle, regardless of phase, this works (I tested both methods with an oscillator running using CTRA).
    pub half_cycle_ticks : ticks | pinstate
    
      pinstate := ina & EDGE_MASK                                   ' get current state
      waitpne(pinstate, EDGE_MASK, 0)                               ' wait for change
      ticks := cnt
      waitpeq(pinstate, EDGE_MASK, 0)                               ' wait for initial state   
      ticks := cnt - ticks
    
    Warning: If the pin doesn't change, these methods will block your program. What you could do is launch it into its own temporary cog which would allow your foreground code to timeout the measurement.
  • Thank you both.

    I don't have time today to test this part.
    I wil test it tomorrow


    Daniel
  • For Biphase mark decoding @ 250us (Pal SMPTE LTC)


    I got in a dedicated cog, detecting all the edges and toggle pin:
    EDGE_MASK  =(|< Pin_14_det)
    EDGE_MASK2 =(|< Pin_0_in)
    
     Repeat
        
            !outa[Pin_14_det]              'edge pulse for mask
            waitcnt(50*us +cnt)
            !outa[Pin_14_det]
    
            waitpne(pinstate, EDGE_MASK2, 0)  ' look for edge do not match
            pinstate :=ina[Pin_0_in]'
    

    And other cog, analyzing @ 6/8 time, of the next pulse:
      Repeat i from 0 to 80
           waitpeq(EDGE_MASK, EDGE_MASK, 0)
           phsa := 0
           !outa[Pin_15_edge]             'Just for scope monitoring
           waitcnt(380*us + cnt)
           !outa[Pin_15_edge]
           pulses[i] := (phsa/2)
    


    The result if I have 2 pulses, we got a 1, if we have 1 pulse we got 0
    Proof of concept is working fine.

    Now I go try in pasm
Sign In or Register to comment.