Designing a 24-bit VGA Adapter

See Ming Jie
8 min readOct 4, 2021

--

In learning FPGAs, I wanted to create use a display interface to interact with my code. However, the best I came across was this 8-bit VGA adapter from Waveshare, built on an R2R DAC.

Output from 8-bit colour VGA, with a simple test pattern

I wasn’t really happy with this result, as I wanted more modern graphics with better colour resolution. So, I set out to design my own VGA board with 24-bit colour, using the 40P FPC slot available on the Lichee Tang FPGA board that I was using for my FPGA tutorial.

The VGA interface is quite simple. There only a few control signals, the RGB analogue lines between 0~0.7V, HSYNC and VSYNC to control the active area of the pixels. The latter two control signals also allow the monitor to synchronise with the source so that pixels are correctly mapped to the screen. You’ll notice that there isn’t a clock signal present, as it is typically recovered from the RGB signals.

Control signals for VGA

For my case, I was working with a 640x480 resolution, the most common VGA resolution for most use cases. It uses a slow enough clock (25.175MHz) that most FPGAs can provide, yet enough resolution for most uses. This includes an inactive area of 160x120, which consist of the Front Porch, Sync Pulse and Back Porch.

| Resolution | Refresh Rate | Pixel Clock (MHz) | Display (H) | Inactive Area (H) | Display (V) | Inactive Area (V) |
| --- | --- | --- | --- | --- | --- | --- |
| 640x480 | 60 | 25.175 | 640 | 160 | 480 | 120 |

For the VGA output, we use a parallel 24-bit RGB bus from the FPGA to drive a DAC. An R2R DAC of this size would be unwieldy, so I decided to use a GM7123C chip. This chip consists of three 10-bit DACs for each of the RGB lanes, providing up to 30-bit colour resolution. However, due to the lower number of pins available to me from the 40P FPC connector, I decided to stick with the 24-bit resolution.

Designing the Schematic

To capture the schematic for the PCB design, we use the application circuit from the datasheet. Unfortunately, the GM7123C chip datasheet is only available in Chinese. To get around this, we can use the similar ADV7123 chip datasheet. For my PCB layout, I use the cloud-based EasyEDA for PCB design. Feel free to use other PCB design tools such as KiCad, Altium Designer or EAGLE. I chose EasyEDA for its supplier integration, as I find it easier to order my components and PCBs through the tool.

GM7123C schematic

In the schematic above, we see that the GM7123C has RGB [0–9], allowing 10-bit colour per lane. Since we’re only using 8-bit, we tie the two Least Significant Bits (LSB) to ground, leaving them unused by default. The VDD power supply is tied to our local 3.3V net. We add decoupling capacitors C1, C2 and C3 to stabilise the power supply to the chip. This is particularly important for the internal DACs, for stable output. Lastly, we tie the #PSAVE control signal high to disable power-saving mode, and the RESET signal high to keep the chip active.

For the VGA analogue signal output, we use the IOR , IOG , IOB lines. For DC coupling, we tie these signals to ground through a 75 ohm resistor, as recommended for VGA. These signals will go to our VGA D-Sub connector.

Connections to VGA connector

The main control signals are the analogue RGB lines, and the two HSYNC and VSYNC signals. We take these signals directly from the FPGA, instead of using the SYNC and BLANK functionality from the chip. Hence, these two signals are wired directly from the FPGA, using its 3.3V voltage levels. There are some additional control signals as defined in the Display Data Channel (DDC) standard, but we can ignore them for now.

Connections to the Lichee Tang

Lastly, we connect the relevant signals to the correct pins of our 40P FPC socket, as defined by the Lichee Tang schematic. The original use case for this socket was a 40-pin LCD display. I’ve broadly maintained the same connections with the RGB lanes, as well as the video clock (D_CLK) and HSYNC/VSYNC connections.

Logic level shifter for PS2 interface

