Pretty basic question about constant CNT
turbosupra
Posts: 1,088
From my reading and understanding, correct me if I am wrong please ...
CNT will go 2^32 or 4294967296 and roll over every 53.6870912 seconds at 80mhz
I can correlate time to any divisor of 80mhz then, for example 1/6.67 or .15 seconds equals 12_000_000 cycles?
Is the CNT constant signed? If it is, would I have to write || CNT or write || variable := CNT ?
Part of this is that I should have a better understanding of this constant and also is that I'm trying to deal with roll over and if I convert it to milliseconds, I can go from 53.68 seconds to 49.71 days with a 2^32 register.
I'm a little confused as to why Parallax didn't make only the system CNT at 64 bit register? If my math was right, we'd go from 53 seconds to 7300 years?
Thanks for reading!
CNT will go 2^32 or 4294967296 and roll over every 53.6870912 seconds at 80mhz
I can correlate time to any divisor of 80mhz then, for example 1/6.67 or .15 seconds equals 12_000_000 cycles?
Is the CNT constant signed? If it is, would I have to write || CNT or write || variable := CNT ?
Part of this is that I should have a better understanding of this constant and also is that I'm trying to deal with roll over and if I convert it to milliseconds, I can go from 53.68 seconds to 49.71 days with a 2^32 register.
I'm a little confused as to why Parallax didn't make only the system CNT at 64 bit register? If my math was right, we'd go from 53 seconds to 7300 years?
Thanks for reading!
Comments
CNT is unsigned and you can use it for any timing up to about 50 seconds with an 80MHz system clock.
Typically, you save the current value of CNT at the beginning of a timing interval, then compute (CNT - savedCNT) to get the elapsed time in system clocks. You use CLKFREQ as a reference for computing other time units. For example, to get the elapsed time in milliseconds, you'd compute ( (CNT - savedCNT) / (CLKFREQ / 1000) )
I made an object for reading a tachometer and had difficult time with CNT.
Thanks for the more in depth explanation.
My code is still a little flakey, I will post it when it smooth.
Charlie
Simply calculating (CNT - savedCNT) / (CLKFREQ / 1000) leads to negative values after 26 seconds
if the negative sign would be eliminated by the "||"-operator I would get values that DECREASE instead of INCREASE.
SPIN treats longs as SIGNED longs. There must be a possability to get not only 26.000 milliseconds as result but 53.000 milliseconds
So how is the math done in two's complement to get the full 53-second range that the counter offers?
best regards
Stefan
But if the difference is higher then $7FFF_FFFF Spin sees the number as negativ that's why it works only up to 26 seconds with Spin.
With Assembly you can also do unsigned math.
A solution with Spin is this:
milliseconds := (CNT - savedCNT) >> 1 / (CLKFREQ/500)
The highest bit (the sign bit) is forced to zero by shifting all bits to the right. The resolution is halfed but that really not matters here.
Andy
@Stefan
I get negative values as well, somehow the math still works on my output calculations though
@BluHair
What kind of car is this?
Here is my code for others trying to do this, it includes error checking where it dumps values that have too great of a change, or are too far out of range.
Sorry if this breaks forum etiquette as far as attaching code, for some reason I cannot upload .zip files today to the forum?
You may need to change the math formula at the bottom, depending on how your ECU outputs to your tachometer.
Jon Williams has a nice object in the exchange that works flawlessly if you are simply measuring the output waveform from the PCM:
obex.parallax.com/objects/479/
Good Luck.
Post Edited (AJM) : 8/2/2010 7:46:50 PM GMT
I've had mixed results with using the || operator as well.
Does anyone have a full proof way of doing this?
This crude but you get the idea, I just tested this and get 2 sets of 0 - 2147483647 back to back. This may need to be cleaned up on the last digits.
VAR Long NewCnt
PUB GetCNT
...If CNT < 0
.....NewCNT := 2,147,483,647 - (||CNT + 1)
.....Return NewCNT
...elseIf CNT => 0
.....Return CNT
If you just need a time stamp every 52 seconds, you could scan for a certain CNT value in a loop, when the loop sees a value withing the window, then do something. In a SPIN loop you may miss a specific CNT number, so if the timing requirements can handle a little tolerance per iteration (will not accumulate an error), then you can check for a small window of time in CNT to be sure not to miss it:
If CNT > 1 AND CNT < 5000
do something
As you can see in the example above, all I do is test to see if the calculated time elapsed is <0 and if so, then just skip this measurement cycle. You can optimize the way I have coded this to reduce lines. I purposely expanded it a little to make it easier to read.
this will only work if
1. The worst case lenght of a measurement cycle is less than 50 seconds or so (Cnt Rap time)
2. You can afford to allow the time elapsed measure to skip an update every 50 seconds (Cnt Rap Time)
The prop will send a binary number to the BCD, and turn on ONE of the LED's (via the anode) for 1ms, then it will cycle to the next LED, send a different binary number to the BCD and turn that LED on for 1ms and so on ... This way I use 10 pins for my 6 LED's instead of 24.
When spin goes negative, it hoses the whole operation. One of the lines of code I tried but couldn't use because of the signed stuff is
For example, let's say you start timing with cnt at $FFFF_FFFE and end at $0000_0002. In signed math that's simple enough; $FFFF_FFFE is -2 so 2 - (-2) = 4. But with unsigned math it's 2 - 4294967294 or -4294967292. That's not what you want! But that's a signed number and you're using unsigned math; rolling has the effect of adding (or subtracting in the other direction) $1_0000_0000 to the result to get it within the limits, so -4294967292 + 4294967296 = 4. Same result!
I don't understand the asm to be perfectly honest, but I can tell you that the complement ideal does not work when I write code such as
If half of cnts cycle is a negative number, this repeat loop will not run for ~26 seconds.
So either there has to be a better way to calculate time, or a better way for me to write my loops, both of which I'm not sure how to do.
This does go negative. You should first get an understanding of what these values really are before doing the math. Print out the value 2_147_483_648 alone and you will see that SPIN considers that number to be 0. So you are really saying in that formula:
0 + (0 + CNT) which goes negative just like it always did. I posted code above that perfectly cycles from 0 to 2_147_483_647, not sure why you are changing the formula when the one posted works.
2_147_483_647 is the maximum number allowed in signed numbers with SPIN. -2_147_483_648 is the lowest. If you write 2_147_483_648 then SPIN considers it 2_147_483_647 + 1.
There are 16 counters on the Prop that are amazing at doing 32 bit counting locked to the system clock. You should take a look at the App note for the counters, they may make things easier for you.
Thanks for replying, I tried your way but didn't have success, but I will try again.
I'm getting closer with the bitwise shift operator >>, but I will try your way first.
The fact that CNT goes - completely hoses the whole thing no matter what I seem to try.
Although that may work, it still does not work within my loops
repeat while (variable + clkfreq) => (cnt >> 1)
If I want the code to do something for a second, and then update
How do you write your loops to take advantage of your newcnt?
Yes, that's pushing past the rollover without recovering properly if cnt has rolled over. The way you do it is this:
cnt - snapshotofcnt > clkfreq
That will work.
it is still not clear to me, what you want to do.
The negative cnt values are only a problem if you try to measure time intervals longer then 27 seconds (up to max. 54 seconds).
But from what you describe, I think you will just do a 1ms delay.
For that exists the waitcnt command.
So for measuring a time interval:
and for doing a 1ms delay:
Andy