Shop OBEX P1 Docs P2 Docs Learn Events
Timing Question — Parallax Forums

Timing Question

I am stuck on a timing issue. Can someone provide some insight to this bit of code and output. It runs this loop 5 times and the time count never changes and it exits out on the return false. The pin state is changing as there is 40 bits coming in and I can see it on my oscilloscope.

CODE

  start := getms() * 1000
  count := 5

  repeat 
    waitus(10)                       
    status := pinr(_dataPin)
    if ( status == state)
      count--
      if (count == 0)
        return false                     
      now := getms() * 1000
      seriald.fstr3(string("Start: %f Now: %f TImeout: %f\r\n"),start, now, timeout). 
  while (now - start < timeout) 
  return true

OUTPUT

Start: 104000 Now: 104000 TImeout: 50 
Start: 104000 Now: 104000 TImeout: 50 
Start: 104000 Now: 104000 TImeout: 50
Start: 104000 Now: 104000 TImeout: 50
Start: 104000 Now: 104000 TImeout: 50
Start: 104000 Now: 104000 TImeout: 50
Start: 104000 Now: 105000 TImeout: 50

Comments

  • You've used getms() (milliseconds) for the start and now variables, but waitus() (microseconds) for the wait. 5 waits of 10 microseconds only gives 50 microseconds total wait, which is well below 1 millisecond of resolution, so it's no surprise that now - start never changes. Instead of getms() * 1000, why don't you use getus() to get the elapsed microseconds?

  • Eric,

    Thanks for the input. getus() doesn't seem to be a valid function. error: unknown identifier getus used in function call

  • Ah, right, Chip added getms() but not getus(). If you're using FlexProp only, you can use the version with an underscore in front (_getus()). If you need to be compatible with PropTool, you'll have to use getct() to get the cycle counter and then do arithmetic on that to find the number of microseconds elapsed.

  • Yep, use getct.

    Arguably getms/_getus should never be used for anything. They are fundamentally bad functions for any serious use case. Maybe they shouldn't even be builtins to avoid the footgun effect.

    Getting the time in ms/µs involves a hidden divide, which is slow and has undesirable overflow behaviour (after ~50 days of uptime, getms WILL return garbage. About one hour for _getus).

    (This doesn't neccessarily apply to waitms/waitus. Divide is still there, but it's between your wait time and a clkfreq-derived value, so no overflow unless your wait time is too long)

  • evanhevanh Posts: 15,183

    It doesn't have to produce garbage. There is extra processing to manage it though. I used to do a lot of this with a rotary machine that flowed in one direction during normal run.

  • @evanh said:
    It doesn't have to produce garbage. There is extra processing to manage it though.

    getms, (at least flexspin's implementation) just uses a straight QDIV, which doesn't return anything approaching a reasonable result when it overflows.

  • evanhevanh Posts: 15,183
    edited 2022-08-16 01:35

    I found it, in p2_code.spin. Right, yes, 64-bit input to QDIV can't return a valid quotient when it would be larger than 32-bit.

    Yeah, working from the raw CT values is better. The rollover there is clean, diff's can be used as the application needs.

    I wonder how Chip is doing getms() ...
    Huh, it's a little more convoluted because it does both seconds and milliseconds in one routine. Meaning its divide overflow occurs after 32-bit of seconds rather than milliseconds. 136 years after power up then.

    The millisecond results stay mostly meaningful throughout because it is multiplying both the seconds and remainder by 1000 to get the milliseconds. Four Codic ops in total. I guess there will be glitches every 32-bit of milliseconds still. Rounding means the multiplies won't be clean.

  • So, to be clear, am I safe using the following?

        do
            waitcnt(presamp + samptime)
            presamp = getcnt()
    

    My samptime is typically 1ms and I increment my own timer vars which are then reset at the appropriate time.

    Craig

  • evanhevanh Posts: 15,183
    edited 2022-08-16 09:28

    Slightly buggy, the WAITCNT updates presamp itself. Besides, that's actually Prop1 code. Prop2 can use WAITX for a self-contained delay instead.

  • @evanh said:
    Slightly buggy, the WAITCNT updates presamp itself. Besides, that's actually Prop1 code. Prop2 can use WAITX for a self-contained delay instead.

    Hmm, I'm going off the FlexBasic docs:

    Craig

  • Oops, keep searching and then...

  • evanhevanh Posts: 15,183

    Yeah, there is Spin1 compatible functions that will compile on the Prop2.

  • pik33pik33 Posts: 2,350

    I needed to have an uptime in seconds in the robot, so I used this (clk is 285 MHz):

    pub gettime64():time |a  
    
    asm
      getct $1e0 wc
      getct $1e1
    
      mov   $1e2,##285000000
      setq  $1e0
      qdiv  $1e1,$1e2
      getqx a
    endasm
    return a
    
  • evanhevanh Posts: 15,183

    PR0..PR7 is now valid register symbols for user code, as of Flexspin v5.9.15 release. Same names as Pnut/Proptool.

  • @"Greg LaPolla"
    Hmmm, before we correct or even optimize code or discuss which commands would fit best we probably should define what that code is intended to do. I'm only guessing here, but I think the original intention could be to add delay to a loop so that it executes exactly once per millisecond (or any other time interval).

    That could be done with something like this:

    interval:= clkfreq/1000 ' 1 ms
    time:= getct ()
    repeat
      time+= interval
      waitct (time)
      DoSomeTask ()
    

    In assembler there is a quite powerful event system. You can wait for events (for example smart pin ADC result ready or serial RX buffer full) with an additional timeout.

  • The P2 has a RX buffer? I assumed that was the responsibility of the driver 🤔

    Craig

  • ersmithersmith Posts: 5,909
    edited 2022-08-18 19:47

    @Mickster said:
    The P2 has a RX buffer? I assumed that was the responsibility of the driver 🤔

    Craig

    Each smartpin does have a buffer, but it's very tiny (32 bits).

  • It doesn't have a multi-byte FIFO but it can store one received word (up to 32 bits) in the Z register while the next one is being processed by the shift register.

Sign In or Register to comment.