Shop OBEX P1 Docs P2 Docs Learn Events
Using a global timer to time mutiple Events — Parallax Forums

Using a global timer to time mutiple Events

dermotdermot Posts: 26
edited 2012-06-06 20:02 in Propeller 1
Hi,

I want to have one central timer running and by doing calculations on this running timer I want to be able to time mutiple events (up to a max of 15 events). How can this be implemented most effectively using least resources. Accuracy or timer in hundreds of seconds is accurate enough. No event will be longer than 60seconds. Will I require a 3 seperate variable for each event to be timed??

Is starting a new cog for the timer and performing the following calculation for each event the best way to do it.

StartTime1:=Current Time
FinishTime1:=CurrentTime

FinishTime1-StartTime1:=Event1Time

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-06-05 14:32
    dermot wrote: »
    Hi,

    I want to have one central timer running and by doing calculations on this running timer I want to be able to time mutiple events (up to a max of 15 events). How can this be implemented most effectively using least resources. Accuracy or timer in hundreds of seconds is accurate enough. No event will be longer than 60seconds. Will I require a 3 seperate variable for each event to be timed??

    Is starting a new cog for the timer and performing the following calculation for each event the best way to do it.

    StartTime1:=Current Time
    FinishTime1:=CurrentTime

    FinishTime1-StartTime1:=Event1Time

    You'll need a variable for each start time and some some way to indicate the interval you wish to time.


    This is pretty much the way I do it.
      interval1 := [B]clkfreq[/B] / 4
      startTime1 := [B]cnt
    [/B] [B] repeat
    [/B]    if [B]cnt[/B] - startTime1 > interval1
          startTime1 += interval1 ' use this if you want somethink done [B]every[/B] quarter of a second
          ' do stuff when a quarter of a second if up
        ' do stuff all the time
    

    This take two variables per timer. You could use a constant as the interval if you check prefer.

    Make sure you make these variables longs.

    As I read your post again I see you might not want to check when a set time passes but how much time has passed.

    There's a trick to do this with one variable. I'll see if I can remember it.

    timer1 := -[B]cnt[/B] ' this is the trick part
      ' do stuff that takes time
      timer1 += [B]cnt
    [/B]
    

    I don't use this trick myself, I generally use two variables.

    startTime1 := [B]cnt
    [/B]  'do stuff that takes time
      timeInterval1 := [B]cnt[/B] - startTime1
    

    I think I do it this way out of habit.

    I only recently saw Phil do the "-cnt" trick but I haven't started using it in my code yet.
  • jmgjmg Posts: 15,183
    edited 2012-06-05 14:51
    dermot wrote: »
    Accuracy or timer in hundreds of seconds is accurate enough.

    I guess that was meant to be hundredths of a second (10ms) ?
    dermot wrote: »
    No event will be longer than 60seconds.

    Will I require a 3 seperate variable for each event to be timed??

    Is starting a new cog for the timer and performing the following calculation for each event the best way to do it.

    StartTime1:=Current Time
    FinishTime1:=CurrentTime

    FinishTime1-StartTime1:=Event1Time

    ( I have assumed "each event to be timed" means capturing external pin changes, if you want to create time ticks, that is a different approach. )

    Depends if the events are completely independent, and your desired precision. PASM + many cogs would likely get under 1us.

    At 10ms, you may be able to poll all inputs in a tight loop, looking for a change, and then store at that location.

    You will want to slow the Prop down a little, to avoid any chance of two overflows in your maximum time (+ margin).
    eg 1/(80e6/2^32) = 53.6870912 seconds.

    If two inputs can change inside one sample, then your extract-code needs to be able to find multiple changes.

    What is the maximum edge rate ?
    If it is slow, another solution would be to have one Cog doing a fast-poll and store of Time and Change tags only, into a FIFO, and then another cog can read out from there, at a slower average speed.
    This would give you the best precisions, over many sampled channels.
  • JonnyMacJonnyMac Posts: 9,195
    edited 2012-06-05 16:58
    If you can spare a cog it would be easy to create a 1ms resolution timer that would get you past the limit of the cnt register. Without monkey motion, i.e., just using a 31-bit value your timer(s) can run up to 2,147,483 seconds (35,791 minutes; 596 hours -- you get the point).
  • Mike GMike G Posts: 2,702
    edited 2012-06-05 17:17
    I second JonnyMac's 1ms timer. You could place the 1ms timer in an object along with an array of 15 variables exposed by getters and setters. A SetMark(id) method could mark the current timer value. A GetDelta(id) method could return the difference between the marked time and current timer value.
  • kwinnkwinn Posts: 8,697
    edited 2012-06-05 20:04
    Or you could use the variables as counters in an object and use start_timer, stop_timer, get_time.
  • dermotdermot Posts: 26
    edited 2012-06-06 00:47
    I wish to both check when a set time has passed and check how much time has passed.

    Timers will be triggered by serial data coming from external sensors. Up to 15 may run simultaneously.

    10ms resolution is accurate enough for me.

    Will I need 2 cogs for all this? One cog for timer (see code below) and another cog for taking all the time references.
    repeat
     waitcnt(clkfreq/100+cnt)       'Hold 10ms
     timer:=timer+1                    'Add one to timer
    

    If I set up a 31 bit timer will do that do the trick for just using one cog?? How do you set this up?
  • Mag748Mag748 Posts: 269
    edited 2012-06-06 06:51
    If the below statement:
    startTime1 += interval1
    

    results in startTime1 being the value 4294967295, then it appears to me that the following statement:
    if cnt - startTime1 > interval1
    

    will never be true. This would cause the timer to stop functioning.
    How come this is not a worry?

    Unless these numbers are signed, in which case the maximum value for interval1 cannot exceed half of the value of a long, 2147483647?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-06-06 07:13
    Mag748 wrote: »
    Unless these numbers are signed, in which case the maximum value for interval1 cannot exceed half of the value of a long, 2147483647?

    They are signed. I think your right about the 31-bit limit so this will only work for intervals up to 26.84 seconds @80MHz.
  • jmgjmg Posts: 15,183
    edited 2012-06-06 13:51
    dermot wrote: »
    Timers will be triggered by serial data coming from external sensors. Up to 15 may run simultaneously.
    10ms resolution is accurate enough for me.

    So this is some custom Sensor protocol, that encodes values in a very low baud rate way ?
    dermot wrote: »
    Will I need 2 cogs for all this? One cog for timer (see code below) and another cog for taking all the time references.
    repeat
     waitcnt(clkfreq/100+cnt)       'Hold 10ms
     timer:=timer+1                    'Add one to timer
    

    The waitcnt 'snaps' to the next 10ms, so if more code is added in the loop, _provided_ it never takes more than 10ms you still keep your timebase.
    Fastest additional steps, as pseudo code, will be a simple write-on-change
     PinDiff = (MaskedPins XOR OldPins)
     IF  PinDiff <> 0 THEN 
       OldPins = MaskedPins
       StoreTime[WrPtr] = timer
       StoreDiff[WrPtr] = PinDiff
       StoreWrPtr = WrPtr       // WrPtr is local, StoreWrPtr is a copy visible to another cog, so you can make a fifo 
       WrPtr = (WrPtr+1) MOD Size(StoreTime)  // post INC, circular buffer
       IF WrPtr = StoreRdPtr THEN
          // oops, write has over-flowed, too many edges for read to keep up
       ENDIF
     ENDIF
    

    and the other Cogs code can scan StoreTime, StoreDiff arrays, and StoreWrPtr which are all in main memory

    You may be able to decode more inside this loop, but if you have two cogs available, often keeping the tight stuff deterministic if a good idea.
    With simple code, you can easily decrease the sampling time, until it breaks, to get best resolution.

    ie 10ms is coarse, if you can run this at 1ms, why not do so ?

    Or code it in PASM, and I'd guess you would get close to 1us resolution. (just over 1 hour roll over)
  • kwinnkwinn Posts: 8,697
    edited 2012-06-06 20:02
    I'm not sure what you mean by " I wish to both check when a set time has passed and check how much time has passed.". Perhaps you could explain it with a diagram or example.

    I am certain that a single cog could easily handle 15 interval timers and an elapsed time counter with 1mS resolution. The cog would spend most of that time waiting for the 1mS to elapse. For 10 or 100mS resolution the cog would probably be waiting over 99.9% of the time.
Sign In or Register to comment.