Never returning from waitcnt
RogerInHawaii
Posts: 87
I've got a problem with calling the waitcnt method.
I'm calling it like this:
· waitcnt(cnt+ClockDelay)
where the ClockDelay variable happens to have the value 381. In this case the amount of time
that waitcnt should wait is extremely short.
But it never returns from waitcnt. Well, I don't know if it's "never". I waited for a minute and it didn't return so I stopped the program.
Is it possible that waitcnt has some minimum wait time and cnt+381 is just too short?
I'm calling it like this:
· waitcnt(cnt+ClockDelay)
where the ClockDelay variable happens to have the value 381. In this case the amount of time
that waitcnt should wait is extremely short.
But it never returns from waitcnt. Well, I don't know if it's "never". I waited for a minute and it didn't return so I stopped the program.
Is it possible that waitcnt has some minimum wait time and cnt+381 is just too short?
Comments
regards,
John
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
'Necessity is the mother of invention'
Those who can, do.Those who can’t, teach.
Try the following:
waitcnt(ClockDelay + cnt)
I assume that cnt is read later than in your code and maybe late enough. And try to increase Clock Delay to find the minimum value.
But these proposals are only for experimenting and analyzing! Take care that delays are significant longer than the minimum delay.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Airspace V - international hangar flying!
www.airspace-v.com/ggadgets for tools & toys
I think the issue here is that watcnt waits until the system clock is EXACTLY equal to the specified value. Obviously if you specify a value that's less than the "current" clock value (current as far as when the waitcnt actually performs the comparison) then it never encounters a clock value that's EQUAL to the specified value. Well, at least not for a very, very long time.
I think the correct solution to this is for the waitcnt method to be changed so that it returns as soon as the current clock value is GREATER THAN the specified target value. That would avod problems like I encountered, where the value added to cnt is a time value that's shorter than the amount of time taken by the interpreter to process it. Plus, it would accommodate situations where the specified value is (inadvertantly) prior to the actual current clock value, which would clearly be a mistake but waitcnt should do better than waiting days to return.
I think you answered the question in your question 'Is it possible that waitcnt has some minimum wait time and cnt+381 is just too short?' - but good practice is waitcnt(delay+cnt) as you found in your testing ..
Are you enjoying the learning curve ?
Regards,
John
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
'Necessity is the mother of invention'
Those who can, do.Those who can’t, teach.
This works great until your counter rolls over. For example, cnt is at max - 1000, and you ask it to wait for 10000 clocks...the value it would compare to be >= would wrap around to be 9000, so waitcnt would immediately return.
Jonathan
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
"undocumented" is a bit harsh. The waitcnt documentation on page 323 of the propeller manual has this text:
"IMPORTANT: Since WAITCNT pauses the cog until the System Counter matches the given
value, care must be taken to ensure that the given value was not already surpassed by the
System Counter. If the System Counter already passed the given value before the wait
hardware activated then the cog will appear to have halted permanently when, in fact, it is
waiting for the counter to exceed 32 bits and wrap around to the given value. Even at 80
MHz, it takes over 53 seconds for the 32-bit System Counter to wrap around!
Related to this, when using WAITCNT in Spin code as shown above, make sure to write the
Value expression the same way we did: in the form “offset + cnt” as opposed to
“cnt + offset.” This is because the Spin interpreter will evaluate this expression from left
to right, and each intermediate evaluation within an expression takes time to perform. If cnt
were at the start of the expression, the System Counter would be read first then the rest of the
expression would be evaluated, taking an unknown amount of cycles and making our cnt
value quite old by the time the final result is calculated. However, having cnt as the last
value in the WAITCNT expression ensures a fixed amount of overhead (cycles) between reading
the System Counter and activating the wait hardware. In fact, the interpreter takes 381 cycles
of final overhead when the command is written in the form waitcnt(offset + cnt). This
means the value of offset must always be at least 381 to avoid unexpectedly long delays."
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
Thus, instead of doing:
·· waitcnt(100 + cnt)
You'd just d:
·· waitcnt(100)
and waitcnt itself would determine what the current cnt is, add the specified value to it, and wait for the cnt to hit that value. Waitcnt would also be able to determine, by itself, whether the specified value is too short a cycle count to handle and return immediately.
Is there ANY situation where you'd call waitcnt and NOT add cnt to the value you want wait? Then why not have waitcntdo it by itself?
Maybe it's unreasonable to expect a change to waitcnt, but perhaps another method could be added that does the +cnt itself and can therefore detect by itself when the specified "number of cycles to wait" is too small to handle and therefore return immediately.
and so on when more precise timing is required (though, for obvious reasons, this is often done in assembly)
I agree that a "delay" type function is more often what people want than a waitcnt. You could wrap your own, of course, and use the #> operator to make sure the delay value is always >= 381. (Note that the #> operator treats values as signed.)
As to using waitcnt without adding cnt to it, I use waitcnt in this mode most frequently. For example, if I want to sample an ADC at regular intervals, I will kickstart my wait_until_cnt variable using the cnt register, but from then on out I would just say
This lets me have a deterministic (and very precise) sampling rate, even though I'm using SPIN code which may vary in execution time. I just need to make sure that my "<do a bunch of processing>" code takes less time than interval.
Not a problem...this particular issue has bitten me before too! [noparse][[/noparse]8^)
Jonathan
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
But seriously, 32 XOR gates (equality check) was a lot cheaper to implement than having another counter register start from zero and count up to the desired delay ticks. Plus in Chip's mind, he wanted every core to be able to synchronize to and see the same number.
Is there ANY situation where you'd call waitcnt and NOT add cnt to the value you want wait? Then why not have waitcntdo it by itself?
No, but there are situations where you want several subsequent points in time·to be·related exactly to that time you started something. If you have a magic wait which does add cnt itself you never·know exactly·how long waitcnt is going to·wait. waitcnt itself is getting parameters from HUB-RAM. So·at least for the very first·fetch of data from HUB-RAM you don't know how long the HUB-access took. rdlong can take·7 to 22 cycles. So, in the way that waitcnt is implemented it is as accurate as the clock. And it can keep the accuracy even over the long term.
For an additional wait which·would add cnt by magic and recognize a waittime which is to low, ther might be different reasons: Not enough space left in the Interpreter, no more bytecode available. No need for that.
If you want waitcnt to work as you described it, then take the SPIN-interpreter sourcecode and change it.
Post Edited (MagIO2) : 4/24/2009 11:39:20 PM GMT
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--Steve
Propalyzer: Propeller PC Logic Analyzer
http://forums.parallax.com/showthread.php?p=788230
I understand the need to have things happen at specific time intervals, but that approach has the same danger of passing in a value to waitcnt that is already greater than the current cycle count as in my example where I'm adding a value to cnt that's too small. The problem with the time interval approach is that it's always possible that the processing that occurs between one event and the next event takes longer than expected so that when you add your constant time interval value to the running total it ends up being less than the current cnt value, so that the call to waitcnt does not in fact return when you expect it to, since the next "event time" has already passed.
I suspect that the only way to really assure performing operations at specific time intervals·is to use a timed interrupt. But I don't think that's available with the Propeller.
Actually OwenS example should set time then add cnt afterwards, but considering how geologically slow spin is, I figure it didn't really matter·because it would be silly to do for very short periods anyway.·
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--Steve
Propalyzer: Propeller PC Logic Analyzer
http://forums.parallax.com/showthread.php?p=788230
-Phil
Chip designed the propeller to be as deterministic as it can be.
That's why waitcnt waits for an exact match.
In the manual is a variant described that gives a rocksolid time-delay which will be still very exact
even if execution-time of the loop will be variant. (Of course within the limit of 381-cycles plus what come
from execution other commands in the loop.
If you want to have it REALLY fast you have to go to PASM. Here the minimum-delay is reduced to 9 cycles.
I haven't read each post of this thread. So maybe it was mentioned somewhere.
But what are your minimum-requirements for the wait-delay ?
In the obex there is a timer-object with a millisecond-timer. If you use this object
Depending on your requirements you can use this timer to compare to what ever you want.
Of course the resoltion is reduced to a millisecond. But maybe this would still fit your requirements.
Another way could be to measure the elapsed_time and compare with "equal or greater than"
some time ago I wrote a method for this
with this you get a upper limit of around 26 seconds at 80 MHz
best regards
Stefan