Operating Systems Development Series
Operating Systems Development - 8253 Programmable Interval Timer
by Mike, 2008

This series is intended to demonstrate and teach operating system development from the ground up.

8253 PIT Microcontroller with all pins labled

Please note: This tutorial may require some knowledge of hardware interrupt handling and the 8259 Programmable Interrupt Controller (PIC). Please see this tutorial for information on them.

Introduction

Welcome! :)

This tutorial will cover everything you ever wanted to know about system timing and programming the Intel 8253 Programmable Interval Timer (PIT).

The 8253 PIT has had a long history, and has played an important part in nearly every x86 PC. It is the "System clock", and is responsible for many very important functions within the PC. This erm.. "chip" is no longer distributed as an independent chip (as a Dual Inline Package (DIP) to be more precise), but rather integrated into the motherboards southbridge chipset.

Everything about the 8253 still remains, however. Because of this, its input and output facilities, hardware, and the way we program the 8253 remains the same. Because there is not of any difference (besides speed) between this and the older DIPs, we will be looking at the older 8253 DIP to help keeping things simple.

The picture at the beginning of this tutorial displays what we will be looking at and programming.

Lets have some fun ;)

Programmable Interval Timers

A Programmable Interval Timer (PIT) is a counter which triggers an interrupts when they reach their programmed count. The 8253 and 8254 microcontrollers are PITs avialble for the i86 architectures used as timer for i86-compatable systems.

These PICs include three timers that are used for different putposes. The first timer is useually used as the System Clock. Timer 2 was used for RAM refreshing, and timer 3 is connected to the PC speaker. We will see all of the connections a little later, so we won't go into much detail now.

Instead, lets take a closer look at one of these famous PITs... The 8253 Microcontroller.

8253 Hardware

Before looking at the software side of things, it will be helpful to learn more about what we are actually programming. Because of this, we will look at the 8253 hardware first, and learn how it works and is connected to the rest of the PC. We will also be looking at internal registers, pin layout, command words, and more that will be needed for the software side of things.

8253 Hardware: Description

The 8253 PIT has a simple interface, and is not that hard to program.

Yep--There is the chip that we will program.

Here is the complete pin layout. We will be refrencing these pins throughout this tutorial, so it is important to know what they are.

  • D0...D7: 8 bit data lines. This is connected to the data bus so we can read and send commands.
  • CLK 0, CLK 1, CLK 2: Clock input pins. There are 3 pins for 3 separate counters
  • OUT 0, OUT 1, OUT 2: Output data line. There are 3 pins for 3 separate counters
  • GATE 0, GATE 1, GATE 2:Gate data line. There are 3 pins for 3 separate counters
  • GND: Ground
  • Vcc: Input voltage
  • WR: Write enable. When this line is active, lets the 8253 that we are writing data
  • RD: Read enable. When this line is active, lets the 8253 that we are reading data
  • CS: Chip select signal
  • A0, A1: Address lines. Used to determin what register we are accessing.
Not to bad. There are a couple of important pins here that we need to look at.

The D0-D7 pins connect to the systems data bus. These pins carry our data when we are sending or reading data to the controller.

Vcc and GND complete the circuit (Voltage input, Ground output.)

The WR pin tells the controller that we are writing (expect input on the data pins.) When the signal in this pin is "low", we are currently sending data. The RD pin is very simular in this manner, but it tells the controller we are reading data instead. The CS pin is a special pin that determins what the controller should do with the RD and WR pins. If the CS pin is "low", the controller will respond to the RD and WR pins. If CS is not, they are ignored. WR and RD connect to the Systems Control Bus. The CS pin connects to the systems Address Bus for port i/o operations.

The A0 and A1 pins are connected to the Systems Address Bus, and are used to determin what register we are accessing. These, in conjunction with WR and RD allows the controller to determin if are reading to or from a register.

Notice that there are three groups of the CLK, OUT, and GATE pins. Yes, there is indeed a reason for this: The 8253/8254 microcontrollers contain 3 independent timers.

Lets look closer on how this works...

8253 Hardware: Counters

The 8253 consists of three counters: Counter 0, Counter 1, and Counter 2. Each counter has 2 input pins: CLK (Clock Input) and GATE, and one pin for output--OUT.

As there are three counters, they are used for different purposes within the system. Each counter are 16 bit down counters.

Typical computers connect the first timer's OUT pin to a Programmable Interrupt Controller (PIC) to generate an interrupt for every clock tick. This is useually used as the System Timer. The second counter was used for generating a timing signal to the Memory Controller to refresh DRAM memory. The third counter is used to generate tones to the PC speaker.