On the same board, I also add a PS2 connector to interface with the FPGA. PS2 is an older Human Interface Device (HID) interface standard that allows us to connect keyboards and mice to computers before USB was invented. It functions at a 5V logic level, which is higher than what the FPGA can tolerate. As such, we have to implement a bidirectional 5V/3.3V logic level shifter, using transistors as shown above.

Pinout for PS2 connector

The connections for the PS2 port are straightforward as well; just follow the common standard. One thing to note is that you’ll need to supply 5V from somewhere, such as your USB connection to the FPGA board. The FPGA doesn’t provide any 5V power sources; it’s only able to sink/source current at 3.3V maximum.

With that, our schematic capture is complete! We can now move on to piecing the puzzle of our PCB layout.

PCB Layout

Transferring the components to the PCB layout format, we group each component together in its logical groups. For this simple PCB, this means keeping the passives close to their relevant chips/connectors. Additionally, the low speeds of the VGA interface mean that length/impedance matching isn’t a bit concern for us, unlike modern differential interfaces like DVI/HDMI.

Layout view of the VGA PCB

After some routing, we make quick work of the layout! Notice how everything is logically grouped and routed, to minimise track length and unnecessary crossovers. The RGB lines are routed in parallel to the FPC socket, while the remaining components surround the main IC (U1) to minimise their track length to the relevant chip lead. I’ve also added some standard 2.54mm pin headers to allow us to manually control the SYNC and BLANK functionality of the GM7123C, and supply 5V to the VGA/PS2 nets respectively if needed.

3D View of final PCB

Above, we see the final, pretty 3D view of our PCB! You’ll notice that the FPC socket seems to be backwards here — it is. I had neglected to flip it around and use a reverse FFC cable instead. At the time of designing the PCB, I was so insistent on using a same-sided FFC cable that I didn’t think about using a reverse one to tidy up the layout, and allow the cable to come off the edge of the board instead.

Now, we can send our board to be manufactured by our favourite PCB house. Personally, I find that the cheapest options tend to be manufacturers based in China, and I have had good experiences with them in the past, so I decided to go with that. I’ve just got to be patient for the next few weeks while my boards get manufactured…

Assembled Boards

Finally! After a 2–3 week-long wait, my boards have finally arrived! I decided to try out the SMT option, where the manufacturer orders and assembles the components for me. Handy if you don’t have a heat gun or reflow oven handy! I just had to solder some of the through-hole components myself, which isn’t difficult with some good solder wire and a soldering iron.

I was so excited to start working on it, I loaded in my VGA module code and plugged in my monitor…

And nothing showed up on the screen. I was confused! Where had I gone wrong? I had tested the code with my pre-made VGA board with a 3-bit R2R DAC and everything had worked smoothly. I had even simulated my code in iverilog, verifying that each signal was responding correctly. I double-checked and triple-checked my connections on the PCB, probed every pad with a multi-meter, but alas, I couldn’t find the problem.

Troubleshooting

Wiring setup with the logic analyser

That was when I decided to run video data to both my 3-bit R2R VGA module and this 24-bit VGA module, and probe the signals of each with the Saleae Logic Analyser. I hoped to find a difference in timing that might have been the cause of the malfunction.

Lo and behold! When probing the outputs of the VGA D-Sub connector, I discovered my fatal flaw. In routing the signals from the FPC socket to the VGA connector, I had accidentally swapped the HSYNC and the VSYNC signals. Fortunately, this was an easy fix in the FPGA, by simply swapping the pin definitions for the two signals. Finally, after many hours of frustration, I had my result…

Final Results

It was beautiful! Using the same test pattern generator, the colours in the 24-bit RGB DAC were much more smooth and vibrant, blending into one another seamlessly. This will provide a great platform for my future FPGA projects on the Lichee Tang.

In retrospect, I probably wouldn’t have found my error without the logic analyser; I tried to probe it with a multimeter but it wasn’t immediately obvious that I had swapped the signals, as the only difference was the effective DC voltages. I would recommend getting a logic analyser for your electronics toolbox, any one will do!

--

--