Shop OBEX P1 Docs P2 Docs Learn Events
Waiting untill a certain time without using waitcnt, What am I doin wrong here?? — Parallax Forums

Waiting untill a certain time without using waitcnt, What am I doin wrong here??

Jorge PJorge P Posts: 385
edited 2011-12-30 09:27 in Propeller 1
In the following code I am trying to mark a point in time, then use a variable to mark 1 second past that point. i loop untill I reach the 1 second mark and increment TickCount. But It stops updating TickCount every few iterations, for a while, then continues. So what am I doing wrong, if not everything. Also what is the purpose of WMin in Clock.Spin (in obex)

My goal is to wait to do something until I reach a certain point in time without using waitcnt. I cant stop the cog.

EDIT: Solution is in Post #8 of this thread! Thanks Stefan.
{{
    Continue through a loop until a certain amount of time has passed
    without pausing or stopping the cog using waitcnt.
    
    using code samples from "Clock.spin V1.1" by Jeff Martin in obex

    -----
    
    
}}
CON
     _clkmode = xtal1 + pll16x
     _xinfreq = 5_000_000

     WMin     = 381 ' in Clock.spin ?? What is this for?

OBJ
'    T : "Clock"
    Debug : "Parallax Serial Terminal"

VAR
    long Now, StartPoint, EndPoint, SyncPoint, LoopNum
    byte TickNum, HitMark     

PUB Main
    Debug.start(115200)

    Now := 0        ' the current point
    StartPoint := 0 ' 
    EndPoint := 0   ' the point equal to 1 second past SyncPoint 
    SyncPoint := 0  ' stores the point to sync to
    LoopNum := 0    ' stores the number of time we have looped so far
    TickNum := 0    ' stores how many times we hit the EndPoint
    HitMark := 0    ' stores 0 or 1 to indicate if we hit the mark
    
    repeat

      LoopNum++
      
      if SyncPoint == 0
         ' were at the beginning of the program
         MarkSync ' sets SyncPoint
         StartPoint := GetSync

         EndPoint := StartPoint + (clkfreq * 1) #> WMin '??? one second from now??????
         
         Now := cnt
          
      else
         ' were in progress
         if Now => EndPoint
            ' reset values and update the tickNum
            Now := 0       
            StartPoint := 0 
            EndPoint := 0  
            SyncPoint := 0

            TickNum++
            HitMark := 1
            
         else
            HitMark := 0   
            Now := cnt
            
            
      SendIt

PUB SendIt    
    
      NewLine
      Seperator
      NewLine
      Debug.Str(String("StartPoint is: "))
      Debug.Dec(StartPoint)
      NewLine
      Debug.Str(String("EndPoint is:   "))
      Debug.Dec(EndPoint)
      NewLine
      Debug.Str(String("Now is:        "))
      Debug.Dec(Now)
      NewLine
      Debug.Str(String("LoopNum is:    "))
      Debug.Dec(LoopNum)
      NewLine
      Debug.Str(String("TickNum is:    "))
      Debug.Dec(TickNum)
      NewLine
      Debug.Str(String("HitMark is:    "))
      Debug.Dec(HitMark)

               
      
PUB NewLine

    Debug.NewLine

PUB Seperator

    Debug.Chars($2D, 25) ' print 25 hyphens

PUB MarkSync                                                                                     
{{Mark reference time for synchronized-delay time windows.                                       
Use one of the WaitSync methods to sync to start of next time window.                            
}}                                                                                               
  SyncPoint := cnt

    
PUB GetSync
    return SyncPoint

PUB WaitSyncSec(Width)                                                                           
{{Sync to start of next second-based time window.                                                
Must call MarkSync before calling WaitSyncSec the first time.                                    
  PARAMETERS: Width = size of time window in seconds.                                            
}}                                                                                               
  SyncPoint += (clkfreq * Width) #> WMin
      