As you can probably guess, the PIT uses the OUT pins to signal these devices when its counter reaches 0. When the PIT's counter reaches 0, it simply wraps around and starts again.

CLK is the clock input for the timer. It may be used with the GATE pin depending on the current mode of operation. The following table describes the operation depending on if the current in GATE is low, rising, or high.

GATE Input pin operations
ModeLow or going lowRisingHigh
0Disables Counting-Enables Counting
1-Initiates Counting and resets OUT after next CLK-
2Disables Counting, Sets OUT to highReloads counter and initiates countingEnables Counting
3Disables Counting, Sets OUT to highInitiates CountingEnables Counting
4Disables Counting-Enables Counting
5-Initiates Counting-

The 8253 Counters are also known as Channels. Knowing that the 8253/8254 PITs contain three channels, lets look at each of them more closer...

Channel 0

Channel 0 is connected to the 8259 PIC to generate an Interrupt Request (IRQ). The PITs OUT pin connects to the PIC's IR0 pin. Typically the BIOS configures this channel with a count of 65536, which gives an output frequency of 18.2065 Hz. This fires IRQ 0 every 54.9254 ms.

The is the primary timer used on almost all x86 machines. the clock rate (Signalled through Counter 0's CLK pin) is at 1193181.6666... Hz, one third of the NTSC subcarrier frequency. This was required do to backward compatability with the older CGA PC's.

Channel 0 is typically programmed in most systems to act as the System Clock. This is made possible do to channel 0's OUT pin indirectly connecting to the PIC's IR0 line. Depending on the mode that we set it in, we can set the timer to a good frequency, and have it enable the PIC's IR0 line at a constant rate. Afterwords, reseting itself and starting over again. Because the PIC is used to handle hardware interrupts, we will need to first reprogram the PIC.

Because it is connected to the interrupt with the lowest number (IR0), it also has the highest priority over all other hardware interrupts.

Its lowest frequency rate is normally used for computers running the old DOS systems (Are there any left?) at about 18.2 Hz. Its highest frequency rate is a little over a megahertz.

In real mode operating systems, the BIOS normally increments the number of times IRQ0 is fired to 0000:046C, which can be read by any running program.

Channel 1

Many video cards and the BIOS may reprogram the second channel for their own uses. This channel was originally used for generating a timing pulse signal to signal the memory controller to refresh the DRAM memory. In modern times, this is no longer needed as the refresh is done by the memory controller. Because of this, there is no guarantee at what devices may use this counter.

Channel 2

This channel is connected to the PC Speaker to generate sounds. the PC speaker is normally meant to produce a square wave with two levels of output. However, it is possible to go between the two true defined sound square levels. This is called Pulse-Width Modulation (PWM).

We can set up this channel by programming it for mode 3, and setting a frequency rate for the tone.

We can also program the PC Speaker directly. Looking back at Tutorial 7, we can see that the PC speaker is mapped to port 0x61. This port defines how the speaker will operate:

  • Bit 0: If set (1), the state of the speaker follows bit 1
  • Bit 1: If set (1), the speaker uses the PIT, If not set (0), the speaker disables its connection to the PIT
If bit 0 is set, the rest of the byte contains a pattern of bits representing the frequency of the tone. We can generate up to 8 bit sounds from the speaker, which is kind of cool, but tricky to do.

You should also notice that we can disable devices from using the PIT. At startup, the BIOS configures the speaker to use the PIT channel 2, running in mode 3. It is recommended to keep the speaker to use the PIT do to timing problems that you will run into.

Here is an example, for completeness sake:

; disables the speaker, and stop using channel 2 mov dx, 0x61 out dx, 0 ; generates tone from speaker out dx, 11111101b

Conclusion

Once a counter is set up, it will remain that way until it is changed by another control word.

There is some cool things we can do with these counters, huh? Because channel 1 is not used anymore, we cannot assume it is safe and use it ourselves. Because of this, it is recommended to stick to channel's 0 and 2.

We can use channel 0 to fire off our interrupt handler. Our interrupt handler can increment a counter used by our kernel. This special little counter variable, plays a very important role in the system: The System Timer. We will see all of this soon, don't worry ;)

Allright...So, we looked at pin configurations, and the three timers used by different devices for..err...timing. Whats next?

When programming these timers, we have to initialize them. Remember that each channel supports 6 different modes. Some of these modes are very useful. Other modes are not. Lets take a look at each of these modes for better understanding of them. Please note that this gets a little detailed, but I am sure you already knew or were expecting that :)

8253 Channel Modes

