Shop OBEX P1 Docs P2 Docs Learn Events
measuring microseconds — Parallax Forums

measuring microseconds

kenkenkenken Posts: 13
edited 2009-10-06 18:40 in Propeller 1
I am trying to make a precise and synchronous stepper motor control for 2 motors. But I just can't figure out, how my ON an OFF pulse can be precise over a long time.
A cog handles the pulse routine (simplified):
repeat
   ON
   wait for e.g. 200 microseconds 
   OFF
   wait for e.g. 200 microseconds 
   the routine does something else and loses important microseconds 




so I tried to constantly measure the time of the loop and adjust (shorten) the period in which the OFF phase is actually waiting ... (simplified)
repeat
   ON
   wait for e.g. 200 microseconds 
   OFF
   wait for e.g. 200 microseconds - correction
   measure the loop and calculate correction 




But how can I reliably measure and compare these short periods?


* First I tried it with saving the clockcounter:
time:=cnt


and compare it later with the new value of cnt
realspeed := cnt - time


But it didn't manage to handle the fact that the counter is 32-bit unsigned and also cycling. So measuring continuously was not possible.



* Then I tried to use a seperate cog as counter but I only managed to get a resolution of 40 microseconds. below that the counter just refused..
PUB Main 
       musecond~    
       result := cnt
       repeat                  
           waitcnt( result += 3200 )    'every 40 mus
           musecond += 40
           if musecond == 2_000_000_000
               musecond := 0   
                                                          
  Pub getMusecond  
       return musecond



For this second approach I would need a reolution of 5 microseconds.


Can anybody please help me?

Comments

  • Cluso99Cluso99 Posts: 18,069
    edited 2009-10-06 09:04
    You will need to do that resolution in pasm as there are at least 50+ pasm instructions at 50nS each (80MHz) for each spin instruction.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade, RetroBlade,·TwinBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: Micros eg Altair, and Terminals eg VT100 (Index) ZiCog (Z80) , MoCog (6809)
    · Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • kenkenkenken Posts: 13
    edited 2009-10-06 09:25
    Could you give me an example of how to measure the time of a loop in pasm and use the result in microseconds in spin afterwards? I honestly have no idea at all about it...
  • AleAle Posts: 2,363
    edited 2009-10-06 10:36
    kenken:

    Yu can use a second COG with a couple of waitpeq/waitpne for the output pins and report the difference (reading CNT before and after) and write this value back in a HUB variable.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Visit some of my articles at Propeller Wiki:
    MATH on the propeller propeller.wikispaces.com/MATH
    pPropQL: propeller.wikispaces.com/pPropQL
    pPropQL020: propeller.wikispaces.com/pPropQL020
    OMU for the pPropQL/020 propeller.wikispaces.com/OMU
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-10-06 10:53
    In a DAT section you will use the cnt. cnt is a free-running counter which increments each clock cycle. It is a 32bit unsigned counter, so it wraps about every 90 seconds. So with an 80MHz clock (5MHz xtal and PLLx16) each clock count is 12.5nS. Most pasm instructions take 4 clocks (see the instruction table).

    You will need to work through the examples in the manual to get some ideas for starters.

    Your pasm code will be something like... (lots missing and probably not the simplest but will give you an idea)
    
    
    VAR 
      long  flag
      long  c_begin
      long  c_end
     
    PUB start
      cognew(@entry, @flag)
      flag := 1
      repeat while flag == 1
      ....now do something with c_begin and c_end to convert to current time.
     
     
    DAT
          org   $0
    entry
          mov      flagptr,par   'set pointers to hub memory flag
          mov      hubptr1,par
          add      hubptr1,#4    '.......................... c_begin
          mov      hubptr2,par
          add      hubptr2,#8    '.......................... c_end
     
    loop  waitpeq  ....   'wait for your pin to be equal
          mov      countbegin,cnt
          waitpne  ....   'wait for your pin to change
          mov      countend,cnt
          wrlong   countbegin,hubptr1
          wrlong   countend,hubptr2
          wrlong   zero,flagptr
          jmp      #loop
     
    zero       long 0 
    flagptr    long 0
    hubptr1    long 0
    hubptr2    long 0
    countbegin long 0
    countend   long 0
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade, RetroBlade,·TwinBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: Micros eg Altair, and Terminals eg VT100 (Index) ZiCog (Z80) , MoCog (6809)
    · Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • kenkenkenken Posts: 13
    edited 2009-10-06 11:19
    Thank you so much for your help. I will try this out.
    Hopefully I will understand it [noparse];)[/noparse]
  • LawsonLawson Posts: 870
    edited 2009-10-06 16:36
    to paraphase the initial example you gave. But with cycle accurate timing. (maximum pulse rate is limited by spin's overhead)

    dira[noparse][[/noparse] 0 ] := 1    'set a pin as an output
    200usec := CLKFREQ*2/10000    '200 microseconds at the current clock speed
    mark := cnt + 200usec    'record some initial CNT value, and project it into the future a bit.
    repeat
      waitcnt(mark)        'wait for mark to arrive
      outa[noparse][[/noparse] 0 ] := 1        'set our output pin
      mark += 200usec    'project mark 200 microseconds further into the future
      waitcnt(mark)        'wait for mark to arrive
      outa[noparse][[/noparse] 0 ] := 0        'clear our output pin, note that the statments to set and clear a pin are as similar as possable
      mark += 200usec    'project mark 200 microseconds into the future 
                            'loop
    



    The above code should cycle pin zero with a period of exactly 400 micro seconds, and a duty cycle of almost exactly 50%. This should be accurate down to one clock cycle independent of clock frequency. (with too slow a clock this code will hang) This code has exactly the same code after the WAITCNT to set or clear pin zero which effectively hides the overhead of spin. Also, computing the timing targets outside of a WAITCNT allows any overhead in the WAITCNT itself to be hidden.

    Lawson

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Lunch cures all problems! have you had lunch?
  • LawsonLawson Posts: 870
    edited 2009-10-06 16:45
    kenken said...

    * First I tried it with saving the clockcounter:
    time:=cnt
    


    and compare it later with the new value of cnt
    realspeed := cnt - time
    


    But it didn't manage to handle the fact that the counter is 32-bit unsigned and also cycling. So measuring continuously was not possible.

    I've used that exact code and it works just fine. The rollover of CNT is handled because all math in spin is 32-bit and based on two's compliment so sign can be ignored much of the time on real hardware with limited precision.

    Lawson

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Lunch cures all problems! have you had lunch?
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-10-06 18:40
    In the manual is a descritpion how to set the waitcnt-command in a way that a loop can
    vary in its execution-time and the waitcnt catches up the differences so that you get a rock-solid
    frequency-output.

    If you want to drive two steppermotors at different speeds but still absolutly synchron
    you can use the bresenham-algorithm. This algorythm is fast because this algorithm just
    needs addition and substraction to do all the math for calculate pulse-times

    see attached file

    best regards

    Stefan
Sign In or Register to comment.