UPD7220 Video Card (Revision 2)
The uPD7220 Video Card revision 2 is a video card with 128KB of VRAM using the uPD7220 GDC or its variants. It operates at a maximum clock speed of 32Mhz. The card is based on the original uPD7220 card I (Dylan Brophy) made, which had half the VRAM and generally was far simpler. This card solves several issues with the older card, at the cost of greater size and complexity.
Detailed Specifications
- 16-color VGA output
- 128KB of RAM
- 4 RAM chips, 32KB each, 25ns access and write time
- 16 bit bus (8 bits per chip, two chips per byte)
- 4 color bits per pixel, 4 pixels per word in RAM
- Maximum 262144 pixels (hardware double buffering disabled)
- Suggested resolutions: 544x480, 640x408
- Maximum 131072 pixels (hardware double buffering enabled)
- Suggested resolutions: 448x288, 400x300
- Maximum 262144 pixels (hardware double buffering disabled)
- uPD7220 at up to 24Mhz, Z7220 at up to 32Mhz
- uPD7220 wide mode supported
- Allows higher pixel clock frequencies, for higher resolutions and lower visible display times
- Accesses two VRAM words per uPD7220 clock cycle
- Direct access to VRAM is provided to the host CPU
Video Modes
It is assumed that the reader is familiar with VGA display timings. If not, then it is recommended to study it, or to use the video timing calculator and to leave the card in wide mode.
The uPD7220 was invented before the VGA standard, and due to this, was not designed to output a VGA signal. Since VGA was designed to drive CRT monitors, as was the uPD7220, it turns out that they are fairly compatible. VGA timings work perfectly fine, but to compute them one must keep in mind the pixel and uPD7220 clocks. The uPD7220 clock is always one fourth of the card's clock speed.
For common VGA signal timings, I would recommend looking at this very useful site: TinyVGA signal timings
One must take the timings and convert them to the correct resolution. For an example, let's convert the 640x480 VGA standard timings to a 400x400 resolution. Here are the video timings from TinyVGA's 640x480 60hz page:
Region | Pixels | Microseconds |
---|---|---|
Visible area | 640 | 25.4220 |
Front porch | 16 | 0.6356 |
Sync pulse | 96 | 3.8133 |
Back porch | 48 | 1.9067 |
Whole line | 800 | 31.778 |
Region | Lines |
---|---|
Visible area | 480 |
Front porch | 10 |
Sync pulse | 2 |
Back porch | 33 |
Whole frame | 525 |
First, we need to decide on a clock frequency for our card. 24Mhz is slower than the 25.175Mhz recommended, and this will make our pixels wider by about 5%. However, a 24Mhz clock will run our uPD7220 at 6Mhz, right at the maximum frequency, and 25.175Mhz would overclock it. We will select 24Mhz, as the 5% elongation of pixels is too small to care about, and the timings should be compatible with the uPD7220 IC. We will enable wide mode, so our pixel clock is set at 24Mhz (the same as the card - without wide mode it would be 12Mhz, or half). This keeps the pixel width close to the intended width. Importantly, this change in clock speed will change the necessary timings for the video signal. Since each uPD7220 clock cycle is 166.7ns at 6Mhz, and each word is two cycles, we will be dividing the horizontal porch and sync widths by 333.3ns to get the number of words for each of the regions. We cannot compute this yet though, because the visible region still needs to be adjusted for our new resolution.
For our application, we need less pixels, but still need to meet the timing spec. To achieve this, we can increase the back porch and reduce the visible region until we have the resolution we want. We do this on both the x and y axes. This works because, during the back porch, the video signal is sent a black signal. On older monitors, this corresponds to a dark box around the image, and newer monitors will treat it as a blank region. Fundamentally, the monitor will still generally treat it as a 640x480, standard VGA signal, because we haven't encroached on the porches, and we haven't changed/moved the sync signals. To compute the width of the new visible area, we multiply the number of horizontal pixels by the pixel clock period: 41.67ns * 400 pixels = 16.67us. From this, we can calculate the new horizontal front porch, and then we can recompute the lines per vertical video region:
Region | Microseconds |
---|---|
Visible area | 16.67 |
Front porch | 0.6356 |
Sync pulse | 3.8133 |
Back porch | 10.6620 |
Whole line | 31.7776 |
The back porch becomes much wider. All we did was move the time over from the visible area to the back porch, such that the visible area has the correct number of pixels at our clock frequency. The vertical regions are adjusted similarly, but the math is much simpler, because we are only trying to keep constant the number of lines:
Region | Lines |
---|---|
Visible area | 400 |
Front porch | 60 |
Sync pulse | 2 |
Back porch | 63 |
Whole frame | 525 |
You will notice that I added lines to both the front and back vertical porches. This is because the uPD7220 cannot output more than 63 of each porch, so I needed to add to both to obey this limitation. For lower resolutions, it is usually acceptable to reduce the total number of lines to obey these limitations. It is important, however, that in such a case the horizontal lines are made longer to keep the refresh rate at 60hz, and that the video settings are tested to work on the monitor.
At this point we have the description of the mode we want, now we can convert it into the numbers used by the card. The vertical timings are already in the correct format, but the horizontal timing still must be converted. To do this, we need to get the number of memory cycles (not uPD7220 clock cycles) for each horizontal region, which is the time for two uPD7220 clock cycles. The exception is the visible region, which is computed from the amount of memory used to represent the data (4 pixels per word, one word accessed per uPD7220 cycle in wide mode). For the visible region, we divide the number of pixels by 4, and for the other regions, we divide the time by 333.3ns and round to the nearest whole number. Here is the result:
Region | Words |
---|---|
Visible area | 100 |
Front porch | 1.907 => 2 |
Sync pulse | 11.4399 => 11 |
Back porch | 31.986 => 32 |
Any VGA monitor should accept these signal timings for a 400x400 resolution. For video memory consumtion, this needs 400 * 400 / 4 = 40000 words of memory. The card has 65536 words total, but only 32768 if automatic double buffering is enabled, so we cannot enable automatic double buffering for this resolution. So, we must enable wide mode and disable double buffering for this video mode.
Card Specific Details: Wide Mode
This card can reach quite high clock speeds for the uPD7220, and to maintain this high speed for such slow chips, wide mode is used. This allows twice as many pixels to be output per uPD7220 clock cycle. This can be used either to increase the maximum resolution, or to reduce the display time. Reducing the display time gives the uPD7220 and host processor more time to draw to the screen. On the other hand, due to the high speeds used in wide mode, there is also typically more data that must be written to the display per frame, thus putting more pressure on the host processor. The balance in display characteristics depends on the application.
Due to wide mode support, the card's clock is 4x the uPD7220's clock. When doing calculations for video, this must be kept in mind. If wide mode is disabled, then the pixel clock is only half the card's clock. If the video timing math does not account for this, then the video signal timing will be incorrect.
Communication with the Host Processor
The hardware connection uses a fairly simple 8-bit parallel bus for data exchange. Once connected, the software can read from and write to several registers and addresses on the card to control it.
Hardware Protocol
Here is a pinout of the card:
Pin | Name | Description |
---|---|---|
1 | A0 | Address pin 0 (LSB) |
2 | A1 | Address pin 1 |
3 | A2 | Address pin 2 (MSB) |
4 | NC | No connection: this is the key pin and should be blocked |
5 | GND | Ground connection |
6 | D0 | Data pin 0 (LSB) |
7 | D1 | Data pin 1 |
8 | D2 | Data pin 2 |
9 | D3 | Data pin 3 |
10 | D4 | Data pin 4 |
11 | D5 | Data pin 5 |
12 | D6 | Data pin 6 |
13 | D7 | Data pin 7 (MSB) |
14 | SEL | Select pin (active low input) - selects the card for communication |
15 | 5v | +5V rail to power the card |
16 | RD | Read enable pin (active low input) |
17 | WR | Write enable pin (active low input) |
18 | WAIT | Wait indication (active low output) |
When trying to access VRAM, if the VRAM is being used by the card, then WAIT will be pulled low to tell the CPU not to end the current operation until after the WAIT pin goes high again. After WAIT goes high, wait at least 31.25ns for the read/write operation to complete before releasing any control lines or changing any data/address lines. Never read data while WAIT is low, and wait 31.25ns after WAIT goes high before reading the data to the CPU. WAIT only becomes low when trying to read from or write to VRAM; otherwise WAIT is always high.
Each access cycle should last at least 31.25ns, and SEL should be de-asserted between cycles. Any conventional processor like Z80, 8086, 6502, etc, should have no issue with WAIT or access cycles below an operating frequency of 32Mhz, regardless of the speed of the card. There may be exceptions to this, but there are no known exceptions.
Software Protocol
Register | Purpose |
---|---|
0 | uPD7220 command register (uPD7220 A0 = 0) |
1 | uPD7220 parameter register (uPD7220 A0 = 1) |
2 | Card configuration register (write only) |
3 | Direct VRAM access (accessing this may cause WAIT to go low) |
4 | VRAM Address bits 0-7 (write only) |
5 | Reserved - for now same as register 4 |
6 | VRAM Address bits 8-15 (write only) |
7 | Reserved - for now same as register 6 |
For this card, a driver should first configure register 2 for the selected video mode and card interface configuration. This register has various bits to tell the card what to do:
Bit | Purpose |
---|---|
0 | Enables automatic counting of the VRAM address registers if set. If reset, then the VRAM address registers do not change when VRAM is written. More on this later. |
1 | Setting this bit enables the card's wide mode circutry. When reset, one pixel will be output every other clock cycle. This should match the setting on the uPD7220 IC. |
2 | Enables automatic double buffering. When set, draws to VRAM from the host CPU or the uPD7220 will happen on the opposite buffer as the one displaying. Setting this halfs the available VRAM for displaying. |
3 | Reserved |
4 | Reserved |
5 | Reserved |
6 | Reserved |
7 | Controls which buffer is displaying. Changing this bit will swap the currently displaying buffer. Only works in automatic double buffer mode. |
It is recommended to keep track of what buffer is currently displaying, and perhaps this entire configuration register, so that the selected buffer can be switched. This register is important for controlling how the CPU accesses VRAM, how smooth the display is, and the way the image data is displayed. Generally, automatic double buffering is recommended if the resolution demands less than half of the available VRAM, as double buffering makes the display smoother by removing visual artifacts due to drawing, but doubles VRAM demand.
You can read the programming manual to get a detailed understanding of how to program the uPD7220, but I will also provide an abridged version here. Once the card's configuration register is set, the uPD7220 must be initialized. The uPD7220 requires a sequence of commands to be sent to set it up: 1. A reset command (write 0x00 to address 0x01)
- This must be followed by parameter bytes, described below
2. Setting the video mode to master (write 0x6f to address 0x01) 3. Configuring the pitch 4. Initializing the PRAM
- PRAM is some internal memory in the uPD7220, which configures how it accesses memory, and probably some other things
5. CCHAR command to configure the character characteristics 6. Disabling zoom (write 0x46 to 0x01, then 0x00 to 0x00) 7. Starting the display (write 0x6B to 0x01) 8. Disable blanking (write 0x0D to 0x01)
My driver also seems to issue a FIGS command at the end of startup, but this may not be necessary.
Each command starts with a write to address 0x01, and for each parameter a write to address 0x00 follows. Each command I describe will proceed this way, with the first byte being the command byte written to address 0x01, and all following bytes being parameters written to address 0x00. At the end I will have some example code in C which provides as both an example and an additional explanation.
The first command is the reset command; here is the format:
Address | Value / Description |
---|---|
1 | 0x00 |
0 | Operation mode. Discussed below. |
0 | Horizontal display words minus two. Must be an even number. This is equal to ((horizontal_pixels / 4) - 2). Wide mode does not affect this. |
0 | Lower 5 bits are the HSync width minus 1, in words. Upper 3 bits are the lower 3 bits of the VSync width. |
0 | Lower 2 bits are the upper 2 bits of the VSync width. Upper 6 bits are the horizontal front porch width minus 1. |
0 | Horizontal back porch width minus one. Upper two bits must be zero. |
0 | Vertical front porch width minus one. Upper two bits must be zero. |
0 | Number of display lines per frame, lower 8 bits. |
0 | Lower 2 bits are the upper 2 bits of the number of display lines per frame. Upper 6 bits are the vertical back porch length. |
Note that the vertical field sizes do not have numbers subtracted from them, but the horizontal field sizes have one or two subtracted from them. If this description is confusing, the uPD7220 manual provided above does contain a nice illustration you may consider looking at.
The operation mode is a bitmask, which controls interlacing, character or graphic mode, as well as DRAM refresh and if drawing is allowed during an active display cycle. Here are some of the options that one can OR together to control the operation mode:
Bitmask | Selected Option |
---|---|
0x00 | Leave bits 5 and 1 zero to have mixed character and graphics mode. |
0x02 | Enables just graphics mode |
0x20 | Enables just character mode |
0x00 | Leave bits 3 and 0 zero to disable interlacing |
0x08 | Enables interlacing |
0x09 | Enables "Interlaced repeat field for character displays". Read the manual for more information. |
0x04 | Enables DRAM refresh cycles - not used on this uPD7220 card, as static RAM is used. |
0x10 | Disables drawing during active display time. Enabling this is recommended. |
Generally 0x12 is a good setting for this card, unless you intend on using character mode. 0x10 will also work as a good mode.
The second command one must send is 0x6f, again written to address 0x01, and it does not take any parameters. The third command is the PITCH command:
Address | Value / Description |
---|---|
1 | 0x47 |
0 | Number of memory words per line. Usually the same as the number of display words per line. Generally equal to (horizontal_pixels / 4). The only reason it would differ, is if the |
The fourth command is a PRAM command, which writes data to the uPD7220 parameter RAM. Here is a recommended usage of the command (although other usages are possible, again read the manual for more info):