x86 Assembly/Programmable Interval Timer

The Programmable Interval Timer (PIT) is an essential component of modern computers, especially in a multi-tasking environment. The PIT chip can be made ‒ by setting various register values ‒ to count up or down, at certain rates, and to trigger interrupts at certain times. The timer can be set into a cyclic mode, so that when it triggers it automatically starts counting again, or it can be set into a one-time-only countdown mode.

On newer hardware, a HPET (High Precision Event Timer), which is an evolution of the PIT concept, is likely to be available.

Function

edit

The PIT contains a crystal oscillator which emits a signal 1193182 hz. This output frequency is divided by three different values to provide three output channels to the CPU. Channel 0 is used as a system timer by most operating systems. Channel 1 was used to refresh the DRAM, but is no longer used and may not even be accessible. Channel 2 is used to control the PC speaker. Of these, channel 0 is the most frequently encountered.

To make the PIT fire at a certain frequency f, you need to figure out an integer x, such that 1193182 / x = f. This is a trivially solved problem which results in the formula:

x = 1193182 / f

How this division actually works is that each divisor is saved in an internal register. On every clock pulse, the register is decremented. Only when it reaches 0 is the clock pulse allowed to continue on to the CPU. Higher divisors result in lower frequencies, and vice versa.

Note that because the divisor is 16 bits, and a value of 0 is interpreted as 65536, there are limits on the producible frequencies:

max = 1193182 / 1 = 1193182 hz
min = 1193182 / 65536 ≈ 18.2065 hz

This final value is also the resolution of the frequency, that is, each consecutive possible frequency differs by 18.2065 hz.

Programming

edit

The PIT is accessed via four ports, three for the three channels and one for commands:

Channel 0 0x40
Channel 1 0x41
Channel 2 0x42
Command 0x43

One commonly performed task is setting the frequency of the channel 0, the system timer. If a frequency of 100 hz is desired, we see that the necessary divisor is 1193182 / 100 = 11931. This value must be sent to the PIT split into a high and low byte.

mov al, 0x36
out 0x43, al    ;tell the PIT which channel we're setting

mov ax, 11931
out 0x40, al    ;send low byte
mov al, ah
out 0x40, al    ;send high byte