Note: An updated version of this article is available here! However, this article remains valid and I placed a note in every section that got updated.
It’s been a while since I published this series of articles on nerdhut about monochrome video signals for an old Macintosh CRT. I wanted to post a short follow-up article about VGA and how to generate such signals. This article will also be a follow up to the custom CPU series and it will be another step towards the custom computer, I always wanted to design and build.
However, in this article, I only want to take a look at how the standard 640×480@60Hz VGA-Signal can be created using a screen testing device, made from discrete electronic components, which can be used to test monitors without the need of a computer being around.
Even though digital alternatives, like DVI, DisplayPort and HDMI, have been commonly available for quite a while now, VGA still seems to stick around, especially in older devices. However many manufacturers slowly discard VGA and concentrate towards using DisplayPort and HDMI. If you have never seen a VGA-connector before, it looks like this:
Although the quality of the video signal can get quite bad when using VGA, you can still display images at high resolutions, even with a relatively cheap cable and display hardware.
But in this article, I want to re-create the standard 640×480@60Hz signal. If you are interested in other display resolutions, make sure to take a look at the end of this article, where I have linked a list of display resolution standards.
When looking at the connector from fig. 1, the following image shows the pinout of the plug on the device side (note the direction, the second row is shifted in, so you don’t get confused between the male and the female type of connector):
The other pins are not relevant for this project, so I’ll simply not discuss them any further, to keep the article short.
It turned out that they are important. See this article for more!
VGA is an analog standard, that mainly relies on 5 signals to communicate display data between a device and a monitor. These 5 signals are HSYNC, VSYNC, R, G and B.
The sync-signals come from the old times when CRTs were commonly used. These types of monitors had one or multiple electron guns, that shot a beam which got deflected by one or multiple coils. These beams were used to draw pixels on a coated screen by making the coating glow. However, at the end of a line, the electron gun needed to be moved back to the beginning of the next line. And to make sure it reached it had the time to travel back, a delay was needed at the end of each line, where no pixel-information was sent to the display. This was the HSYNC signal:
At the end of each frame, the electron gun had to travel all the way back to the first pixel again, so the VSYNC follows the same principle as the HSYNC and it looks like this:
Each pixel is composed of a red, green and blue signal. They range from 0V (completely off) to 0.7V (full brightness) with an impedance of 75 Ohms.
The VGA-standard resolution is relatively easy to work with, especially when using only discrete components, due to the relatively low clock-speed of 25.175MHz.
However I couldn’t find this exact oscillator, so I used a 25.0MHz one instead, which comes close enough and shouldn’t cause any problems.
Turns out that it does matter. However, the rest of this section remains valid but you have to use an exact 25.175 MHz oscillator!
Let’s first take a look at the following chart, which can also be found on this page:
Each line consists of the following parts:
|Scanline part||Pixels||Time [µs]|
Which sums up to a total of 800 Pixels per line and each line takes around 31.7775 microseconds to be drawn. Each frame consists of 480 visible lines and is then followed by a VSYNC-pulse with the following timings:
|Frame part||Lines||Time [ms]|
Both sync-pulses (HSYNC and VSYNC) are negative.
Let’s take a look at fig. 3 again, but this time with the scanline parts marked:
The blue area represents the pixel data (HSYNC high), the green part is the front-porch (RGB-lines low, HSYNC high) followed by the sync-pulse, marked in yellow, and then the line ends with the back-porch (shown in orange) before the next line is sent.
Signal generation circuit
The completed circuit is actually quite a bit simpler than it might appear when first looking at it:
The main work is done by two 12-Bit binary counters (built using three 4-Bit counters), which count the horizontal and vertical position to determine the time when a sync-signal has to be sent to the monitor:
The counters used in this circuit provide a fast carry-lookahead functionality and can be used with clock speeds up to 25MHz, which is exactly the speed, that I used in my circuit. However, faster counters can be bought, if needed.
Other than that, I used several AND and NAND gates to determine the moment when the sync-signal should change states. Two NAND-Gates form an R/S Flip-Flop at the end of the HSYNC portion so that the signals can stay high and low for more than one clock cycle.
The VSYNC doesn’t use its own R/S Flip-Flop. Instead, two interrupt lines go to the CPU and the VSYNC-signal is derived from these. I had to do this because I made a mistake in the design somewhere and the Flip-Flop was forced into an astable state.
Let me quickly cover the operation: When you turn the circuit on, both SYNC lines are low. The HSYNC portion then starts counting to 95 before setting the R/S Flip-Flop and therefore setting the HSYNC line to high, which initiates a new line. In this simple application, I ignore the front and back porch, because there is no actual pixel data. The counter continues to count until it reaches 799. When it does, the R/S Flip-Flop and the horizontal count are reset, while the vertical count is increased by one.
The VSYNC signal follows the same procedure, using the numbers from the table above. This leads to the following signals:
Figure 8 shows both signals combined. Here is a different screenshot only showing the HSYNC-signal in more detail:
The HSYNC-signal is slightly slower than the optimum signal from above, but my monitor still detects it. The following image shows the duration of the sync-pulse:
|6||74LS163AN||4-Bit binary counters with fast look-ahead|
|1||74LS279N||Quadruple R/S Flip-Flop|
|1||TFT680||25.0 or 25.175MHz crystal oscillator|
|1||–||3 pin DIP-switch|
Signal generation with software
Of course, it’s absolutely no problem to generate these simple waveforms with a fast enough microprocessor, for example with one of the PRUs found on a BeagleBone Black.
However, I don’t want to discuss it in this article, because I’ve already done so in this series. But if you want to see an example of an Arduino Uno generating 800×600@60Hz VGA, take a look at the end of this article under “Helpful resources”.
The signal seems good, but probably not good enough for some monitors. Some struggle to find the proper resolution. Maybe they try to communicate with the “graphics card” via I2C to find a valid resolution or maybe my signals are simply not stable enough. However, older monitors seem to lock on my VGA signal pretty easily and fast. So I will definitely have to put some work into that and further investigate what’s going on.
An update is available here.
But because the goal of this article was to re-create the signals, mentioned above, I will still call this a success, because I managed to perfectly recreate the exact timings (See fig. 8, 9, 10).
Besides that, it was a very interesting trip into the huge field of discrete electronics and real-life applications. So far I haven’t really gone any further than simulating digital circuits like I did with my home-made CPU. But I think that it turned out quite well:
I learned, that the real world differs quite a bit from a simulator and that hazards can quickly cause a simple circuit to behave completely random.
Even though I had some difficulties, I think that it was a nice project and I understand video signals and VGA much better now. This was truly a huge step towards my completely custom PC build that I wanted to do for so many years.