Timing Question
Greg LaPolla
Posts: 323
in Propeller 2
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 usegetus()
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 usegetct()
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)
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.
getms, (at least flexspin's implementation) just uses a straight QDIV, which doesn't return anything approaching a reasonable result when it overflows.
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?
My samptime is typically 1ms and I increment my own timer vars which are then reset at the appropriate time.
Craig
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...
Yeah, there is Spin1 compatible functions that will compile on the Prop2.
I needed to have an uptime in seconds in the robot, so I used this (clk is 285 MHz):
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:
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
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.