Shop OBEX P1 Docs P2 Docs Learn Events
Timing blocks of code with waitms in SPIN2 — Parallax Forums

Timing blocks of code with waitms in SPIN2

I'm using a P2 Eval board, revision C,

I'm expecting to see:

` set command mode.started: 30_000_000 microseconds

something just over 30 seconds

instead, I'm seeing

` set command mode.started: 1 microseconds

Code taken from the P2 Spin manual

{Object_Title_and_Purpose}

CON
_clkfreq = 250_000_000

_txpin = 16 + 6

PUB main() | time
time := getct()
pinlow(_txpin)
waitms(30_000)
pinfloat(_txpin)
time := getct() - time
time := muldiv64(time, 1_000_000, clkfreq)
debug("set command mode.started: ", sdec(time), " microseconds")

Comments

  • At 250 MHz, the number of ticks elapsed will exceed 32 bits in a bit over 16 seconds. So getct() alone will not be useful for timing intervals longer than that.

  • JonnyMacJonnyMac Posts: 8,912
    edited 2022-11-24 19:11

    In addition to Eric's point about the getct() delta, the waitms() instruction is limited by the clock speed. This is from an article I wrote for Nuts & Volts magazine.
    (https://www.nutsvolts.com/magazine/article/an-introduction-to-the-parallax-propeller-2)

    The formula for determining the maximum delay is: 2^31/clock frequency. If you’re running a 200 MHz clock as I do, the maximum delay
    is about 10.74 seconds; that’s 10,737 milliseconds, or 10,737,418 microseconds. Longer delays can be created with loops or through the
    use of delta timing via the system counter. The P2 has a 64-bit system counter. To give you an idea of the magnitude of 64 bits, running that
    counter at 200 MHz would take 2,924.7 years to roll over! Like the P1, the P2 is a 32-bit machine, so it’s not easy to deal with the system
    counter directly. The good news is we don’t have to.

    For a 250MHz clock, the maximum delay will be about 8.589 seconds, or 8_589 milliseconds, or 8_589_934 microseconds (yes, I tested)

      t := getct()
      waitus(8_589_934)
      t := getct()-t-40
      term.dec(t/US_001)
    

    The -40 accounts for the getct() instruction time. I have timing constants at the top of my programs that look like this:

    con { timing }
    
      CLK_FREQ = 250_000_000                                        ' system freq as a constant
      MS_001   = CLK_FREQ / 1_000                                   ' ticks in 1ms
      US_001   = CLK_FREQ / 1_000_000                               ' ticks in 1us
    
      _clkfreq = CLK_FREQ                                           ' set system clock
    
  • @JonnyMac @cgracey : Does the standard PNut waitms() not handle long waits? It's not hard to make it work right up to 2 billion milliseconds (~23 days) by just waiting 1 second at a time, with the last one being a fractional second. With a bit of care about signed/unsigned arithmetic that can be doubled.

  • The current interpreter gets the clock frequency, divides by 1000 (waitms) or 1000000 (waitus) and then multiplies that by the user parameter for use by waitct. it's not ideal, but it's what we have.

    ' WAITUS(us)
    ' WAITMS(ms)
    '
    waitus_         getct   w                       'get ct now to minimize error
    
                    rdlong  y,#@clkfreq_hub         'get clock frequency
    
                    rep     @.stall,#1              'use REP to stall interrupts to protect cordic operation
                    qmul    y,x                     'multiply clock frequency by us/ms
                    getqx   x
                    getqy   y
    .stall
                    cmp     pa,#bc_waitus   wz      'us or ms time unit?
                    mov     z,##1000
            if_z    mul     z,z
    
                    rep     @.stall2,#1             'use REP to stall interrupts to protect cordic operation
                    setq    y                       'divide by time unit
                    qdiv    x,z
                    getqx   x
    .stall2
                    add     x,w                     'add ct
    
                    jmp     #pwct                   'do WAITCT
    
  • What do you think?

    sample code of my stopwatch object. call sw.reset at the beginning of the code you want tested; use sw.elapsed at the end of the code you want tested...

      sw.reset()
      pinlow(Txpin)
      waitms(500)
      pinfloat(Txpin)
      time_low, time_high := sw.elapsed()
    

    The stop watch object

    VAR
            long _low
            long _high
    
    PUB reset()| low, high
    ' Reset current start time
      org
        getct high wc
        getct low
      end
      _low, _high := low, high
    
    PUB elapsed() : low, high | c_low, c_high
    ' Get elapsed time
      c_low, c_high := _low, _high
      org
        getct high wc
        getct low
        sub   low, c_low wcz
        subx  high, c_high
      end
    
    PUB elapsedms() : low, high | c_low, c_high
    ' Get elapsed time in milliseconds (ms)
      c_low, c_high := _low, _high
      org
        getct high wc
        getct low
        sub low, c_low wcz
        subx high, c_high
        ' TODO: convert to millisecond (ms)
      end
    
    PUB elapsedmu() : low, high | c_low, c_high
    ' Get elapsed time in microseconds (mu)
      c_low, c_high := _low, _high
      org
        getct high wc
        getct low
        sub low, c_low wcz
        subx high, c_high
        ' TODO: convert to microseconds (mu)
      end
    
  • I wrote similar code a couple years ago -- before getms() was available in Spin2. Seeing your code I got mine back out and did a clean-up, especially as I have a new project coming that needs long-duration timing. What you call reset(), I call start(), and I allow an offset. In the P1 version of this code I have found it convenient to set a negative time duration and then while checking look for the timer to be 0 or higher. This object has delay routines that will break the ~10 second (at 200MHz) limit of the waitms() and waitus() instructions.

    I run my P2 projects at 200MHz, hence the constants in the program that make calculating duration easy.

    You might find some of this useful.

Sign In or Register to comment.