VGA Line Doubler [Concept]
February 12, 2019This is a concept design for a VGA line doubler that I’ve wanted to build for a while now. I’m putting my notebook rumblings on here for future reference, or if anyone wants to extend upon these ideas. A line doubler has long been a goal of mine but requires a fair amount of mental thought. Commercial line doublers are insanely expensive, so building a low latency one would be rewarding.
The goal of this line double is to upscale 320x240 signals to 640x480 - progressive. (interlaced is a whole other animal). 15-bit color is what I have in mind as most legacy systems running this low of resolution won’t have color depth beyond this.
The term line doubler is used commonly, but is a misnomer. You can’t think strictly in the sense of horizontal lines. If you only displayed every horizontal line twice, you’d distort the aspect ratio of your source data. A line doubler refers to the doubling of both horizontal and vertical. That is a single pixel will now occupy 4 pixels. (2 horizontally, 2 vertically).
Yes, there are customized chips for this exercise but they are expensive, have massive pinouts, and overwhelming data sheets. That said, I’ve actually never seen a chip tailored specific to line doubling, so regardless there is unavoidable work we have to do ourselves!
So, some Preliminaries…
-
Original resolution 320x240p, Vsync will be 240 X 60Hz = 14.4KHz
-
(In reality 15.1KHz as there are more than 240 lines, drawn off the screen, but don’t obsess over this)
-
New resolution 640x480p, Vsync will be 480 x 60Hz = 30Khz
-
In other words, 2x Vsync, Hsync unchanged.
-
Original pixel clock will be 320 X 240 X 60Hz = 4.6MHz
-
New pixel clock will be 640 X 480 X 60Hz = 18.4MHz.
-
That is pixel clock increases by 4x (not 2x !!!)
So line doubler needs two things to function…
- Mechanism to double the Vsync from 15Khz to 30Khz
- Mechanism to store a data line of row of graphics
Right off the hop, it’s obvious we need an ADC R2R that will turn our analog graphics data into digital so we can store it, and eventually we will run it through a DAC R2R to get it back into analog.
For doubling Vsync… we need to use original vsync, or csync (and strip it apart) and double that to get a new Vsync pulse (30Khz). Hsync will remain the same at 60Hz and doesn’t need to change.
I believe you can get away without phase-locked loops in this, there are some whitesheets on doubling timings with great precision, and since we are dealing with legacy low resolution stuff the standard seems pretty forgiving with sloppy pulses - but its anyones guess until they go actually try it.
For storing a data line of row of graphics… things become a little more difficult to convey; however to keep things clean without doing weird shift registers and complicated memory addressing, I propose 3 qty of 8-bit SRAM chips. One for each RGB line. Plus this way everything runs in parallel for minimum latency.
Now, complication begins where the digital data from the ADC R2R needs to be stored, sequentially, into RAM. That is, every original pixel pulse, the 15-bits of data (5-bits for each color Red/Green/Blue) need to be struck to RAM in a sequential address. For this we need a parallel counter which on every original pixel pulse, counter will increase by 1, and output the count on the parallel output lines (two’s complement) to the SRAM memory address lines, recording the graphics data.
As a line doublers purpose is to repeat every column and row twice (i.e. pixel at co-orindate [1,1] will now be at [1,1],[1,2][2,1][2,2]), focus now becomes on achieving that.
We already know the new pixel clock, which is determined by the monitor based on Vsync (now 2x speed) and Hsync (original 1x speed) will be four times as fast as the original source clock.
The flaw in this becomes that original source outputs a pixel, and now with this 4x pixel clock, that pixel will be “smeared” horizontally 4 pixels. So board now needs to have two sub-components/counters that will alter this behaviour. As our board isn’t actually “generating” this 4x pixel clock anywhere, we can instead use the original pixel clock, as output by the Motorola chip, and play with the numbers a little that yield the same results.
First sub counter will on every 8th original clock pulse get the next graphics data in SRAM (to get our column doubling). Note this would be equivalent to every 2nd new graphics pulse (as 4x the speed)
Second sub counter will on every 4th vertical sync pulse, reset the parent counter and toggle the SRAM chips between storing a graphics data line, and retrieving a graphics data line (to get our row doubling). Note this would be equivalent to every 2nd new vertical sync pulse (again, as Vsync pulses are now 2x speed).
As these sub-counters count, loop, etc, data is consequentially setup on the SRAM output lines, which feed into the DAC R2R and are ready for the graphics display to read from as it draws.
My prototype more or less ends here, I’ll expand as I come up with some new ideas or schematics as I conceptualize my thoughts more. I’m in the process of drawing out schematics which may bring more clarity as well to the design. Please feel free to comment on any ideas you may have or errors in my design, as I haven’t built this thing my understanding could be off basis!
But in summary the general idea is:
- Original 320x240 video data is digitized through a ADC R2R
- 15-bit graphics data is stored in three high speed SRAM chips
- Memory address in SRAM is based on counter value, counting on original pixel pulses
- Sub-counters limit how data is stored/retrieved from SRAM based on original pixel pulses and original Vsync pulses
- These Sub-counters are what tames how pixels are displayed (column & row doubling)
- Data output from SRAM is converted back to analog via DAC R2R
- New Vsync output is 30KHz, Hsync output remains 60Hz, monitor internal pixel clock runs 4x speed based on standards.
- This 4x speed is 640x480 video, for every frame at 60Hz.
If anyone has any thoughts or advice on how to improve this concept please add to the comments below! Especially if my understanding of any of the above is incorrect!