Comments

  • Jorge PJorge P Posts: 385
    edited 2011-12-27 05:09
    I just noticed it is hiccuping on negative values of StartPoint and Now variables. How to correct this? Also, I Modified the variables section so TickNum is now a long.
    VAR
        long Now, StartPoint, EndPoint, SyncPoint, LoopNum, TickNum
        byte HitMark
    
  • Jim FouchJim Fouch Posts: 395
    edited 2011-12-27 05:14
    WaitCnt will only work for timesof about 53.68 seconds. This is due to the counter being a 32-bit value. At 80Mhz the clock rolls every 53.68 seconds. The 381 WMin is because in SPIN that's the number of clock cycles it takes to intereperet the WaitCnt command and if you set the setpoint to something less than the current clock + 381 it will sit there and wait for the counter to spin, which could be why you are seeing ~1 second extra in your results sometimes.
  • Jorge PJorge P Posts: 385
    edited 2011-12-27 05:21
    Thanks for the quick reply Jim, I just read the note in the Propeller Manual "IMPORTANT" for WAITCNT on page 219.

    So should I shift right all negative values? Will that correct it or introduce some other error? I will play around with it a bit more, I'm just a bit bugged out on this, no puns intended.
  • Jim FouchJim Fouch Posts: 395
    edited 2011-12-27 05:28
    It all depends on how accurate you want the events to happen. If you don't need them to be supper tight, then just adding something like 500 so your count is always ahead should be fine. Remember don't get too caught up in thinking about the rolling effect of the counter. If you are adding a large number to the counter, the propeller will roll your result too. Which, is a good thing. The biggest thing is to make sure you are not setting target times closer then the CNT+381.
  • pgbpsupgbpsu Posts: 460
    edited 2011-12-27 05:39
    JorgeP

    cnt is an unsigned int but the => and <= work on signed numbers. You need to subtract the current time from the start time and then compare that to the timeout time. This subtraction will "convert" your unsigned cnt values to a signed result. You'll need to do something like this to avoid the problem with negative numbers. This still has the 53 second limit that was mentioned earlier.
    timeout:=4 ' number of seconds allowed to elapse before continuing
    sTime := cnt
    
    repeat 
      'do some other things
    
      eTime := cnt
    
    until (eTime - sTime ) > (timeout * clkfreq)
    
    I'm writing this with a 1 year old on my lap (who isn't very happy by the way). It's the right idea but might need some tweaking. The problem is it may not keep you synced. You can change the until line so that it exits the repeat loop once it is within some small amount of time of the timeout value. For example test to see if you are within 10milleseconds of the timeout. If you are DON'T repeat; exit at that point into a waitcnt where you wait for the exact timeout value. If you do this be sure the code you call when you have not timed out executes in less time than your window. In my example it would have to be less than 10 milliseconds, otherwise you could miss your timeout window and end up back in the loop where you don't want to be.
  • Jorge PJorge P Posts: 385
    edited 2011-12-27 05:52
    This is going to be used in my Propeller Professional Development Board project to read the clock in the same loop I am using to update the display, so it need to be at least 1 time per second for the clock read. So far, in that project, I am doing everything in a single cog until it is full so I can keep the rest free for other things like the Video Out, FPU, etc.

    My project link - http://forums.parallax.com/showthread.php?134537-PPDB-Using-the-full-PPDB-Updated-Code-Version-1.4
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-12-27 09:44
    For cases where a loop has to go on running fast as possible but inside the loop parts of the code should only be exectuted
    every 200 msec or every 10 seconds etc. I use this code that is attached to this posting.

    The method is called elapsed_time_msec it just needs one long per timer and if timeevent has occured a line of code

    CntSnapShot := CntSnapShot + WaitTimeTicks

    to "start" timer again

    The method takes care of the systemtimer-rollover from max to zero and sign-changing through that
    see comment inside method elapsed_time_msec. The waiting-period can go up to 26 seconds.
    For longer waitingperiods I would set up a counter variable that is counting seconds.

    keep the questions coming
    best regards

    Stefan
  • Jorge PJorge P Posts: 385
    edited 2011-12-27 10:31
    @Stefan & pgbpsu,

    I will check it out later tonight. I'm off to to catch some z's. I'll post updates and mark this thread solved then if I get it working.

    Thanks again for your pointers, tips, and samples.
  • Jorge PJorge P Posts: 385
    edited 2011-12-28 18:00
    @Stefan
    This is exactly what I was trying to do, I will mark this thread as solved! I would like to add credits in the project I use this in for the person who wrote the code, is it yours Stefan?

    Anyways, this will help me reduce the led flicker of the display, in my above stated project, by helping me skip the RTC reads wile updating the display. I am sure it will, when I get that far, help me with reading a GPS, connected to a uM-FPU V3.1 over I2C, every few seconds or at the push of a button on the 4x4 Matrix keypad.

    This is very helpful to me!
  • kuronekokuroneko Posts: 3,623
    edited 2011-12-28 18:15
    StefanL38 wrote: »
    The method takes care of the systemtimer-rollover from max to zero and sign-changing through that see comment inside method elapsed_time_msec. The waiting-period can go up to 52 seconds.
    I'm not really comfortable with the 52sec statement. Let's say p_TimeVar is $8000_0000 and RightNow resolves to $6E6B_2800 (50sec later). Then your method returns ||($6E6B_2800 - $8000_0000) = $1194_D800 (3.68sec). We had [post=1000116]this discussion before[/post], the method used to have a comment saying it's good for ~26sec. Which makes it (the method) pointless. Unfortunately you stopped replying.
  • Jorge PJorge P Posts: 385
    edited 2011-12-28 18:51
    @kuroneko
    hmmm, Should I revert to unsolved until I test this more thoroughly? Or Should I continue with my own messy code and try shifting right negative values? Or, how, in my code, can I unsign the values, I'll take a look at some more math objects to see if I can find something....
  • Jorge PJorge P Posts: 385
    edited 2011-12-28 18:59
    Ok, so, if I have this 53 second limit, can I just add 7 seconds to the time I am waiting for, and use a second variable to store when we get to the 53 second mark, then check for 7 seconds after that?
  • Heater.Heater. Posts: 21,230
    edited 2011-12-28 19:04
    If you get your subtractions and comparisons done in the right order (as shown above I believe) it will work using regular 32 bit signed Spin variables without any hiccups as CNT rolls over. You may have a question in your mind as to weather it fails after 26 or 53 seconds but I guess in your case you can arrange for your time delays to be the smaller.

    P.S. Why do people say CNT is an unsigned quantity? Clearly when used in in Spin (in comparisons) it can only ever be signed. Perhaps it's just counting in an odd order.
  • kuronekokuroneko Posts: 3,623
    edited 2011-12-28 19:09
    @Jorge P: Nah, it's not that critical. If you stay within the 26sec limit then it doesn't do any harm. You can change the following line to something simpler though (from Stefan's example):
    '   elapsedTime := elapsed_time_msec(CntSnapShot)            ' old
        elapsedTime := (cnt - CntSnapShot) / (clkfreq / 1_000)   ' new
    
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-12-29 00:31
    elapsedTime := (cnt - CntSnapShot) / (clkfreq / 1_000) ' new

    very compact solution.
    question: why do you not add examples with concrete numbers to show how it works?
    maybe then I would have remembered it from the last time.
  • kuronekokuroneko Posts: 3,623
    edited 2011-12-29 15:50
    StefanL38 wrote: »
    question: why do you not add examples with concrete numbers to show how it works?
    DAT
    {
              before       after (26s)       elapsed (after - before)
            $00000010  +/+  $7BFA4810       $7BFA4800
            $7FFFFFF0  +/-  $FBFA47F0       $7BFA4800
            $80000010  -/-  $FBFA4810       $7BFA4800
            $FFFFFFF0  -/+  $7BFA47F0       $7BFA4800 (26s @80MHz)
    }
    
  • Jorge PJorge P Posts: 385
    edited 2011-12-30 05:37
    Regarding the ~26 seconds...

    It will still work for what I need, If I need to keep track of lets say 1 minute with Stefan's code, I can just add an additional variable to store a count of when I hit the 20 second mark 3 times. Shouldn't that solve the ~53 second hiccup too?

    Thank you for pointing out this information, without it I may have not realized it later when I least expect it! Maybe once FirstSpin.tv gets to discussing code timing later in their discussions, they can point out these things to their listeners.

    Can someone explain in more of a lengthy detail as to why/how this all happens?
  • Mike GMike G Posts: 2,702
    edited 2011-12-30 05:57
    Here's a 4x timer object that I used to turn relays on/off in a Spinneret project. The object is accurate to 1/512 of a second and can span 97 days. Timers start with a the associated IO pin high 27-24. The pin goes low when the timer expires. IO pin state is constantly written to HUB RAM so a consumer can monitor state.
  • JonnyMacJonnyMac Posts: 9,198
    edited 2011-12-30 09:27
    @Jorge: You may find something useful in this article from my Nuts & Volts column:
    -- http://www.parallax.com/Portals/0/Downloads/docs/cols/nv/prop/col/nvp7.pdf
Sign In or Register to comment.