A system consisting of an ATMEL MEGA32 chip, Altera FLEX10K FPGA, and a library of source code for the Atmel processor to generate 256-color VGA video signals in real time optimized for game development.
The Nintendo Entertainment System sports 2 KB of RAM and a 1.79 MHz 8-bit processor. Using an additional video processing chip, it is capable of displaying 48 colors (16 simultaneously) at a resolution of 256 by 224 pixels. Knowing the technical limitations of the system, we felt that an ATMEL microprocessor with some additional hardware to handle the video bandwidth would be capable of reproducing a similar game programming environment for amateur game hackers.
To distinguish our project from previous ECE 476 final projects, we chose to generate VGA output instead of the NTSC iamges favored by previous designs. While time constraints prevented us from generating a full-scale game, we have succeeded in creating a game development environment with all of the “dirty work” done. Our project features custom hardware running on an Altera Flex10K FPGA which generates VGA video in 256 colors at a resolution of 200×160 pixels, and stores the neccessary screen buffer data in its RAM. A communications protocol we developed allows an ATMEL microprocessor to control the screen’s contents by downloading a tile map and tile descriptions to the FPGA during the screen blanking period. Additional control logic allows freely positioned “sprites” to be displayed on top of this tiled background. Finally, some simple code enables a would-be game to utilize an NES or Super NES controller for user input.
High Level Design:
Our system is composed of one Atmel MEGA32 processor running on an STK500 development board, an Altera Flex10K FPGA on a UP2 development board, and an array of DACs implemented by hand on a whiteboard. The FPGA is used to store screen data and drive the VGA signal (generating horizontal and vertical sync signals using its internal clock, and sending digital color information to the DACs for the analog VGA lines). The screen is abstracted as a two-dimensional array of 8 pixel by 8 pixel “tiles” — indices into an array of 8×8 bitmaps consisting of 8 bits of color information per pixel. The FPGA is directed in what data to display by the Atmel processor which maintains a computer game or other application’s state. The Atmel downloads tile bitmaps and screen tile arrays to the FPGA using a communication protocol described in the appendix. Timing is synchronized by using external interrupts generated by the FPGA coincident with line and screen blanking periods. The Atmel processor can also communicate with an external game controller over an additional I/O port.
The main standard encountered by this project will be the VGA signal standard. We successfully implemented this standard, and tested our system with a regular VGA monitor.
We utilized an Altera Flex10K FPGA to implement the screen buffer and to generate the VGA output. The FPGA has 18 kilobits of RAM. Three RAM blocks are instantiated: a tile definition block, a sprite definition block, and a screen buffer block.
Each tile and sprite is an 8 pixel by 8 pixel block. Each pixel contains an 8-bit color value: 3 bits of red, 3 bits of green, and 2 bits of blue. The tile RAM can store up to 16 tiles. The sprite RAM can store up to 4 sprites.
The screen is 200 pixels wide by 160 pixels high. The screen buffer is 26 tiles wide by 20 tiles tall. Each position in the screen RAM stores an index into the tile memory. The extra column is used in scrolling. The FPGA stores a horizontal offset value between 0 and 7. The entire screen is shifted this number of pixels to the left, with pixels on the right side being pulled from the 26th column of tiles as neccessary. This horizontal offset is incremented by one on a positive edge of the “scroll” signal from the ATMEL, and is reset to zero when the “reset_X_off” signal goes high.
The VGA standard uses 5 lines: a horizontal sync, a vertical sync, and analog red, green, and blue signals. The FPGA is conveniently clocked at 25.175MHz, which is the pixel rate for the VGA signal. The FPGA uses a counter clocked at this rate to count “logical pixels.” The horizontal blanking, sync, and active video portions of each line are generated based on this counter. A vertical counter is clocked using “logical lines.” The vertical blanking, sync, and active video portions of each frame are generated based on this counter. Since the RAMs on the FPGA are single-port RAMS, the VGA module turns off the write enable signal for the RAMs when they need to be read to determine the pixel value to be output. The VGA module uses the current row and column number to generate an index into the screen buffer RAM, whose output is an index into the tile definition RAM. Meanwhile, the ATMEL can specify the position of up to two sprites. These positions are used to generate an index into the sprite definition RAM. Based on the current row and column, the output from the tile definition RAM and the sprite definition RAM is MUXed to generate the pixel output.
We use three DACs (of 3, 3, and 2 bits each) to generate the analog red, green, and blue signals sent to the VGA monitor. The VGA standard calls for values ranging from 0.0V to 0.7V for each wire, with 0.7V yielding the highest intensity, and 0.0V indicating black. The input impedence for each of these signals is 75 Ohms. We implemented the DACs using an R-2R ladder design, built on banks of matched 10KOhm resistors. The 10 KOhm resistors keep the actual current draw from the FPGA low, but do not possess enough power to actually drive VGA signals. Therefore, we used 3 fast op-amps (TI OPA37GP’s) in voltage-follower configurations to isolate the signal generation from the signal delivery. Since the DAC output ranges from 0-5V, we used a 330 Ohm resistor after each op amp to voltage divide the signals down to 0.7V maximum. The op-amps draw their power from a separate power supply with +/-12V rails.
Our ATMEL can also interface with an NES or Super NES game controller for user input. Each of these controllers internally uses a standard 4021 8-bit linear shift register chip. When the “latch” line is pulsed, the state of all buttons on the controller is recorded into the shift register. Pulses on the “clock” line then advance the output of the shift register, sending a 1 or a 0 on the “data” line back to the ATMEL chip for each of the 8 buttons (including the 4-way directional pad) in a predetermined order.
Our initial design called for a 64 KB SRAM to be used as a full screen buffer. Buying a dual-port SRAM would enable an address generator to generate the VGA output signal from the screen buffer, while the ATMEL chip could fill the screen buffer from the other port. This plan was abandoned when we realized that 64 KB SRAM chips were only available in surface-mount and other difficult-to-solder configurations.
The ATMEL software consists of a library of functions designed around the shared communications protocol. We include functions for downloading tile and sprite bitmaps to the FPGA. Other functions quickly set the sprites for the current screen row, and strobe a full screen or column of tiles to the FPGA. (Individual tiles can also be set with another function.) A separate function will quickly read in the game controller state for use.
The FPGA generates two falling-edge signals corresponding to the beginning of horizontal and vertical blanking. The ATMEL interprets these as external interrupts and invokes two interrupt handlers, which currently count which logical screen line the FPGA is displaying.
Our main program initializes the ATMEL’s ports and interrupts, downloads the tile images to the FPGA RAM, and then enters the main loop. In the loop, it fills the screen with an image reading “ECE 476!”. At every vblank period, it commands the FPGA to scroll left by 1 pixel. Every eighth scroll, it downloads the entire screen again, but advanced by a single column of tiles. The result is a demo screen which wraps the “ECE 476!” message horizontally.
The ATMEL code is also responsible for storing the tile maps for game levels, as well as the tile and sprite bitmaps in its flash RAM. Since the FPGA clears on boot, the ATMEL must re-download its tiles to the FPGA at game start. This design also allows increased flexibility, as different tiles could be loaded in at different points of a game to allow a much wider variety of game environments within a single program.
While this proof-of-concept program only does the above, it is the framework upon which a more complicated program such as a game could be written. The major modification would be performing game update logic in the vertical blanking period. (Downloading a full screen of tiles to the FPGA requires approximately 7,600 cycles of the ATMEL’s processor, which must be done once per eight scrolls. The vertical blanking period is approximately 22,800 cycles, yielding ample time for additional processing.)
Nearly all I/O pins on the ATMEL are used. Interfacing with a video game controller requires 3 pins on port D. Two other pins on port D trigger the line- and frame-end interrupts. Ports A, B, C, and 3 pins of port D are all used as output to the FPGA for one-way communication purposes. The entire protocol is listed in the appendix.
Throughout the process, the software code was remarkably easy to write, given the nature of the task. The major difficulties in our project lay in building the hardware device itself; through careful design we were able to avoid most problems in advance.
Our system works as described. Continuous scrolling is some times (approximately one pixel in 40) jerky, resulting in an annoying but negligible “click” in the scroll process. The DAC and op-amp circuit also seems to lack the bandwidth to handle sudden changes in brightness. As a result, a solid block of one color followed by a solid block of another color will cause the first one to “bleed” into the second for a few pixels. While this is regrettable, a single-chip DAC circuit would probably alleviate these issues. At the time we were doing our design, we dismissed this option for cost reasons. Since we are under budget, a “future rev” of this project would most likely include a higher-performance integrated DAC circuit.
One additional issue is that writes to the tile bitmap memory did not always seem to succeed on the first try; we cannot find a reason for the values to fail to take hold, since the same data lines succeed in writing to the screen buffer memory every time. Our work-around solution is to send each value from the Atmel to the FPGA multiple times. While technically “non-deterministic,” it has proven to be a reliable mechanism. Future revisions of this system would focus on increasing data transfer reliability.
We tested the timing of the VGA sync signal generation. We generate horizontal sync pulses with accuracy within 25 us of the target time for a line. Vertical sync pulses are generated with a period of 16.70 ms; this is very close to the 16.68ms standard, and is accepted by our test monitor.
Our project is safe for use by virtually anyone. While in its current form, it is vulnerable to electrostatic shock, this could be solved by careful packaging. It does not generate large electrical currents, nor does it involve the use of any motors or other potentially dangerous parts. To be extra safe, we heat-shrinked the wiring connected to the external VGA header.
|ATMEL Mega32 chip||$8||“rental”|
|ALTERA UP2 & FLEX10K||free||scrounged — obsolete ECE 230 hardware|
|VGA female connector (DB-15 connector)||$2.00||Radio Shack|
|Test 4021 chip||$0.48||DigiKey|
|3 x OPA37GP op amps||free||Sampled – Texas Instruments|
|4 x matched 10 KOhm resistor packs||free||in-lab components|
|12V power supply||$5||“rental”|
For more detail: MCU/FPGA color video Game Platform