# Re: Problem with kernel-pll in 2.0.3x (at least)

Rogier Wolff (R.E.Wolff@BitWizard.nl)
Mon, 4 May 1998 11:09:38 +0200 (MET DST)

Ulrich Windl wrote:
>
> # Using 1024 Hz as interrupt frequency the following is true:
> # Using 976us as tick you'll have 999424us per second, and 576us error
> # Using 977us as tick you'll have 1000448us per second, and 448us error
> # Using 976us and 977us every second tick, you'll have 999936us per second,
> # and 64us error
> # Using 976us and 977us every second tick, plus 978 every 16th tick, you'll
> # have no error (while your time is still quite steady)! 8-)

Hi,

Your method depends on HZ being 1024. It is ad-hoc. We might want this
because it happens so often, but I personally perfer a general solution.

Below is a code snippet that uses fixed-point arithmetic to calculate
tick much more accurately (10 bits behind the binary point). For 1
million microseconds in a second and 1024 ticks per second, that
yields exactly 0 error.

But if you happen to have 555 (*) ticks per second, it will be much
more accurate than the older algorithm (in fact one 40th of a
microsecond per second of systematic error is quite acceptable don't
you think? The old system yielded 110 microseconds of error per
second. ;-).

(*) The 555 is completely arbitrary. I just banged on my keyboard to
get an example number that doesn't divide evenly.

As the final code is slightly more complicated than the standard

time += tick;

you could make this code conditional on:

#if HZ * (1000000/HZ) != 1000000
/* #warning "HZ doesn't divide." */
#define USE_FP_TICK
#else
#define USE_SIMPLE_TICK
/* #warning "HZ DOES divide." */
#endif

/* Code snippet: */

#include <stdio.h>

#define HZ 1024

#define FP_SHIFT 10
#define FRAC_BITS 0x3ff

int main (int argc, char **argv)
{
long tick;
int residual, tick_of_the_day;
int i;
int time;

residual = time = 0;

/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
tick = ((1000000 << FP_SHIFT) + HZ/2) / HZ;
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

for (i=0;i < HZ;i++) {

/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
residual += tick;
tick_of_the_day = residual >> FP_SHIFT;
residual &= FRAC_BITS;
time += tick_of_the_day;
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

printf ("%d %d %d\n", time, tick_of_the_day, residual);
}
exit (0);
}

I'm willing to prepare a patch if Linus says he'll include it in the
kernel.

Roger.

P.S. Having had a look at the kernel code: A similar thing is being
done with time_adj. It could be initialized to 1000000 - HZ * tick.
That would make time move a little more jerky, but have the same
effect. (yeah, you also have to add this in every time an assignment
is made to this variable. I think this modifies the "bandwidth" of
```--