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 | edit source]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 | edit source]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