When your FPGA project needs to display a large amount of data, there is one solution which is simple but may not be obvious: the VGA monitor. An analogue monitor from a digital FPGA, really? Yes, it's actually really straight forward to generate VGA signals, and no external chips are required to do so. This topic has been covered many times before by others, and in this blog entry I will try to simplify it as much as possible whilst including some important details that are sometimes missed. HDMI/DVI are covered later in the series...
Project objective
If you haven't read it already, please read the introduction to the VHDL Teletext project over on my dedicated VHDL Teletext Overview blog entry, which covers the project objectives, a brief history of Teletext and its current uses, and the FPGA Teletext hardware.
The basics
The hardware
VGA has five key signals - R, G, B, Horizontal Sync, and Vertical Sync. There are additional signals which can be used to get details of the monitor via I2C, but those are outside of the scope of this entry.
Horizontal Sync and Vertical Sync are TTL-level digital signals, but it is sufficient to use 3.3V FPGA pins directly. These are not terminated in the monitor, so you can use low value series resistors to protect the FPGA pins in case of a short circuit without affecting functionality.
R, G and B are the analogue signals, which are terminated with 75 ohms inside the monitor. 0V corresponds to black and 0.7V is full brightness. A simple resistor ladder DAC will suit most FPGA applications; the design is very simple: decide how many "bits" of colour depth are required, then calculate the resistor values so that they follow these rules
- The voltage at the output, when terminated with 75 ohms, is approximately 0.7V when all FPGA outputs are on
- Each bit in order of decreasing significance should have a resistor value of double that used for the last bit
For many text-based applications, all that is required is one bit per channel, in which case a 270 ohm resistor is ideal when using an FPGA IO voltage of 3.3V.
The firmware
The firmware is simple too; there's just a few terms which need to be understood, and the best way to explain these is with a diagram:
The dotted arrows indicate the retrace of the electron beam on CRTs; this happens during the blanking interval. LCDs don't have a retracing anything, but the timings remain the same for compatibility. The scanning is done from left to right, top to bottom. The HSync waveform happens once per line, whereas the VSync waveform happens once per frame, so the HSync signal will pulse hundreds of times for each VSync pulse.
Translating this to HDL, all that's needed is:
- A "Horizontal" counter which is normally incremented once per clock cycle
- A "Vertical" counter which is incremented every time the Horizontal counter completes a full cycle
- Some logic to generate the sync signals and ensure the video is blanked during the blanking intervals
But wait...
VGA was originally designed for CRT monitors, but nowadays it is frequently used on LCD monitors. How does it know what the horizontal time period of each pixel is when it doesn't know what the pixel clock is?
Well, it doesn't. The "Auto Adjust" function attempts to work this out, but it only works if the active area is full of content. If you're using a black background and the content doesn't reach the edges, then the Auto Adjust function may not work correctly. To ensure correct Auto Adjustment when using a black background, a border around the edge of the active area should be drawn. This will, of course, be visible on the monitor, but that's only a minor price to pay to guarantee correct adjustment. This is easy to implement with a line of combinational logic.
Resolution selection
The resolution is limited by the speed of the FPGA, the quality of your hardware, and the length of your cables. The resolution is normally dictated by the requirements for what needs to be displayed.
The most common resolution is 640x480; with a pixel clock of 25.15 MHz, this can be closely matched using a common 25MHz clock. 1280x960 can be achieved with a 100MHz clock. High resolutions can be achieved with lower clocks if you are happy to use non-square pixels (wider than they are tall).
It's a good idea to specify the parameters using constants or generics to allow them to be changed easily. Any experimentation should be done with an LCD monitor, since some CRTs can be blown up by improper timings. Here are some typical timings for 640x480:
- H Size: 640 clock cycles
- H Front Porch: 16 clock cycles
- H Sync Pulse: 96 clock cycles
- H Back Porch: 48 clock cycles
- V Size: 480 lines
- V Front Porch: 11 lines
- V Sync Pulse: 2 lines
- V Back Porch: 31 lines
The calculation for the required clock frequency is: F (Hz) = Frames per second * (H Size + H Front Porch + H Sync Pulse + H Back Porch) * (V Size + V Front Porch + V Sync Pulse + V Back Porch)
For most monitors, the frames per second should be around 60Hz. The lower limit is usually around 50Hz, and the upper limit 65Hz, or 80Hz for most monitors with a resolution of 1280x1024.
Example code
Link to my example code (read the points below first)
- My code just outputs internal sync signals, but you may desire to output the pixel counter values instead; this would be simple to implement. (hint: convert integer to std_logic_vector)
- This code does not generate any display content on its own, not even the test card. Generating this is a challenge for the reader.
- The timings have been modified for 720x576 resolution, therefore the clock frequency required is higher (see equation above). The border generator has also been written to draw the vertical borders offset from the edges. LCD monitors which can't sync to this resolution should detect it as 800x600.
Next: let's generate our content.
No comments:
Post a Comment