Remember that each counter can be programmed in 1 of 6 modes. This is done by sending an Initialization Control Word (ICW) to the controller. We will look at the format of this command word later. For now, lets look at each mode.

Mode 0: Interrupt on Terminal Count

In this mode, the counter will be programmed to an initil COUNT value and afterwords counts down at a rate to the input clock frequency (The CLK signal). When COUNT is equal to 0, and after the Control Word is written, the counter enables its OUT pin (by setting its line high) to signal the device it is connected to. Counting starts one clock cycle after the COUNT is programmed. The OUT line remains high until the counter is reloaded with a new value or the same value or until another control word is written to the controller.

What this mode basically does is allow us to set a timer that counts down to 0. After which, we will need to reload a new count number to it, or a new control word to re-initialize the counter.

Mode 1: Hardware Triggered One-Shot

In this mode, the counter is programmed to give an output pulse every certain number of clock pusles. The OUT line is set to high as soon as a Control Word is written. After COUNT is written, the counter waits until the rising edge of the GATE input. If the trigger occurs during the pulse output, the 8253 will be retriggered again. One clock cycle after the rising edge of GATE is detected, OUT will become and remain low until COUNT reaches 0. OUT will then be set high until the next trigger and wait again until the rising edge of the GATE input is detected.

Mode 2: Rate Generator

This mode configures the counter to be a "divide by n" counter, which is commonly used to generate a real-time system clock.

The counter is programmed to an initial COUNT value. Counting starts at the next clock cycle. OUT remains high until COUNT reaches 1. Afterwords, OUT will be set low for one clock pulse. OUT is then set back high, and COUNT is reset back to its initial value. This process repeats until a new control word is sent to the controller.

The time between the high pulses depends on the current value in COUNT, and is calculated using the following formula:

COUNT = input (Hz) / Frequency of output

COUNT never reaches 0. It only ranges from n to 1, where n is the initil COUNT value.

Okay, lets stop for a moment. Remember that Counter 0 is connected to the PIC? Counter 0's OUT line indirectly connects to the PIC's IR0 line. Knowing that, when the IR0 line is low, the PIC will call the IRQ 0 handler defined by us.

If we set the counter to Mode 2, we can set up the timer to fire off our interrupt at a constant rate. All we need to do is determine what the COUNT value should be based off of the above formula. This is used very often in setting up the System Timer for the operating system. After all, IRQ 0 is now being called for every clock tick at a frequency rate that we defined.

Yes, Mode 2 is an important mode, indeed.

Mode 3: Square Wave Generator

This mode is quite similar to Mode 2. However, OUT will be high for half of the period, and low for the other half. If COUNT is odd, OUT will be high for (n+1)/2 counts. If COUNT is even, OUT will be low for (n-1)/2 counts.

Everything else is the same from Mode 2. We will need to use the formula from Mode 2 to set up the initial COUNT value.

If the speaker is configured to use the PIT, the channel that it uses typically should be set to use this mode.

Mode 4: Software Triggered Strobe

The counter is programmed to an initial COUNT value. Counting starts at the next clock cycle. OUT remains high until COUNT reaches 0. The counter will then set OUT low for one clock cycle. Afterwords, it resets OUT to high again.

Mode 5: Hardware Triggered Strobe

The counter is programmed to an initial COUNT value. OUT remains high until the controller detects the rising edge of the GATE input. When this happens, the counting starts. When COUNT reaches 0, OUT goes low for one clock cycle. Afterwords, OUT is set high again. This cycle repeats when the controller detects the next rising edge of GATE.

8253 Registers

The 8253 contains a few registers that we can access. Most of these registers are very simular to each other, so I will just put them in the same table for clarity. This table displays each register and their functionality when the corresponding lines on the 8253 are active. Notice how the RD and WR lines determine the read and write operation. Also notice how the A0 and A1 lines determin what register we are accessing.

Looking at the port table from Tutorial 7, we can see that the System Timer is mapped by the BIOS to use ports 0x40-0x4F. Each port address is a byte in size.

8253 PIT Internal Registers
Register NamePort AddressRD lineWR lineA0 lineA1 lineFunction
Counter 00x401000Load Counter 0
0100Reads Counter 0
Counter 10x411001Load Counter 1
0101Reads Counter 1
Counter 20x421010Load Counter 2
0110Reads Counter 2
Control Word0x431011Write Control Word
NA 0111No Operation

All other port addresses from 0x44-0x4f are undefined.

The system will activate the correct lines depending on the operation we are performing. When setting the counter registers, we need to first let the controller know how we are going to load it. This is done by first setting up the control word. Lets take a look closer at these registers...

