X86 Assembly/Programmable Interval Timer

From Wikibooks, open books for an open world
< X86 Assembly
Jump to: navigation, search

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 accessable. 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 11931820 / 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
out 0x40, ah    ;send high byte