From: Greg King (gngking_at_erols.com)
Date: 2004-12-13 08:38:59
From: Jim Brain; on Date: December 09, 2004, 03:19 PM -0500
>
> > Is that sign-inversion necessary? If the code to subtract the old
> > counter value from the new one is less efficient, then can't you use
> > the negative difference directly? (If it's greater than -7000, then,
> > compare it to -4096.)
>
> Dunno, let me see:
>
> void calc(unsigned int old, unsigned int new) {
> unsigned int tmp;
> if (new < old) {
> tmp=old-new;
> } else {
> tmp=new-old;
> }
> if (tmp < 7000) {
> ...
> }
> }
>
> ... Is the old code.
>
> void calc(unsigned int old, unsigned int new) {
> int tmp;
> tmp=new-old;
> if (tmp > -7000 && tmp < 7000) {
> ...
> }
> }
>
> The corner case is when the counter is at 65535 (for example), and it
> wraps, to 4095.
>
> 4095-65535 = -61440 -> (signed int) -4095 (I think...)
>
> It would seem to work, and it'd be a bit faster, but someone needs to
> check my math. I think the intermediate result would be stuffed into 16
> bits, and that would normalize to -4095, but someone needs to verify.
There are two problems with my questions:
1. I didn't know that you're writing the code in the C language. I had
assumed that you were using assembly language. (Silly me -- I should have
known it, from a previous message of yours.)
2. I had forgotten that the free-running timer-counter wraps around.
Those two revelations change everything! First, they raise a new question:
How wide is the "int" type in your micro-controller's C compiler?
In the rest of this letter, I will assume that it's 16 bits.
Second, the calc function must use "clock arithmetic" because of that
wrap-around. For example, if the old value is 65532, and the new value is
5, then the (16-bit) distance between them is 9, not +/- 65527.
Fortunately, as Spiro said, two's-complement arithmetic, working in
unsigned variables, does what you need [a signed 16-bit -65527, when cast
into (unsigned), is 9]. So, calc() should be:
void calc(unsigned int old, unsigned int new) {
unsigned int tmp;
tmp = new - old;
if (tmp < 7000 && tmp != 0) {
if (tmp < 4096) {
/* Run faster. */
...
} else if (tmp > 4096) {
/* Run slower. */
...
}
}
}
That "tmp != 0" catches the case when the counter wraps completely around
to its original value (the distance actually is 65536).
Message was sent through the cbm-hackers mailing list
Archive generated by hypermail pre-2.1.8.