Page 1 of 1

PIT ticking in wrong intervalls

Posted: Tue Dec 20, 2016 9:34 am
by cklie97
Hello there,
i have set up the PIT for tracking time. But when I check the time the values are not sane. I initialize my clock via the RTC and want to keep it with the PIT. The initialization works but the tracking is somewhere messed up.

here the code of the pit

pit.c

Code: Select all

#define BINARY_BIT 0

static bool isInit = FALSE;

static void initPit(void);
static void writePitCommand(uint8_t channel, uint8_t accessMode, uint8_t opMode);
static void writePitReload(uint8_t channel, uint16_t reloadValue, bool is16Bit);
static void initPit(void);

double getMilliPerTick(void)
{
    if (!isInit)
        initPit();
    return 4.000228;
}

static void writePitCommand(uint8_t channel, uint8_t accessMode, uint8_t opMode)
{
    uint8_t value = ((channel & 0x3) << 6) | ((accessMode & 0x3) << 4) | ((opMode) << 1) | BINARY_BIT;
    outb(0x40, value);
}

static void writePitReload(uint8_t channel, uint16_t reloadValue, bool is16Bit)
{
    channel &= 0x3;
    channel += 0x40;
    outb(channel, (reloadValue & 0xff));
    if (is16Bit)
        outb(channel, reloadValue >> 8);
}

static void initPit(void)
{
    uint16_t reloadValue = 4773;
    uint8_t opMode = 2;
    uint8_t accessMode = 3;
    uint8_t channel = 0;
    writePitCommand(channel, accessMode, opMode);
    writePitReload(channel, reloadValue, TRUE);
    isInit = TRUE;
}
I measured the timedifference between my os and the real time. The result is that my os only counted 17 seconds in a period of 143 ones.

Re: PIT ticking in wrong intervalls

Posted: Tue Dec 20, 2016 9:49 am
by Brendan
Hi,

The code looks right to me (although I calculated it as "4773 / (3579545/3) = 4.000229 ms between ticks").
cklie97 wrote:I measured the timedifference between my os and the real time. The result is that my os only counted 17 seconds in a period of 143 ones.
Where? If you measured it inside an emulator (e.g. Bochs), then you may have measured "virtual time" and not real time (and might need to figure out how to configure the emulator for "virtual time = real time").


Cheers,

Brendan

Re: PIT ticking in wrong intervalls

Posted: Thu Dec 22, 2016 4:33 am
by cklie97
I solved the problem kind of like. Th problem was that I tried to send the Commands to 0x40 instaed of 0x43.
So the programm works. But now there is something suspecious to me.

When I want to set the reloadValue to 4773 for a ~4ms tick everything works. But when I want to set it to 27

Code: Select all

    outb(0x43, 52);
    outb(0x40, 27);
    outb(0x40, 0);
the programm works wrong.

The tick period is shorter than 4ms but longer than 0.022629ms which should be the right period.

pit.c

Code: Select all

#define BINARY_BIT 0

static bool isPitInit = FALSE;
static bool isShortMode;

static void initPit(void);

double getMilliPerTick(void)
{
	if (!isPitInit)
	{
		initPit();
	}
	if (isShortMode)
		return 0.022629;
	return 4.000228;
}

void enterShortMode(bool enter)
{
        writePitCommand(0, 3, 2);
	if (!enter)
	{
		writePitReload(0, 4773, TRUE);
		isShortMode = FALSE;
	}
	else
	{
		writePitReload(0, 27, TRUE);
		isShortMode = TRUE;
	}
}

void writePitCommand(uint8_t channel, uint8_t accessMode, uint8_t opMode)
{
	uint8_t value = ((channel & 0x3) << 6) | ((accessMode & 0x3) << 4) | ((opMode) << 1) | BINARY_BIT;
	outb(0x43, value);
}

void writePitReload(uint8_t channel, uint16_t reloadValue, bool is16Bit)
{
	channel &= 0x3;
	channel += 0x40;
	outb(channel, (reloadValue & 0xff));
	if (is16Bit)
	{
		outb(channel, reloadValue >> 8);
	}
}

static void initPit(void)
{
    enterShortMode(TRUE);
    isPitInit = TRUE;
}
So when I change initPit() to enterShortMode(FALSE) the PIT does what it should but sometimes I need the shorter period.

Re: PIT ticking in wrong intervalls

Posted: Thu Dec 22, 2016 2:07 pm
by Brendan
Hi,
cklie97 wrote:When I want to set the reloadValue to 4773 for a ~4ms tick everything works. But when I want to set it to 27

Code: Select all

    outb(0x43, 52);
    outb(0x40, 27);
    outb(0x40, 0);
the programm works wrong.

The tick period is shorter than 4ms but longer than 0.022629ms which should be the right period.
Imagine a graph with reload value on the bottom (x axis) and frequency along the side (y axis). On the right hand side of this graph (large reload value, lower frequency) you'd expect a nice line that can be described by "y = (3579545/3) / x". However, at some point on the left hand side of the graph (smaller reload value, higher frequency) you'll reach a point where the frequency is higher than the hardware and OS can handle, where the graph becomes more like "y = k".

Essentially, that graph might look something like:

Code: Select all

    |  :
    |  :
    |XX:
  F |  X:
  r |   X    
  e |   X      
  q |    X      
    |     X
    |      XXX
    |         XXXXXX
    |_______________XXXXX
          Count
The point where the frequency is higher than the hardware and OS can handle depends on many things - how fast CPU is, how much the IRQ handler does, how long the OS disables IRQs (for worst case), how many IRQs per second the PIC chip can handle, etc. What happens beyond that point is that you simply miss IRQs. At "x = k - 0.00001" (the point where it's only a tiny bit faster than hardware and OS can handle) you might miss one IRQ each minute. At "x = k/4" for every 4 IRQs that the PIT chip sends you might only receive/handle one of them.

For conservative/safe values, assuming the OS doesn't disable IRQs for too long, on old CPUs (e.g. CPU clock speed < 1 GHz) I wouldn't want to go faster than maybe 1 KHz (or 1000 us between IRQs, or "reload value = 1193"). For new computers I wouldn't go faster than about 8 KHz (125 us between IRQs, "reload value = 149").

Note that (during boot) I typically do a crude benchmark to estimate how fast CPUs are and adjust various timing related things based on that CPU speed estimate; so that on slower computers you'd get less IRQs per second (and less precise "time elapsed" tracking), and less task switches per second.

Anyway; I suspect that the problem you're having is just "PIT too fast" - 44 KHz is about 5 times faster than I'd consider safe.


Cheers,

Brendan

Re: PIT ticking in wrong intervalls

Posted: Fri Dec 23, 2016 3:37 am
by cklie97
Brendan wrote: For conservative/safe values, assuming the OS doesn't disable IRQs for too long, on old CPUs (e.g. CPU clock speed < 1 GHz) I wouldn't want to go faster than maybe 1 KHz (or 1000 us between IRQs, or "reload value = 1193"). For new computers I wouldn't go faster than about 8 KHz (125 us between IRQs, "reload value = 149").
Thanks that solved my problem.