Counter Registers

Each counter register holds the COUNT value used by the PIT to count down from. They are all 16-bit registers. When writing or reading from these registers, you must first send a control word to the PIT. You might wonder why we cannot just do it directly. There is a reason for this, and it has to do with the size of the data. The PIT only has 8 data lines (Pins D0-D7). However, the counter registers are all 16 bits, not 8.

Because of this, how does the PIT know what data you are writing to its counter register? How does it know what byte within the counter registers 16 bits are you setting? It doesn't. Sending a command word allows you to let the PIT know to expect incoming data, and what to do with it. We will look at that next.

Control Word Register

THIS will be important to us.

This is an important register used to determin and set the operation modes for the controller. This is accessed by enabling the RD, A0, and A1 lines. This register can only be written to, not read from.

The control word register uses a simple format. At first I was thinking of using a table here, but it may be easier in a list format so here it is:

  • Bit 0: (BCP) Binary Counter
    • 0: Binary
    • 1: Binary Coded Decimal (BCD)
  • Bit 1-3: (M0, M1, M2) Operating Mode. See above sections for a description of each.
    • 000: Mode 0: Interrupt or Terminal Count
    • 001: Mode 1: Programmable one-shot
    • 010: Mode 2: Rate Generator
    • 011: Mode 3: Square Wave Generator
    • 100: Mode 4: Software Triggered Strobe
    • 101: Mode 5: Hardware Triggered Strobe
    • 110: Undefined; Don't use
    • 111: Undefined; Don't use
  • Bits 4-5: (RL0, RL1) Read/Load Mode. We are going to read or send data to a counter register
    • 00: Counter value is latched into an internal control register at the time of the I/O write operation.
    • 01: Read or Load Least Significant Byte (LSB) only
    • 10: Read or Load Most Significant Byte (MSB) only
    • 11: Read or Load LSB first then MSB
  • Bits 6-7: (SC0-SC1) Select Counter. See above sections for a description of each.
    • 00: Counter 0
    • 01: Counter 1
    • 10: Counter 2
    • 11: Illegal value
Allright, then! bit of stuff going on here, don't you think? So...All we need to do is build up the control word by writing to the control word register to initialize the controller, right? Of course! Sort of...

Basically, we want to initialize a counter for a specific purpose. So, we have to build up the control word to set up the counter, the counters counting mode and operating mode. THEN, we initialize the counter itself. Remember that, once initialized, the counter can carry on itself (depending on its mode), so we only need to do this once.

Lets give an example and put everything together, shall we?

Lets pretend we already have a PIC initialized and interrupt 0 handler. We want to set up a timer to fire off IRQ 0 every 100Hz (once every 10 milliseconds). We know that channel 0 of the PIT is connected to the PIC's IR0 line, so we can program channel 0 to do this.

; COUNT = input hz / frequency mov dx, 1193180 / 100 ; 100hz, or 10 milliseconds ; FIRST send the command word to the PIT. Sets binary counting, ; Mode 3, Read or Load LSB first then MSB, Channel 0 mov al, 110110b out 0x43, al ; Now we can write to channel 0. Because we set the "Load LSB first then MSB" bit, that is ; the way we send it mov ax, dx out 0x40, al ;LSB xchg ah, al out 0x40, al ;MSB
Notice how we set up the control word first, THEN write to the counter 0 register.

Is that it!?? Yep. The above will program counter 0 to fire IRQ0 every 10 milliseconds.

Conclusion

The 8253 and 8254 PIT's are very usefull little chips. They can be used in alot of different devices, and used for alot of different purposes.

For our needs, we can both have a nice signaled output via the PC speaker and a system timer that is a very important aspect on all modern system software. We have even looked at another way of working with the speaker directly, and even disable its connection to the PIT, which has advantages and disadvantags. It is up to the system software designer to decide and outweight the pros and cons of the different and unlimited possibilities when developing their system.

We have looked at the PIT in depth, pin configuations, and their connections on a standard x86-based PC motherboard. The PIT itself is useually integrated with the motherboard's southbridge in modern computers.

I an planning on adding more to the chip itself, and describe exactally how it connects in a typical computer system. Mabey even breaking it apart?

Tutorial 16: Kernel: Timing and Exception Handling puts everything from the 8259A PIC and this tutorial together. It impliments and creates interfaces for both devices. Mabey even a little bit more...

Welcome back to kernel Land!

Until next time,

~Mike
BrokenThorn Entertainment. Currently developing DoE and the Neptune Operating System

Questions or comments? Feel free to Contact me.

Would you like to contribute and help improve the articles? If so, please let me know!