Shop OBEX P1 Docs P2 Docs Learn Events
A bit of some code help - Time keeping - — Parallax Forums

A bit of some code help - Time keeping -

grasshoppergrasshopper Posts: 438
edited 2009-02-19 21:59 in Propeller 1
I am using the code below that I got from forums.
PUB Timer(In) | RightNow, ClockTicks
            
  RightNow~
  ClockTicks~   
  RightNow := cnt
   
  IF RightNow < In                       
      ClockTicks := ||($FFFFFFFF - RightNow + In)
     
  ELSE
      ClockTicks := || ( RightNow - In )
     
  result := ClockTicks / (clkfreq / 1_000)




I want to understand this code more and don't understand the following line of code.

ClockTicks := || ( $FFFFFFFF - RightNow + In ) 




Whats the "||" mean? The book states that its the absolute vale, but I am still confused.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Those who criticize our generation forget who raised it.

Post Edited (grasshopper) : 2/19/2009 3:53:59 PM GMT

Comments

  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-18 19:20
    It's absolute value. What it means is that if ( $FFFFFFFF - RightNow + In ) comes out negative, it is to be made positive. If it comes out positive, it is to be left that way.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • LeonLeon Posts: 7,620
    edited 2009-02-18 22:50
    0xFFFFFFFF is actually -1.

    Leon

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Amateur radio callsign: G1HSM
    Suzuki SV1000S motorcycle
  • JasonDorieJasonDorie Posts: 1,930
    edited 2009-02-19 08:23
    If you're trying to keep track of periods longer than 53 seconds on an 80MHz prop, you'll need to do extra work, since the 32-bit counter on the prop rolls over every 4.2 billion cycles (53.687 seconds at 80MHz).

    The code above just checks to see if a rollover has happened since the last time you checked, and if so, adjusts the math to produce the correct difference value.· Think of it this way· (assuming a 10 cycle rollover):

    --+-----+- 
    0123456789
    
    

    If your first measurement was '2', and now you're at '8', it's pretty obvious that the time passed is (8-2), or·6 clock cycles.· On the other hand, if the last time you measured was '8', but the clock rolls over after 9 and goes back to 0, and the 2nd measurement is '2', you have a rollover.· 2 - 8 is not the right answer.· The clock counted 9, then 0, 1, 2, for a total of 4 cycles.· The math in your code is actually computing the length of the two segments of time involved - One from 'LastTime' to $FFFFFFFF, and the other from zero to RightNow.

    It's also handling the problem that Spin doesn't appear to deal with unsigned numbers, which would make this much simpler.· When your clock goes from $7FFFFFFF to $80000000, only one cycle has passed, but to Spin, those two numbers are·2147483647, and -2147483648.· The funky bit with $FFFFFFFF takes care of that.

    So for your problem, you're trying to track periods of time longer than your 32 bit clock allows, so you need more than one counter.· If you can call an 'update' function more than once every 53 seconds, you're in business:

    long PreviousTime, CurrentTime, ElapsedTime, Seconds
     
    PUB Main
     
      Seconds := 0 'Actual seconds counter
      ElapsedTime := 0 'Fractional counter
      PreviousTime := CurrentTime := cnt    'intialize everything
     
      repeat
        UpdateSeconds
        waitcnt( 8_000_000 + cnt )  'update every 10th of a second
     
     
    PUB UpdateSeconds | Difference
      PreviousTime:= CurrentTime   'Copy the previous time count value
      CurrentTime := cnt  'Get the new time value
     
      if( CurrentTime > PreviousTime)
        Difference := ||(CurrentTime - PreviousTime)
      else
        Difference := ||(PreviousTime+ $FFFFFFFF - CurrentTime)
     
      ElapsedTime := ElapsedTime + Difference
      if( ElapsedTime => 80_000_000 )
        ElapsedTime -= 80_000_000
        Seconds++
     
    
    

    That code looks to see how many cycles have passed since you last called the function and adds that amount of time to 'ElapsedTime'.· If 'ElapsedTime' has accumulated a second or more, the Seconds value is incremented, and a single second worth of cycles (80 million) is subtracted from the 'ElapsedTime' value, leaving any fractions of a second that might be there intact.

    If you call this code at least once a second, it'll work just fine.· If you call it less often than that, you'll need to change the 'if' to a 'while' (while there's a second or more in 'ElapsedTime', increment seconds and subtract cycles).

    Does that make sense?

    Jason

    Post Edited (JasonDorie) : 2/19/2009 9:01:45 AM GMT
  • kuronekokuroneko Posts: 3,623
    edited 2009-02-19 08:35
    @grasshopper: If you have a spare pin you might as well chain CTRA and CTRB which gives you a 64bit counter.
  • Mike GreenMike Green Posts: 23,101
    edited 2009-02-19 16:10
    CTRB is available. What's absent in the Prop I is the 2nd set of 32 I/O pins and the associated registers (INB / OUTB / DIRB).

    If you can afford the I/O pin, chaining the two counters in a cog together gives you a "set and forget" timer.

    Post Edited (Mike Green) : 2/19/2009 4:16:12 PM GMT
  • JasonDorieJasonDorie Posts: 1,930
    edited 2009-02-19 18:43
    Grasshopper - that waitcnt in my code is only there because my code doesn't do anything else. As long as you call 'UpdateSeconds' more often than once per second, the code will work for you. I put in a 10th of a second wait to 'simulate' real work. In your code, you'd just add a call to UpdateSeconds to you existing main loop, assuming you have one, and it'll repeat often enough. As I mentioned before, a simple change will allow you to call the UpdateSeconds function as little as once every 50 seconds.

    The 80_000_000 is the clock frequency. You could actually replace that with clkfreq, which would be more portable, and better coding practice. I've only run the prop at 80MHz, so I tend to just use the constant.

    Jason
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-02-19 19:01
    Guys,

    For time differences less than 53+ seconds (80MHz clock), you're making things way too complicated. In this case, you have only to subtract the prior cnt from the current cnt to get the time difference. If the timer rolled over in between, the math still works — without a bunch of conditionals. The only catch is that if the interval was longer than 26+ seconds, the difference will be negative. But one seldom needs times accurate to 1/80E6 seconds anyway, and you can simply shift the difference right to eliminate the sign bit. Once you've shifted right by one, you'll have a positive number representing the time difference in 1/40E6 seconds.

    -Phil
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-02-19 20:18
    hello grasshopper,

    if you want to measure longer times than the 26 or 53 seconds
    without stopping the whole cog

    If you have a cog to spend you can use the timer-object from the obex
    which gives a clock with milliseconds seconds minutes hours and even days

    if you don't want to spend a cog to this

    you can use something like this

    VAR
      long Timer  
      long SecoundCnt 
    
    PUB ...
      SecoundCnt := 0
    
      Timer := cnt
    
      repeat 'your repeat-loop doing whatever you want
        if elapsed_time_msec(Timer) >= 1000
          Timer := cnt 'save new snapshot of cnt
          SecondCnt ++ 'increment countervariable for seconds  
    
        ... rest of your code
    
    



    with this code you can count up the seconds until 2.147483648e9 which is more than 68 years (@Chip: smile.gif) is this enough time to finish the Prop II including a 64bit counter ? smile.gif))

    best regards

    Stefan
  • JasonDorieJasonDorie Posts: 1,930
    edited 2009-02-19 21:59
    Phil is absolutely right - I thought that because the Prop didn't handle unsigned numbers that the math wouldn't work, but it still does.

    The new UpdateSeconds code looks like this:

    PUB UpdateSeconds
      PreviousTime:= CurrentTime 'Copy the previous time count value 
      CurrentTime := cnt 'Get the new time value 
    
      ElapsedTime += ||(CurrentTime - PreviousTime) 
    
      if( ElapsedTime => 80_000_000 )
        ElapsedTime -= 80_000_000 
        Seconds++
    

    Stefan - Your approach will work, but since you're recording a new cnt value after a second has passed instead of using the existing value, you'll miss fractions of seconds, which will accumulate over time.· If this doesn't need to be accurate that won't be a big deal, but you'd lose a thousand cycles or more per second with that code.

    Jason
Sign In or Register to comment.