Clock cycle overhead in DEBUG; hamster wheel counter revisited
Archiver
Posts: 46,084
All,
This is a somewhat long post, so please bear with me ...
I've been using the BS2 to measure our hamster's output for a few
weeks now, and I've graduated to using it to count wheel revolutions
when I use my bicycle trainer indoors as well.
I've run across an interesting calibration issue, which I believe is
related to the overhead (in terms of BS2 clock cycles) taken up by
using a DEBUG statement.
I wanted to count individual revolutions of the wheel, vice averaging
over an interval using COUNT. So, I wrote a "state processor" that
counts clock cycles while waiting for the signal that the wheel has
come around again (code below).
Briefly, the hardware setup is: the wheel has a magnet on it that
closes a reed switch (bicycle speed sensor) once per revolution. I've
wired the relevant stamp pin to be high until the reed switch closes,
at which time it goes to ground. My "state processor" looks for
transitions from low to high, and when it gets them, it writes out the
number of times a loop counter incremented whilst waiting.
So, in order to get real time, I've had to "calibrate" the loop
counter. What I did was let the wheel spin for a long time (couple of
minutes), then found the total number of cycles counted for that time
period, and divide the two. In effect, my loop counter increments
approximately every 4 milliseconds.
However, my loop counter doesn't take into account the time taken to
write out the result of the count via DEBUG.
I've discovered that my calibration is different in the bicycle
application (one revolution every 0.2 seconds at about 23 MPH) than it
is for the hamster application (one revolution every 0.6 seconds,
roughly).
The former calibration constant is 4.18 ms, while the latter is 4.02
ms. The difference is only a couple of percent, so it's not a big deal
... and in any case, as long as I use the right constant, it doesn't
really matter. It does give a small effect on the bike, as the speed
can vary by nearly a factor of 2 between warmup and workout pace.
So, here's the question: can anybody improve the code below so that it
takes into account the time required to DEBUG? I'm a novice at this
PBASIC stuff ...
Thanks,
Michael
'{$STAMP BS2}
InputPin VAR IN0
myCount VAR Word
oldState VAR Word
curState VAR Word
LookForStart:
IF InputPin = 0 THEN BeginCount
' DEBUG CLS , "Looking for Start" , CR
GOTO LookForStart
ProcessStates:
curState = InputPin
IF curState = 0 AND oldState = 0 THEN doMyCount
IF curState = 1 AND oldState = 0 THEN doMyCount
IF curState = 0 AND oldState = 1 THEN ReportAndBeginCount
IF curState = 1 AND oldState = 1 THEN doMyCount
oldState=curState
GOTO ProcessStates
doMyCount:
myCount=myCount+1
oldState=curState
IF myCount > 3000 THEN LookForStart 'Wheel hasn't moved in about 12
seconds ...
GOTO ProcessStates
ReportAndBeginCount:
DEBUG "DATA," , DEC myCount , CR
myCount = 0
oldState=curState
GOTO ProcessStates
BeginCount:
myCount=0
oldState=0
GOTO ProcessStates
END
This is a somewhat long post, so please bear with me ...
I've been using the BS2 to measure our hamster's output for a few
weeks now, and I've graduated to using it to count wheel revolutions
when I use my bicycle trainer indoors as well.
I've run across an interesting calibration issue, which I believe is
related to the overhead (in terms of BS2 clock cycles) taken up by
using a DEBUG statement.
I wanted to count individual revolutions of the wheel, vice averaging
over an interval using COUNT. So, I wrote a "state processor" that
counts clock cycles while waiting for the signal that the wheel has
come around again (code below).
Briefly, the hardware setup is: the wheel has a magnet on it that
closes a reed switch (bicycle speed sensor) once per revolution. I've
wired the relevant stamp pin to be high until the reed switch closes,
at which time it goes to ground. My "state processor" looks for
transitions from low to high, and when it gets them, it writes out the
number of times a loop counter incremented whilst waiting.
So, in order to get real time, I've had to "calibrate" the loop
counter. What I did was let the wheel spin for a long time (couple of
minutes), then found the total number of cycles counted for that time
period, and divide the two. In effect, my loop counter increments
approximately every 4 milliseconds.
However, my loop counter doesn't take into account the time taken to
write out the result of the count via DEBUG.
I've discovered that my calibration is different in the bicycle
application (one revolution every 0.2 seconds at about 23 MPH) than it
is for the hamster application (one revolution every 0.6 seconds,
roughly).
The former calibration constant is 4.18 ms, while the latter is 4.02
ms. The difference is only a couple of percent, so it's not a big deal
... and in any case, as long as I use the right constant, it doesn't
really matter. It does give a small effect on the bike, as the speed
can vary by nearly a factor of 2 between warmup and workout pace.
So, here's the question: can anybody improve the code below so that it
takes into account the time required to DEBUG? I'm a novice at this
PBASIC stuff ...
Thanks,
Michael
'{$STAMP BS2}
InputPin VAR IN0
myCount VAR Word
oldState VAR Word
curState VAR Word
LookForStart:
IF InputPin = 0 THEN BeginCount
' DEBUG CLS , "Looking for Start" , CR
GOTO LookForStart
ProcessStates:
curState = InputPin
IF curState = 0 AND oldState = 0 THEN doMyCount
IF curState = 1 AND oldState = 0 THEN doMyCount
IF curState = 0 AND oldState = 1 THEN ReportAndBeginCount
IF curState = 1 AND oldState = 1 THEN doMyCount
oldState=curState
GOTO ProcessStates
doMyCount:
myCount=myCount+1
oldState=curState
IF myCount > 3000 THEN LookForStart 'Wheel hasn't moved in about 12
seconds ...
GOTO ProcessStates
ReportAndBeginCount:
DEBUG "DATA," , DEC myCount , CR
myCount = 0
oldState=curState
GOTO ProcessStates
BeginCount:
myCount=0
oldState=0
GOTO ProcessStates
END
Comments
The debug command will take different amounts of time depending on
how many characters it has to transmit, so transmitting 50 takes less
time than 150.
> DEBUG "DATA," , DEC myCount , CR
That could account for some of the difference. One way to avoid this
is to use this form:
DEBUG "DATA," , DEC3 myCount , CR
which would "050" or "150" in the same amount of time.
More important though, I think, the calibration formula should be, y
= a * x + b, instead of simply y = a * x. The offset b is the time
it takes to run the DEBUG statement as well as all the other overhead
that takes place outside the main counting loop. If you assume b=0
when you calibrate, that is going to change your apparent calibration
constant for the bike vs the hamster wheel. So to find b you have to
estimate the time taken by the routine, "ReportAndBeginCount:"
One alternative is to count every other cycle of the wheel, and do
the DEBUG in the skipped cycle. That would take the overhead "b" out
of the loop.
There are a lot of little factors that can affect the speed of a
stamp program. Not the least of these is variation from Stamp to
Stamp in the resonator frequency. That can vary by a couple of %.
That is not a factor if you are using the same stamp for both
projects. Also, there are little effects in code. For example, if
you replace the number 3000 with the number 4096, the loop will run
faster, because the Stamp stores the powers of 2 in the eeprom in a
particularly efficient way.
I hope some of that helps,
-- Tracy
>All,
>
>This is a somewhat long post, so please bear with me ...
>
>I've been using the BS2 to measure our hamster's output for a few
>weeks now, and I've graduated to using it to count wheel revolutions
>when I use my bicycle trainer indoors as well.
>
>I've run across an interesting calibration issue, which I believe is
>related to the overhead (in terms of BS2 clock cycles) taken up by
>using a DEBUG statement.
>
>I wanted to count individual revolutions of the wheel, vice averaging
>over an interval using COUNT. So, I wrote a "state processor" that
>counts clock cycles while waiting for the signal that the wheel has
>come around again (code below).
>
>Briefly, the hardware setup is: the wheel has a magnet on it that
>closes a reed switch (bicycle speed sensor) once per revolution. I've
>wired the relevant stamp pin to be high until the reed switch closes,
>at which time it goes to ground. My "state processor" looks for
>transitions from low to high, and when it gets them, it writes out the
>number of times a loop counter incremented whilst waiting.
>
>So, in order to get real time, I've had to "calibrate" the loop
>counter. What I did was let the wheel spin for a long time (couple of
>minutes), then found the total number of cycles counted for that time
>period, and divide the two. In effect, my loop counter increments
>approximately every 4 milliseconds.
>
>However, my loop counter doesn't take into account the time taken to
>write out the result of the count via DEBUG.
>
>I've discovered that my calibration is different in the bicycle
>application (one revolution every 0.2 seconds at about 23 MPH) than it
>is for the hamster application (one revolution every 0.6 seconds,
>roughly).
>
>The former calibration constant is 4.18 ms, while the latter is 4.02
>ms. The difference is only a couple of percent, so it's not a big deal
>... and in any case, as long as I use the right constant, it doesn't
>really matter. It does give a small effect on the bike, as the speed
>can vary by nearly a factor of 2 between warmup and workout pace.
>
>So, here's the question: can anybody improve the code below so that it
>takes into account the time required to DEBUG? I'm a novice at this
>PBASIC stuff ...
>
>Thanks,
>Michael
>
>'{$STAMP BS2}
>
>
>InputPin VAR IN0
>myCount VAR Word
>oldState VAR Word
>curState VAR Word
>
>LookForStart:
> IF InputPin = 0 THEN BeginCount
>' DEBUG CLS , "Looking for Start" , CR
>GOTO LookForStart
>
>ProcessStates:
> curState = InputPin
> IF curState = 0 AND oldState = 0 THEN doMyCount
> IF curState = 1 AND oldState = 0 THEN doMyCount
> IF curState = 0 AND oldState = 1 THEN ReportAndBeginCount
> IF curState = 1 AND oldState = 1 THEN doMyCount
> oldState=curState
>GOTO ProcessStates
>
>doMyCount:
> myCount=myCount+1
> oldState=curState
> IF myCount > 3000 THEN LookForStart 'Wheel hasn't moved in about 12
>seconds ...
>GOTO ProcessStates
>
>ReportAndBeginCount:
> DEBUG "DATA," , DEC myCount , CR
> myCount = 0
> oldState=curState
>GOTO ProcessStates
>
>BeginCount:
> myCount=0
> oldState=0
>GOTO ProcessStates
>
>
>END
>
>
>
>To UNSUBSCRIBE, just send mail to:
> basicstamps-unsubscribe@yahoogroups.com
>from the same email address that you subscribed. Text in the
>Subject and Body of the message will be ignored.
>
>
>Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/