Measuring time it takes to execute code for accuracy
ryfitzger227
Posts: 99
I'm creating a timer for a project that I'm working on and I need it to be as accurate as it can be. The resolution is 1uS.
All I'm trying to do is figure out all of my overhead and then subtract that from the final clock cycles. That way I don't have the time it takes to execute the code into my elapsed time.
Here's my code:
What's a good way to go about this? (Especially with all the repeat until.. loops).
Another thing. If I find out my overhead will that ever change or will it always be the same? For example if i set my overhead to 2500 clock cycles and subtract that from the final clock cycles elapsed time will it always be 2500 clock cycles or could that change? If so, depending on what?
Thanks for your help.
All I'm trying to do is figure out all of my overhead and then subtract that from the final clock cycles. That way I don't have the time it takes to execute the code into my elapsed time.
Here's my code:
PUB main(tadr, tstart, tstop, readyadr, stopadr) : ticks ticks := cnt repeat repeat until ina[tstart] == 1 and BYTE[readyadr] == 1 repeat until ina[tstart] == 0 ticks := cnt repeat until ina[tstop] == 1 or BYTE[stopadr] == 1 repeat until ina[tstop] == 0 or BYTE[stopadr] == 1 LONG[tadr] := cnt - ticks if BYTE[stopadr] == 1 BYTE[stopadr] := 0 BYTE[readyadr] := 0
What's a good way to go about this? (Especially with all the repeat until.. loops).
Another thing. If I find out my overhead will that ever change or will it always be the same? For example if i set my overhead to 2500 clock cycles and subtract that from the final clock cycles elapsed time will it always be 2500 clock cycles or could that change? If so, depending on what?
Thanks for your help.
Comments
It will if you edit the code , so usually it is best to avoid such skew situations.
Simple ways to do this are
* make the capture lines as identical as you can
* sometimes even the same line can be re-used by applying an index.
You can use WAITPEQ/WAITPNE commands, they are very precise, but do not allow the test for abort per
BYTE[stopadr].
Here is a possible code: If you really need the abort while waiting for ina[tstop]==0 then you can do that with a free pin which you incorporate into the mask at WAITPNE.
Andy
Andy,
I don't quite understand what you're saying. I found the following link http://www.parallax.com/portals/0/help/P8X32A/QnaMobile/Advanced/Content/CodeTeqTopics/CodeExeTime.htm and used the system timer method to calculate the time it took to execute each repeat block. Basically I commented out everything but the line of code I was trying to calculate then used the system timer to calculate the time it took. It took some time to calculate the time so I subtracted 368 clock cycles (the time it took to execute the "calculation code"). It came up with about 1842 clock cycles for all of the repeat until block (besides the one without the or/and in it). Now I just subtract 6944 clock cycles from the final result.
I did that correctly, right?
And I can't put the stopt variable somewhere else, the value comes from the serial port.
- Ryan
It is not just the path delay you need to consider but also the granularity,
Andy says this line
repeat until ina[tstop] == 0 or BYTE[stopadr] == 1
need ~ 10us, so that is how often it checks a pin, which limits your time-lsb-precision.
If your serial cog that writes to [stopadr] is changed to instead set/clr a spare pin, then you can sense two (pin) flags in a single WAITPNE opcode, and it will exit on either the Stop, or the sampled pin. ( Granularity on a WAITPNE opcode, is 12.5ns )
You may be able to combine Ready and Stop ?
Lets say that it takes 10us to check the pin. Well will that vary?
I'm worried about accuracy to an extent. I don't want it to be off by a couple milliseconds or so, but 10 us really isn't a problem. I can't have the time it takes to check a pin to vary. Everyone will be timed using the same timer, so it doesn't matter if it's off 10us EVERY time.
I hope that makes sense.
- Ryan
repeat until ina[pin]==0 takes 12 us and with two tests: repeat until ina[pin]==0 or byte[xy] > 0 it takes 24us.
Yes, the time will vary, that's the problem. Spin polls the pin every 24us, one time the change of the pin state happens right before the poll, another time it happens just after the poll and it needs one loop more to detect the change. So the time between pin change and detection can vary from 0 to 24us.
And you can not compensate this with subtracting a constant value from the measured time, the problem is that the variation occures at the begin and the end pulse, and both vary differently.
To make it precise you need to poll faster and that is what WAITPNE makes, it polls with 12.5 ns! If the code after WAITPNE is similar for start and stop pulse then you don't need to subtract an "overhead" the delay is the same and compensates itself.
Andy
Sorry for all of the stupid questions, but I think I got it now.
I took the code you gave me and modified it a little bit to make it work. What I'll do about the stop variable is that the cog that reads the serial port will set a pin high when the serial input says to do so. Jmg said that I could use waitpne to watch both pins (the start or stop infrared input AND the manual stop timer pin). How would I do that with waitpne?
Here's the code I have so far. I added some comments to better understand what everything does.
Thanks for everyone's help so far!
Waitpne works like that:
WAITPNE(pinstates, pinmask, 0) is a fast version of: REPEAT UNTIL (INA & pinmask) <> pinstates
so it reads the input pins and sets all pins that are not 1 in the mask to 0. This value is compared to the state.
The mask says what pins to check, the state says what the state of the checked pins should be (WAITPEQ) or not be (WAITPNE).
So this is your code with an additional check for a "manstop" pin: And here a little description of how it checks the pins. To make it simple pin0 is the manstop and pin1 is the tstart pin:
Andy
First off. Sorry for reviving an old thread. I'm starting to work on another part of this project. This time I'm trying to get it to stop until BOTH pins 1 and 3 equal 1. Not or - like before - but both pins. I tried using waitpne, but couldn't get it working so I used waitpeq.. That worked. I really just wanted to know if waitpeq polled differently that waitpne. You mentioned earlier that waitpne polled in 12.5ns, so is that true also for waitpeq? If not, how can I make the below code to work for waitpne?
I've done some extensive reading in waitpeq/waitpne and other spin elements. So maybe I won't be asking too many stupid questions from now on.
Thanks for all of your help on this!
- Ryan
You can not always achieve the same result with WAITPNE and WAITPEQ otherwise they would not both exist. If you check 2 pins as in your case here, then there are 4 possible states. With WAITPEQ you check for one state out of 4, with WAITPNE you check for 3 states out of 4 (= all but one state).
Andy
Ideally, this should all be done on one Cog in PASM to get that fast. Whenever you have to refer to Hubram, you create a degree of uncertainty about the delay timing.
Earlier this year, I got deeply involved with a stepper motor program that used increments of small delays from a look up table. Delay timings varied from 1 to 999 increments.
I used pfth, which is Dave Hein's Forth, and have gotten down to about 35 usec delays with reliable results every time to the exact clock count. But I could not get lower than that because of the overhead of the Forth dictionary calls.
I strongly suspect that Spin is slower than Forth and that C would also be slower than Forth.
To get a good 1 usec timing routine in PASM, you would have to account for the clock cycles of each instruction in the the code. Most are 4 clock cycles, but branches can be either 4 or 8 and have to be coded to the longer jumps are not affecting the timing.