Programmable Interval Timer: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
No edit summary
m Spelling, (retriggerable and prescaler are not words... should it be fixed?)
Line 1: Line 1:
The '''Programmable Interval Timer''' ('''PIT''') chip (also called 8253/8254 chip) basically consists of an oscillator, a prescaler and 3 independant frequency dividers. Each frequency divider has an output, which is used to allow the timer to control external circuitry (for example, IRQ 0).
The '''Programmable Interval Timer''' ('''PIT''') chip (also called 8253/8254 chip) basically consists of an oscillator, a prescaler and 3 independent frequency dividers. Each frequency divider has an output, which is used to allow the timer to control external circuitry (for example, IRQ 0).




Line 6: Line 6:
The oscillator used by the PIT chip runs at (roughly) 1.193182 MHz. The reason for this requires a trip back into history (to the latter half of the 1970's)...
The oscillator used by the PIT chip runs at (roughly) 1.193182 MHz. The reason for this requires a trip back into history (to the latter half of the 1970's)...


The original PC used a single "base oscillator" to generate a frequency of 14.31818 MHz because this frequency was commonly used in television circuitry at the time. This base frequency was divided by 3 to give a frequency of 4.77272666 MHz that was used by the CPU, and divided by 4 to give a frequency of 3.579545 MHz that was used by the CGA video controller. By logically ANDing these signals together a frequency equivelent to the base frequency divided by 12 was created. This frequency is 1.1931816666 MHz (where the 6666 part is recurring). At the time it was a brilliant method of reducing costs, as the 14.31818 MHz oscillator was cheap due to mass production and it was cheaper to derive the other frequencies from this than to have several oscillators. In modern computers, where the cost of electronics is much less, and the CPU and video run at much higher frequencies the PIT lives on as a reminder of "the good ole' days".
The original PC used a single "base oscillator" to generate a frequency of 14.31818 MHz because this frequency was commonly used in television circuitry at the time. This base frequency was divided by 3 to give a frequency of 4.77272666 MHz that was used by the CPU, and divided by 4 to give a frequency of 3.579545 MHz that was used by the CGA video controller. By logically ANDing these signals together a frequency equivalent to the base frequency divided by 12 was created. This frequency is 1.1931816666 MHz (where the 6666 part is recurring). At the time it was a brilliant method of reducing costs, as the 14.31818 MHz oscillator was cheap due to mass production and it was cheaper to derive the other frequencies from this than to have several oscillators. In modern computers, where the cost of electronics is much less, and the CPU and video run at much higher frequencies the PIT lives on as a reminder of "the good ole' days".


=== Frequency Dividers ===
=== Frequency Dividers ===
Line 12: Line 12:
The basic principle of a frequency divider is to divide one frequency to obtain a slower frequency. This is typically done by using a counter. Each "pulse" from the input frequency causes the counter to be decreased, and when that counter has reached zero a pulse is generated on the output and the counter is reset. For example, if the input signal is 200 Hz and the counter is reset to a value of ten each time, then the output frequency would be 200/10, or 20 Hz.
The basic principle of a frequency divider is to divide one frequency to obtain a slower frequency. This is typically done by using a counter. Each "pulse" from the input frequency causes the counter to be decreased, and when that counter has reached zero a pulse is generated on the output and the counter is reset. For example, if the input signal is 200 Hz and the counter is reset to a value of ten each time, then the output frequency would be 200/10, or 20 Hz.


The PIT chip has three seperate frequency dividers (or 3 seperate channels) that are programmable, in that the count is set by software. Each channel also allows the action to be taken when the counter reaches zero to be set by software. In this way, each channel can be used in one of several "modes" - for example, as a frequency divider (where the count is automatically reset) or as a "one shot" timer (where the count isn't automatically reset).
The PIT chip has three separate frequency dividers (or 3 separate channels) that are programmable, in that the count is set by software. Each channel also allows the action to be taken when the counter reaches zero to be set by software. In this way, each channel can be used in one of several "modes" - for example, as a frequency divider (where the count is automatically reset) or as a "one shot" timer (where the count isn't automatically reset).


Each PIT channel also has a "gate input" pin which can be used to control whether the input signal gets to the channel or not. For most of the PIT channels the associated gate input pin is not connected to anything (except for PIT channel 2).
Each PIT channel also has a "gate input" pin which can be used to control whether the input signal gets to the channel or not. For most of the PIT channels the associated gate input pin is not connected to anything (except for PIT channel 2).
Line 32: Line 32:
The output for PIT channel 1 was once used (in conjunction with the DMA controller's channel 0) for refreshing the DRAM (Dynamic Random Access Memory) or RAM. Typically, each bit in RAM consists of a capacitor which holds a tiny charge representing the state of that bit, however (due to leakage) these capacitors need to be "refreshed" periodically so that they don't forget their state.
The output for PIT channel 1 was once used (in conjunction with the DMA controller's channel 0) for refreshing the DRAM (Dynamic Random Access Memory) or RAM. Typically, each bit in RAM consists of a capacitor which holds a tiny charge representing the state of that bit, however (due to leakage) these capacitors need to be "refreshed" periodically so that they don't forget their state.


On the AT and later machines, the DRAM refresh is done with dedicated hardware and the PIT (and DMA controller) is no longer used. On modern computers where the functionality of the PIT is implemented in a large scale intergrated circuit, PIT channel 1 is no longer usable and may not be implemented at all.
On the AT and later machines, the DRAM refresh is done with dedicated hardware and the PIT (and DMA controller) is no longer used. On modern computers where the functionality of the PIT is implemented in a large scale integrated circuit, PIT channel 1 is no longer usable and may not be implemented at all.


==== Channel 2 ====
==== Channel 2 ====
Line 78: Line 78:
The "Access Mode" bits tell the PIT what access mode you wish to use for the selected channel, and also specify the "counter latch" command to the CTC (more on the "counter latch" command latter). These bits must be valid on every write to the mode/command register. For the "read back" command (also discussed later), these bits have a different meaning. For the remaining combinations, these bits specify what order data will be read and written to the data port for the associated PIT channel. Because the data port uses an 8 bit I/O port, the PIT chip needs to know what what each read or write to the data port wants. For "lobyte only", only the lowest 8 bits of the counter value is read or written to/from the data port. For "hibyte only", only the highest 8 bits of the counter value is read or written. For the "lobyte/hibyte" mode, 16 bits are transfered at the same time, with the lowest 8 bits followed by the highest 8 bits.
The "Access Mode" bits tell the PIT what access mode you wish to use for the selected channel, and also specify the "counter latch" command to the CTC (more on the "counter latch" command latter). These bits must be valid on every write to the mode/command register. For the "read back" command (also discussed later), these bits have a different meaning. For the remaining combinations, these bits specify what order data will be read and written to the data port for the associated PIT channel. Because the data port uses an 8 bit I/O port, the PIT chip needs to know what what each read or write to the data port wants. For "lobyte only", only the lowest 8 bits of the counter value is read or written to/from the data port. For "hibyte only", only the highest 8 bits of the counter value is read or written. For the "lobyte/hibyte" mode, 16 bits are transfered at the same time, with the lowest 8 bits followed by the highest 8 bits.


The "Operating Mode" bits specify which mode the selected PIT channel should operate in. For the "read back" command and the "counter latch" command, these bits have different meanings (see the information corresponding to these commands below). There are 6 different operating modes. Each operating mode will be discussed seperately later.
The "Operating Mode" bits specify which mode the selected PIT channel should operate in. For the "read back" command and the "counter latch" command, these bits have different meanings (see the information corresponding to these commands below). There are 6 different operating modes. Each operating mode will be discussed separately later.


The "BCD/Binary" bit determines if the PIT channel will operate in binary mode or BCD mode (where each 4 bits of the counter represent a decimal digit, and the counter holds values from '0000' to '9999'). 80x86 PCs don't use binary mode (BCD mode is ugly and limits the range of counts/frequencies possible). Although it should still be possible to use BCD mode, it may not work properly on some "compatible" chips. For the "read back" command and the "counter latch" command, this bit has different meanings (see the information corresponding to these commands below).
The "BCD/Binary" bit determines if the PIT channel will operate in binary mode or BCD mode (where each 4 bits of the counter represent a decimal digit, and the counter holds values from '0000' to '9999'). 80x86 PCs don't use binary mode (BCD mode is ugly and limits the range of counts/frequencies possible). Although it should still be possible to use BCD mode, it may not work properly on some "compatible" chips. For the "read back" command and the "counter latch" command, this bit has different meanings (see the information corresponding to these commands below).
Line 140: Line 140:


For odd reload values, the current count is always set to one less than the reload value.
For odd reload values, the current count is always set to one less than the reload value.
If the output of the flip flop is low when the current count decrements from two to zero it will behave the same as the equivelent even reload value. However, if the output of the flip flop is high the reload will be delayed for one input signal cycle (0.8381 uS), which causes the "high" pulse to be slightly longer and the duty cycle will not be exactly 50%. Because the reload value is rounded down to the nearest even number anyway, I'd recommend that only even reload values be used.
If the output of the flip flop is low when the current count decrements from two to zero it will behave the same as the equivalent even reload value. However, if the output of the flip flop is high the reload will be delayed for one input signal cycle (0.8381 uS), which causes the "high" pulse to be slightly longer and the duty cycle will not be exactly 50%. Because the reload value is rounded down to the nearest even number anyway, I'd recommend that only even reload values be used.


If the gate input goes low, counting stops and the output goes high immediately. Once the gate input has returned high, the next falling edge on input signal will cause the current count to be set to the reload value and operation will continue (with the output left high).
If the gate input goes low, counting stops and the output goes high immediately. Once the gate input has returned high, the next falling edge on input signal will cause the current count to be set to the reload value and operation will continue (with the output left high).
Line 176: Line 176:
To prevent the current count from being updated, it is possible to "latch" a PIT channel using the latch command. To do this, send the value CC000000 (in binary) to the mode/command register (I/O port 0x43), where 'CC' corresponds to the channel number. When the latch command has been sent, the current count is copied into an internal "latch register" which can then be read via. the data port corresponding to the selected channel (I/O ports 0x40 to 0x42). The value kept in the latch register remains the same until it has been fully read, or until a new mode/command register is written.
To prevent the current count from being updated, it is possible to "latch" a PIT channel using the latch command. To do this, send the value CC000000 (in binary) to the mode/command register (I/O port 0x43), where 'CC' corresponds to the channel number. When the latch command has been sent, the current count is copied into an internal "latch register" which can then be read via. the data port corresponding to the selected channel (I/O ports 0x40 to 0x42). The value kept in the latch register remains the same until it has been fully read, or until a new mode/command register is written.


The main benefit of the latch command is that it allows both bytes of the current count to be read without inconsistancies. For example, if you didn't use the latch command, then the current count may be decrease from 0x0200 to 0x01FF after you've read the low byte but before you've read the high byte, so that your software thinks the counter was 0x0100.instead of 0x0200 (or 0x01FF).
The main benefit of the latch command is that it allows both bytes of the current count to be read without inconsistencies. For example, if you didn't use the latch command, then the current count may be decrease from 0x0200 to 0x01FF after you've read the low byte but before you've read the high byte, so that your software thinks the counter was 0x0100.instead of 0x0200 (or 0x01FF).


While the latch command should not effect the current count, on some (old/dodgy) motherboards sending the latch command can cause a cycle of the input signal to be occasionally missed, which would cause the current count to be decremented 0.8381 uS later than it should be. If you're sending the latch command often this could cause accuracy problems (but IMHO if you need to send the latch command often you may wish to consider redesigning your code anyway).
While the latch command should not effect the current count, on some (old/dodgy) motherboards sending the latch command can cause a cycle of the input signal to be occasionally missed, which would cause the current count to be decremented 0.8381 uS later than it should be. If you're sending the latch command often this could cause accuracy problems (but IMHO if you need to send the latch command often you may wish to consider redesigning your code anyway).
Line 195: Line 195:
0 Reserved (should be clear)
0 Reserved (should be clear)


Note: Be carefull with bits 4 and 5 - they are inverted.
Note: Be careful with bits 4 and 5 - they are inverted.


Bits 1 to 3 of the read back command select which PIT channels are effected, and allow multiple channels to be selected at the same time.
Bits 1 to 3 of the read back command select which PIT channels are effected, and allow multiple channels to be selected at the same time.
Line 226: Line 226:
0 BCD/Binary mode: 0 = 16-bit binary, 1 = four-digit BCD
0 BCD/Binary mode: 0 = 16-bit binary, 1 = four-digit BCD


The bottom six bits return the values that where programmed into the mode/command register when the channel was last initialised.
The bottom six bits return the values that where programmed into the mode/command register when the channel was last initialized.


Bit 7 indicates the state of the PIT channel's output pin at the moment that the read-back command was issued.
Bit 7 indicates the state of the PIT channel's output pin at the moment that the read-back command was issued.
Line 273: Line 273:
To complete this page I've to included the following example code. This code was written for NASM, but hasn't been tested.
To complete this page I've to included the following example code. This code was written for NASM, but hasn't been tested.


The idea is to provide a single routine to initialize PIT channel 0 for any (possible) frequency and use IRQ 0 to accurately keep track of real time in milli-seconds since the PIT was configured.
The idea is to provide a single routine to initialize PIT channel 0 for any (possible) frequency and use IRQ 0 to accurately keep track of real time in milliseconds since the PIT was configured.


For the sake of accuracy, the initialization code will calculate the number of whole milli-seconds to add to the "system timer tick" each IRQ, and the number of "fractions of a milli-second" to avoid drift. This may be important, for example if the PIT is set for 700 Hz it'd work out to (roughly) 1.42857 mS between IRQs, so keeping track of whole milli-seconds only would lead to huge inaccuracies.
For the sake of accuracy, the initialization code will calculate the number of whole milliseconds to add to the "system timer tick" each IRQ, and the number of "fractions of a millisecond" to avoid drift. This may be important, for example if the PIT is set for 700 Hz it'd work out to (roughly) 1.42857 mS between IRQs, so keeping track of whole milliseconds only would lead to huge inaccuracies.


I hope you are all familiar with fixed point mathmatics. For example, with the "32.32" notation I'll be using, if the high dword is equal to 0x00000001 and the low dword is equal to 0x80000000 then the combined value would be 1.5. In a similar way, the fraction 0.75 is represented with 0xC000000, 0.125 is represented with 0x20000000 and 0.12345 would be represented with 0x1F9A6B50.
I hope you are all familiar with fixed point mathematics. For example, with the "32.32" notation I'll be using, if the high dword is equal to 0x00000001 and the low dword is equal to 0x80000000 then the combined value would be 1.5. In a similar way, the fraction 0.75 is represented with 0xC000000, 0.125 is represented with 0x20000000 and 0.12345 would be represented with 0x1F9A6B50.


To begin with, this following code contains all of the data used by this example. It is assumed that the ".bss" section is filled with zeros.
To begin with, this following code contains all of the data used by this example. It is assumed that the ".bss" section is filled with zeros.