Calculating microseconds from CNT difference.
ryfitzger227
Posts: 99
Hey guys.
I'm working on a timing project with the Propeller and I've came across a problem I just can't figure out. I've been using the following code to time between two push button presses (like a stopwatch).
Then on the main cog, I'm sending the final result to the computer by using the Extended Full Duplex Serial object. Once it gets to the computer I take the clock cycles difference, divide it by 80 for microseconds, and divide it again by 1,000,000 to put the microseconds into seconds. This works perfect up until the point where the difference becomes a negative (about 26 seconds). I read on another thread that the correct way to do this would be something like this..
I've noticed that this takes away the negative, and gives half of the actual time. The only thing is, the computer doesn't know that it is half and just looks at it like 15 seconds, instead of 30 seconds. I have to find some way to multiply that by two before it's sent to the computer. I tried to just multiply it by 2, but of course that didn't work since the shift right operator is like dividing it by two. It just gives me the same negative number I had before. So all I'm really asking is how do I double the clock cycles result after I use the shift right operator so I can then convert it into microseconds and then later seconds with 6 decimal places. I've tried everything I know to try along with reading the manual. It seems like it would be so simple, but it has really kicked me in the butt!
Thanks.
- Ryan
I'm working on a timing project with the Propeller and I've came across a problem I just can't figure out. I've been using the following code to time between two push button presses (like a stopwatch).
waitpne(0,mask1,0) 'wait for start infrared to be broken (tstart=1 or manstop=1) ticks := cnt 'get timer value waitpne(0,mask2,0) 'wait for stop infrared to be broken (tstop=1 or manstop=1) LONG[tadr] := cnt - ticks 'calculate the final result
Then on the main cog, I'm sending the final result to the computer by using the Extended Full Duplex Serial object. Once it gets to the computer I take the clock cycles difference, divide it by 80 for microseconds, and divide it again by 1,000,000 to put the microseconds into seconds. This works perfect up until the point where the difference becomes a negative (about 26 seconds). I read on another thread that the correct way to do this would be something like this..
if timer < 0 timer := timer >> 1
I've noticed that this takes away the negative, and gives half of the actual time. The only thing is, the computer doesn't know that it is half and just looks at it like 15 seconds, instead of 30 seconds. I have to find some way to multiply that by two before it's sent to the computer. I tried to just multiply it by 2, but of course that didn't work since the shift right operator is like dividing it by two. It just gives me the same negative number I had before. So all I'm really asking is how do I double the clock cycles result after I use the shift right operator so I can then convert it into microseconds and then later seconds with 6 decimal places. I've tried everything I know to try along with reading the manual. It seems like it would be so simple, but it has really kicked me in the butt!
Thanks.
- Ryan
Comments
Just skimmed through while at traffic lights but doesn't left shift once double the result?
Why not have the computer add POSX (2,147,483,647) to the absolute value of the number if the number is negative?
Edit: After seeing kuroneko's post, I think there's probably a more elegant solution than what I'm suggesting. I just don't know it.
(taken from https://github.com/libpropeller/libpropeller/blob/master/libpropeller/stopwatch/stopwatch.h)
I've tried using left shift before, but it just gave me the same result as multiplying it by 2 - back to the negative number.
@SRLM
This is the simplest code snippet of the timing system. Others have pauses in them that get their wait times from the computer in clock cycles. I subtract them out each time from the computer, since it is the only device that actually knows the value. I probably could get it to work like this.. But I'll have to change a couple hundred lines of code on the computer's side.
Honestly, after what I've seen here I guess the easiest way would be do what Duane said - just add POSX to the absolute value of the negative number. If anybody can think of anything else, please let me know.
Duane,
I tried this just now and it's not giving me the correct results. I'm stopping the timer at around 45 seconds (going by the stopwatch on my phone), but I'm getting 35 seconds as the result. When I do it for 35 seconds, I get the opposite 45 seconds. I caught the data from the Propeller and the clock cycles it sent was -659097472. I double checked the computer, and it's performing the correct math I programmed it to do.
Absolute value of -659097472 is 659097472. 659097472 + 2,147,483,647 = 2806581119. 2806581119 / 80 = 35082263.9875us. (35.082264 seconds). Do you see what could be going wrong?
I'm not 100% sure how the timer works after 26 seconds, so I wanted to ask someone else instead of going and just playing with the numbers. Does the timer count up to POSX and then start counting down to 0?
Thanks.
- Ryan
What kind of precision are you after? Whole seconds, tenths of seconds, milliseconds, or ... ?
-Phil
Phil,
I'd like to have microseconds, if possible.
If it's off that much I think I'll be alright. In the beginning I figured I might have to do it in PASM, but figured that it wouldn't be that inaccurate for me to use spin. I don't need the precision to be quite 1 microsecond, and as long as the time it takes doesn't vary I'll be okay. This is a racetrack timing system, so everyone will be running on the same timer - they aren't particularly worried about it being 100% accurate to 1 microsecond as long as the inaccuracy doesn't vary.. If that makes any sense..
And I am planning on subtracting out the overhead, like you did, at the end after I get this negative thing working.
I can't really try post #7, because it's converting it to microseconds and I need clock cycles for my program. The program calculates everything with the clock cycles. I would have to change about 500 lines of code to get that to work. I'm sure it would work - it's just I need clock cycles.
This "negative thing" is a creation of yours. Many of us have shown you successful techniques. Now... these work as long as your interval is about 26.8 seconds (assuming 80MHz clock) or shorter. Is your interval longer? If it is, no joy with a simple delta calculation.
I have a couple projects on my desk that need me to keep track of timers where I don't have a cog to spare. I created a dirt simple object to manage timing -- so long as one of the timer methods is called before the 26.8-second limit, all is well. This is not good for microseconds, though; I'm happy with milliseconds.
Well see, this is what I originally tried (I think). I shifted the negative result one to the right and sent it to the computer. It was giving me what looked like half of the actual time. Well just now I had the computer double the clock cycles and then divide by 80 (it's the same thing as having that number and dividing by 40). I'm getting the same weird results as I got when I tried Duane's suggestion - for 45 seconds the math is showing 35 seconds, for 35 seconds the math is showing 45, and now (I just tested this one) 37 seconds is showing up as 32 seconds.
Edit:
Okay. So I just did multiple tests without doubling the number on the computer I just left it alone. When I did a test with a time of 37 seconds, it came up on the computer as 16. 16 * 2 = 37. So the number that I'm getting from the propeller is not actually half like I previously stated.
Sometimes yes. I can't be limited to 26.8 seconds. One time the time will be 5 seconds, the next 7 seconds, or even 38 seconds. It's never going to be above 50, but definitely above 26.
Again. A lot of these things would be successful if I was doing the calculations on the Propeller. I've even made them successful by doing that. What I'm trying to do is send the clock cycles to the computer and have the computer do the calculations. If that is not possible, then that's all I need to know and I'll start working on re-doing the whole software. But if it is possible, then that is what I'd like to do. The fact is I'm getting a negative number after doing oldCnt - newCnt once I go over the 26.8-second limit, or at least that is what is being sent to the computer. All I need to know is what formula I need to use to convert that number into microseconds like I can before the 26.8-second limit.
I'm very sorry to anyone that I confuse, it's just I'm super confused myself right now.
From previous comments it looks like you're using signed arithmetic on the PC so the above should work. If you were to use unsigned arithmetic then you could simply send the raw (unshifted) delta value.
Then you cannot do a simple delta calculation -- once you go past 26.8 seconds (at 80MHz), everything blows up. You need to take a snapshot of cnt at some interval shorter than 26.8 seconds and accumulate a larger unit (I use milliseconds in my simple timer object).
Another thing to consider is slowing the Propeller clock. If you change the PLL to 8x (40MHz), your delta-calculation interval becomes about 53 seconds.
I press the start button for the prop timer at the same time I do for the handheld stopwatch. When the stopwatch gets to a time (I've been testing 37 seconds) I press the stop button on the propeller timer. I'm just checking to see if the seconds are the same. This works fine for everything under 26 seconds and the results match. But as soon as I go above 26 seconds the results are not matching.
Here is my latest test. I again used the handheld stopwatch as a guide. After 37 seconds the prop sent 1314564368 to the computer. That has already been shifted one to the right by the spin code above, so all the computer did was divide by 40. The final time came out as 32 seconds. As far as I can tell, the computer did the math correctly. (1314564368 / 40 = 32864109 us or 32.864109). It just didn't match up with my stopwatch's 37 seconds. I did another test with a duration of 20 seconds according to my stopwatch. The prop sent 1625543616. Since that was under 26 seconds it got divided by 80 and came out as 23319295us - which matches with the stopwatch. Why does the propeller stop matching with the stopwatch after 26 seconds?
If I'm not making sense, just let me know. This has definitely been the worst experience I've had when trying to learn the propeller and spin.
I have to show 6 decimal places and use microseconds. Using milliseconds will limit me to 4 decimal places and that is not going to work for this project. I think what I will do is just have the propeller figure out the time and then send the microseconds to the computer. By what you're saying that's probably the only way I'll be able to get the 6 decimal places. I'll just have to redo the software. Everything will work out in the long run.
Thanks guys for your help!!
Because Spin treats longs as signed values
I did a little test:
If the delta between start and stop points is negative, adding posx does in fact give you the overshoot past 26.84354560 seconds that posx can hold. On the PC side you may want to create a floating point constant that is 2^31 / 80000000. If the result is negative, add 2^31 to it, divide by 80000000, and then add your floating point constant for 26.8 seconds.
After a cup of coffee...
Here's another crack at it that may be easier:
I tested this will a pause of 53000 (53 seconds) and it does work as expected.
After reviewing thread...
I see that Marko made this suggestion in post #7. You have [had] your answer. JonnyMac out!