Shop OBEX P1 Docs P2 Docs Learn Events
time mesure — Parallax Forums

time mesure

stefstef Posts: 173
edited 2010-08-16 16:02 in Propeller 1
Hi everybody

Anyone has an idea on how to mesure simple the time between two prop input comming high?
I'm trying to do this in a project but I have no clue on how to start it.

I'm controling a machine that is triggering 5 inputs of the propeller. I need to menure the time as accurate as possible between different inputs comming high.

any ideas?

Stefan

Comments

  • John AbshierJohn Abshier Posts: 1,116
    edited 2010-08-15 14:59
    Not much info in your post. If the times are long enough you might be able to use Spin.
    waitpeq(state1, mask, 0)
    t1 := cnt
    waitpeq(state2, mask, 0)
    t2 := cnt
    time := t2 - t1
    If Spin is not fast enough, there are equivalent PASM commands. Counters are also a possibility.

    John Abshier
  • stefstef Posts: 173
    edited 2010-08-16 14:06
    Hi

    Sorry i did not gave a lot info. This is what i know. The 5 inputs can become high at any time . If one becomes high i need the time between that and the 4 others that become high after the first . if the second is slower than 0,5 sec after the first i can discard the time and start over. The second input becoms then the fist And I need to look at the time between the next input comming high. so times are between 0,01 and 0,5 sec to mesure.If all inputs becom high faster then 0,5 sec after the first i need the 4 times. Action is then taken depending the times.

    Hope this is stil doable in spin.?

    stef
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2010-08-16 14:27
    Something along these lines?

    (untested)
    CON
    
      mask = %11111                 ' mask of pins to monitor
    
    PUB GetTime | i, start, time[5], waitmask, maxwait
    
      maxwait := clkfreq / 2        ' don't allow more than 0.5 seconds
    
      REPEAT
        waitmask := mask
        waitpne(0, mask, 0)         ' wait for one to go high
        start := cnt                ' start clock
        waitmask &= !INA            ' ignore high pin for next wait
        
        REPEAT i FROM 0 TO 4
          waitpne(0, waitmask, 0)   ' wait for next IO to go high
          IF (cnt - start => maxwait)
            QUIT
          time[i] := cnt            ' get time it went high
          waitmask &= !INA          ' ignore high pin for next wait
    
    This will put a start time and each of the inputs high time into an array. You can then subtract that time minus the start to get the difference. If any of the high inputs come more than half a second after the first one, it just restarts the loop. BEWARE: But if the second input never comes, it will just hang in the waitpne. You will have to add some code to watchdog it better if this may happen.

    The code also assumes the high inputs will stay high long enough for the INA to be sampled a couple instructions after the waitpne.

    I think this should be able to detect 10ms timing, but if you add too much more code it won't. You could do the same thing in PASM fairly easily and get much higher resolution (like 500 times more) and speed. I am bored today, you want a stab at that too?
  • stefstef Posts: 173
    edited 2010-08-16 14:41
    Thanks Bobb for the spin example. I will look into it tomorrow. It is here olmost 2 AM an I need some sleep.

    Do you know also PASM? I never tried it. Untill now I did everything in spin.
    Can you also provide me with an little example of PASM. I still need to learn but then I'm pointed in the right direction.

    does it also influance the spin example if I run other code in other cog's?

    stef
  • Mike GreenMike Green Posts: 23,101
    edited 2010-08-16 14:44
    Whether you can do this in Spin or you need assembly depends on the resolution you need. What you're doing is to start initially with all 5 pins low and wait using WAITPNE for some pin combination different from the "current" one. You save the value of CNT and save the "current" pin state in a buffer and, if not all pins are high and if some maximum timeout hasn't occurred, you go back and wait again. Once all pins go high or some maximum time has passed, you can go back and analyze the saved information to see which pins change when. With Spin, this much work would take on the order of maybe 10us to 20us and that would be your resolution. With assembly, it would be maybe 250ns to 500ns.

    In Spin, you're talking about something like:
    currentPinState := index := 0
    startTime := CNT
    REPEAT
       WAITPNE(currentPinState, pinMask,0)   ' Wait for the next pin change
       changeTime[index] := relativeTime := CNT - startTime   ' Keep relative time in 12.5ns units
       pinBuffer[index++] := currentPinState := INA & pinMask   ' Keep pin changes
    UNTIL currentPinState == pinMask OR relativeTime > timeLimit   ' All pins high or timeout
    
    Note: This assumes that the pins will only go from low to high while this loop is going. That limits the number of entries in the arrays to 32 at most.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2010-08-16 16:02
    Here is a slightly better/faster version of my SPIN, and below it is it transposed into PASM:
    CON
    
      mask = %11111                 ' mask of pins to monitor
    
    VAR
    
      LONG  start
      LONG  time[4]
    
    PUB GetTime | i, waitmask, maxwait
    '' SPIN version of finding the timing between inputs
    
      maxwait := clkfreq / 2        ' don't allow more than 0.5 seconds
    
      REPEAT     
        waitpne(0, waitmask := mask, 0)                     ' wait for one to go high
        start := cnt                                        ' start clock    
        
        REPEAT i FROM 0 TO 3
          waitpne(0, waitmask &= !INA, 0)                   ' wait for next IO to go high
          time[i] := cnt                                    ' get time it went high          
          IF (time[i] - start => maxwait)                   ' measure take it took to get here from start
            QUIT                                            ' quit this loop if it takes too long
    
        '' code here to get diffence between start and other inputs' times
    
    PUB StartPASMGetTime
    '' start PASM version of finding the timing between inputs
    
      pmaxwait := clkfreq / 2        ' don't allow more than 0.5 seconds
      cognew(@entry, @start)
    
    DAT
                            ORG
    
    entry                   MOV     writeAddr, PAR          ' where to write timing values
                            MOV     idx, #4                 ' get 4 additional inputs
                            MOV     pwaitmask, pmask        ' pins to watch
                            WAITPNE state, pwaitmask        ' wait for first high input
                            MOV     pstart, cnt             ' get start time
                            WRLONG  pstart, writeAddr       ' write time to variable block
                            ADD     writeAddr, #4           ' move to next long
                            NEG     pstart, pstart          ' get negative (used in place of SUB later on)
    
    loop                    ANDN    pwaitmask, INA          ' remove high pin from mask
                            WAITPNE state, pwaitmask        ' wait for next high input
                            MOV     tmp, cnt                ' get time
                            WRLONG  tmp, writeAddr          ' write time to variable block
                           'ADDS    tmp, pstart             ' determine difference of start and now
                           'WRLONG  tmp, writeAddr          ' write difference in time to variable block
                            ADD     writeAddr, #4           ' move to next long
                                             
                            '' watchdog                                                                    
                            MOV     waitlen, cnt            ' get now
                            ADDS    waitlen, pstart         ' difference of start and now
                            CMP     waitlen, pmaxwait WC    ' if below maxwait...do another loop
                            
                  IF_B      DJNZ    idx, #loop              ' do it again!  
                                               
                            JMP     #entry                  ' do it all over again                     
    
    pmaxwait                LONG    0
    state                   LONG    0                       ' set to -1 if you want to measure low timing (and swap PNE with PEQ)                                                   
    pmask                   LONG    mask
    idx                     RES
    pstart                  RES       
    pwaitmask               RES
    waitlen                 RES
    writeAddr               RES
    tmp                     RES
    
                            FIT
    
    With this PASM code, worst case scenerio you end up with 687.5ns resolution, 500ns best case (depending on where the hub is). This could be streamlined (you could remove the wrlong until after all the times are received). Almost half the instructions in the lower loop is the watchdog. But about a third of the time could be wasted waiting for the hub to come around.

    The PASM version assumes each pin will be held high for at least 590.5ns.

    You may also want a line added to the PASM to allow you to know when the time array has been altered.
Sign In or Register to comment.