a question about waitcnt in PASM
msrobots
Posts: 3,709
I want to synchronize a loop to some frequency say 1 Hz
Sadly other stuff happens here COULD exceed the time set for delay, SOMETIMES. By now it just waits 50+ seconds because cnt is already past time when waitcnt gets called.
My goal now is to avoid this over run and instead of waiting 50+ seconds wait as less as possible, best would be no wait. Because I already overrun my time and need to catch up to get synced again.
I am thinking about this
First I am not sure if I need to use CMP or CMPS to compare time with CNT.
Second I now have modified time, so this delay will persist and I am off my frequency and can never catch up because the original time sync is gone.
Another thought is this
Any help welcome here, there should be a known practice to shorten/avoid the 50+ second problem
Enjoy!
Mike
time long 0 delay long 0 rdlong delay, #0 'wait a 1 Hz (clockfreq) startclockloop mov time, CNT add time, #32 'initial delay for first clock as short as good clockloop waitcnt time, delay 'this should get my clock time synced ... other stuff happens here ... jmp #clockloop 'if one axis not ready with MOVEMENT next clock
Sadly other stuff happens here COULD exceed the time set for delay, SOMETIMES. By now it just waits 50+ seconds because cnt is already past time when waitcnt gets called.
My goal now is to avoid this over run and instead of waiting 50+ seconds wait as less as possible, best would be no wait. Because I already overrun my time and need to catch up to get synced again.
I am thinking about this
time long 0 delay long 0 rdlong delay, #0 'wait a 1 Hz (clockfreq) startclockloop mov time, CNT add time, #32 'initial delay for first clock as short as good clockloop cmp time, CNT wz, wc if_be mov time, CNT if_be add time, #9 'or even shorter waitcnt time, delay 'this should get my clock time synced, now I avoid the 50+ delay but am permanent off original sync ... other stuff happens here ... jmp #clockloop 'if one axis not ready with MOVEMENT next clock
First I am not sure if I need to use CMP or CMPS to compare time with CNT.
Second I now have modified time, so this delay will persist and I am off my frequency and can never catch up because the original time sync is gone.
Another thought is this
time long 0 delay long 0 rdlong delay, #0 'wait a 1 Hz (clockfreq) startclockloop mov time, CNT add time, #32 'initial delay for first clock as short as good clockloop cmp time, CNT wz, wc if_be add time, delay if_a waitcnt time, delay 'this should get my clock time synced, now I avoid the 50+ delay time is still in sync? ... other stuff happens here ... jmp #clockloop 'if one axis not ready with MOVEMENT next clock
Any help welcome here, there should be a known practice to shorten/avoid the 50+ second problem
Enjoy!
Mike
Comments
It waits if the loop finishes early, breezes on through if it finishes late, and remains synchronized.
Your system design dictates what.
One important question, is how often does the over-run occur ?
If it is rare, and never more than a 'next tick' in stretch, you have simpler choices.
You can round-up to the next time quanta, in which case you stay in phase, but have skipped a whole time slot.
This would be a good choice in a design where staying in phase matters most.
or, you can just 'get to it as soon as you can', which gives some jitter but is closer to correct time.
You can use WAITCNT for lowest jitter, as that resolves to SysCLK, or you could [read and compare >=] which solves the 50+ jump, but does have a more coarse exit jitter.
(of course, once you have over-run, exit jitter of a few cycles is a moot point )
thank you Jon. So that part I got right since you are doing it also...
as of putting the waitcnt at the end of the loop, its like repeat until or repeat while or - say a style issue. And usually I like the way you program, very readable. So I try to learn from you.
But it should not make any difference on re-syncing.
T Chap and ChrisGadd sadly completely miss the point.
I use my stepper code as example, but the question is not about the stepper code and how to improve it with pins instead of longs, that belongs into the other thread and is a perfect valid question.
But here I am looking for a solution to re-sync a waitcnt loop thru catching up once it got out of sync.
I try my question again, with different wording.
My timed loop works fine, - and since Jon confirmed it, nothing is wrong with it.
PASM waitcnt time, delay - waits for cnt to hit the same value as time has, then adds delay to time (preparing the new wait value) and continuous.
Works fine unless your code in between that loop does exceed delay clock ticks. Then time is less as CNT and CNT needs to go around to catch it. There we have our 50+seconds delay.
what I was thinking now is instead of calling waitcnt time,delay (since I am late anyways) to just add delay to time and skip waitcnt.
IF my time value is less then CNT(+x?) skip waitcnt, just add delay to time else do the waitcnt
And if the next loops I go thru do not exceed their time limit, I am able to catch up to the original timing.
So my question still is how to find out if time is less then CNT? Even better if time is less then CNT - #16 or so to compensate for the instructions in between.
I rather wait 16 clocks as 50+seconds
so how to compare CNT with a long and to decide if the long is BIGGER then CNT so no overflow happens and I can call waitcnt else skip it.
I am simply unsure how waitcnt handles overflow conditions, my understanding is that CNT is unsigned.
IF timer>CNT works as long as I do not hit timer=$FFFA and CNT=1 (or alike) then it goes haywire.
Because at that time, timer=$FFFA is smaller as CNT=1 , but it isn't.
help!
Mike
As I'm testing this code with a PAB that has LEDs on 26 and 27, I started two cogs with this code like this:
Not what I am after, but nice!
ChrisGadd,
YES! that seems to look like what I am after. I have to study it for a moment, but thanks...
Enjoy!
Mike
thank you. This does exactly what I was looking for. Perfect.
Gosh, I love this forum,
Enjoy!
Mike
and will get a test now in real program ...
Thanks @ChrisGadd again, and bow deep - to Jon, I put the check down like you preferred...
Enjoy!
Mike
So my question still is how to find out if time is less then CNT? Even better if time is less then CNT - #16 or so to compensate for the instructions in between.
I rather wait 16 clocks as 50+seconds
so how to compare CNT with a long and to decide if the long is BIGGER then CNT so no overflow happens and I can call waitcnt else skip it.
I am simply unsure how waitcnt handles overflow conditions, my understanding is that CNT is unsigned.
Msrobots,
I am very familiar with exactly the problem you describe, as that is what I have to deal with in my multi-threaded scheduler.
You need to do an actual subtract of CNT from TIMER and test the MSB (bit 31) of the result by doing a left shift into CARRY. If the CARRY is set, the result was negative, and if the CARRY is not set, the result was positive. I can think of no other way to do this.
But do realize that *if* the value of CNT, just happened to be identical to TIMER, and the result then tested as not negative, then you would still be in trouble because by the time you execute the next instruction, the result *will* be negative.
To solve this, you must first add a small number of bogus counts to TIMER before you do the comparison subtraction. The minimum additional required number needs to allow for all the instruction clocks that will be executed between the subtract instruction and the waitcnt instruction. Don't forget to allow 6 clocks for the waitcnt itself.
Then, before you execute or skip the waitcnt, subtract the same bogus number from TIMER to keep your sync.
Sure, there was a tiny hiccup depending on how far the TIMER was *behind* the value in CNT, but sync has not been permanently lost.
If, however things got so silly that TIMER was 26 seconds (half of 53) different from CNT, then you could never tell who is bigger, and this method cannot work. But that's just for the purists, and this method works just great, millions of times an hour in real life industrial applications.
I suspect what you are attempting would be a great candidate for my multi threaded cooperative scheduler that lets you run up to 8 independent threads simultaneously in a single COG.
But that is a whole other discussion.
Cheers,
Peter (pjv)
Jon - I have to redo that. I need the check first, else Hickup will happen.
This way it can't hang...
Enjoy!
Mike
It bit me again. The 50+ seconds thing.
And I guess my problem is that I not just need to read the post of @pjv, but READ it again, and try to understand it completely.
Maybe I am confused here, but I thought is what it should be, come on, its in FullduplexSerial.
But then I READ @pjv,s post again and stumbled over "Don't forget to allow 6 clocks for the waitcnt itself"
Yes who can read has a clear advantage. 6, not 4, so #18 not #16 I said to myself.
But still no luck. But I am really sure that @pjv knows what he is talking about. I am just to slow to understand it, I said to myself, its your second language, that English, READ it AGAIN.
"You need to do an actual subtract of CNT from TIMER and test the MSB (bit 31) of the result by doing a left shift into CARRY. If the CARRY is set, the result was negative, and if the CARRY is not set, the result was positive. I can think of no other way to do this."
Question, is the same as in relation to carry, and if not why not?
Because somehow, sometimes the 50+ seconds thing still appears...
Mike
Mike
I need to know if in Nticks, time is still bigger then CNT.
That means that time has to be > (CNT (now) + Nticks)
or shorter time - Nticks has to be > CNT
subtract, not add. Shoot.
Thanks Dave, at least it seems to makes sense
OK I will try
Mike
yes, you nailed it. what a stupid thing.
Thank you a lot.
Mike
Good catch. In my response to Msrobots I was working from memory of code written quite a long time ago, and my "add" statement was incorrect, it should be "subtract", so please forgive my non-thoroughness.
For the comparison test to make sense, the TIMER first needs to be reduced by at least the number of ticks that will be consumed by code between the test and the WAITCNT that follows. This is to ensure that by the time the WAITCNT is encountered, TIMER is still (just) larger than CNT, and hence will not "snag". I call this the "snagmargin", and to keep synchronism, it needs to be added back to TIMER.
Cheers,
Peter (pjv)
In order for this to work, the result of any operation should clear C until cnt (src) has passed the target (dest).
Peter (pjv)
Mike