Does this project spark your interest?

Become a member to follow this project and don't miss any updates


CPLD-flavored VGA Video card

Similar projects worth following

This project was created on 07/17/2014 and last updated 6 months ago.

Do you remember when 640x480 was a high resolution?

How about when *hundreds* of colors was a huge palette?

Does the pure awesomeness of dithering cause tears of nostalgia to well up in your assaulted-with-pixel-density eyes?

You've found the right project!

We've undertaken the ambitious challenge of fitting first generation display technologies - VGA and NTSC - on the smallest programmable logic device we think we can to create an embedded video card. Targeted for microcontrollers and headless Linux development boards and devices, VGAtonic promises to bring all the retro-video goodness you can shake a stick - or speak SPI - at.

The Executive Summary 

640x480 Video @ 8 bit color from a serial protocol that any Maker's parts can speak.

The Engineer's Report

As there are a number of interesting display-less dev boards and embedded linux products on the market nowadays (not to mention the 2 PogoPlugs and the Intel Galileo in my own parts bin), I set out to find a solution for getting reasonable video out of the world's collection of headless parts.  

VGAtonic is my effort to make said headless parts connect to the displays people already have lying around - monitors with VGA input, and TVs with their anachronistic NTSC RCA jacks.

Our goals are modest - 640x480 is still the fallback, worst case resolution for lots of applications - so we'll target VGA's original 640x480 spec.  Technically, the original VGA asked for just 4 bit color (read: 16 colors), but as an analog protocol we'll double the number of bits to 8 to get 256 colors.  NTSC is still undecided, but in our tests we've been producing 16 colors and 16 brightnesses: 256 colors the hard way.

For the brains, we'll be using a 4MBit ISSI IS61LV5128AL-10 with a Xilinx XC95144XL CPLD providing the brawn and the timing.  Our first reference design, a roughly 3"x3" PCB, was already released, and we decided to use a programmable oscillator (Linear Technology's LTC6903) and a microcontroller (Atmel's ATTiny 2313a) for board support and experimentation.  If we do another design, we'll try to tighten it up and actually target an interesting size.

Oh, and we're going to do it all with a BOM of roughly $23-$32 a board.

  • 1 × Xilinx XC95144XL 144 Macrocell CPLD
  • 1 × ISSI IS61LV5128AL-10 100 MHz 4MBit Static Ram
  • 1 × Linear Technology LTC6903 Programmable Oscillator
  • 1 × ON Semiconductor NCP1117ST33T3G 3.3V Low Dropout Voltage Regulator
  • 1 × Atmel Corporation ATTiny 2313a Microcontroller

Project logs
  • Working Example Code for the Intel Galileo (Arduino Mode)

    6 months ago • 0 comments

    I wanted to share some working code for the Intel Galileo board I've been showing in my videos.  With this update I'm declaring partial victory over this project, because now you can at least reproduce what I've shown in the videos.


    Motivation has waned a bit, but here's where I plan to go with this before I hit my 100% wish list:

    • User Mode in Linux (Done!  Just need to make a formatting/commenting effort and pull it off the Galileo)
    • Kernel Module / Framebuffer in Linux (This is the big one - in progress...)
    • NTSC Output activated (Not started)
    • Add features to CPLD firmware (Not started)

  • Breakout Boards for .5mm TQFP ICs

    6 months ago • 0 comments

    In response to a question in the comments by mylistgroups12, I wanted to show two of the breakout boards I acquired when starting this project.  I should note: I originally thought I might fit everything into a smaller CPLD (recall this post), which was in a 64 .5mm QFP size.  Still, I got a few breakouts which support the larger, 100 pin size - but even with the 64 pin broken out (I did 5 to practice with the smaller CPLD, but only added pins to one) it was tedious to wire Vcc/Vss.

    In the top right, of course, you can see VGAtonic - roughly 3" x 3", for scale.

    In the upper right is a breakout board I bought from Futurlec: (Currently: select 'Components' at top, then on the left 'Sockets', 'SMD Adapter').  It can only support an 100 pin chip, but it makes the pins easier to use/count.

    On the bottom is both sides of an adapter I bought on ebay from user e-sale2010.  I'd try searching 'QFP Adapter' - but this is nice because you can use anything from 32 - 100 pins in the .5mm pitch.  However, the pin count will be funky - I had to make a spreadsheet to convert the labeled pin number to the actual pin number on the CPLDs.

    Hope this helps!

  • CPLD Firmware Uploaded!

    6 months ago • 0 comments

    The moment that a few of you have been waiting for - a glimpse at my VHDL - is now here.  See the newest code in our git repo:

    You'll want to bring that into ISE Webpack and synthesize it.  I've been programming my CPLDs using a Bus Pirate; you can see that methodology here.

    Look in this directory for all of the demo code and design documents so far:

    The How to Use file details how this protocol works - it's very simple, I promise.

    I'll be back soon with firmware for the ATTiny onboard VGAtonic's reference design, along with the client code used in the Youtube demo.

View all 17 project logs


Hacker404 wrote 2 months ago point

Hi again PK,

I am back after the xmas break and it's time to look at my projects again.

I am still waiting on some parts for using the XC9572XL (TQFP44) with some SRAM.

The 44 pin package doesn't have the pin count for what I need at the end.

For soldering the TQFP44 I have been making a big blob of solder and running it along an elevated edge of the chip so the excess solder feeds of at the bottom corner and doing the same for the other three side.

Can you tell me if this - Can I get away with attempting to solder a chip on to a breakout board (same as yours from futurlec) in the same way for a TQFP100 0.5mm or am I wasting my time attempting this?

The tracks of the 0.5mm breakout don't seem to have enough space between them for the solder to run off without leaving a bridge.

Alignment will also be a big issue for me, any tips? I can just barely see the pins of a TQFP44. I am trying to make a digital microscope but that is a way off yet.

Are you sure? [yes] / [no]

PK wrote 2 months ago point

"Can I get away with attempting to solder a chip on to a breakout board" - yes, absolutely.

"am I wasting my time attempting this?" - In my opinion, this is true as well, heh. I would suggest skipping the breakout board for this project and going straight into CAD. Using one of the larger breakout boards (I did it for 'just' 64 pins while testing) was very painful... and the results were a hilarious mess of spaghetti jumper wires, that sort of worked when you didn't get too close to it or jostle it.

Short traces in a CAD program in a cheap Fab service will beat it every time... and will usually be faster than waiting for Futurelec (or eBay) anyway.

For alignment, I didn't use a microscope, but I did use a thin tipped soldering iron, some solder paste (and lots of braid!) from a generic eBay seller, and some of those head attachment dentist tool head things ('head magnifyer' on Amazon works as a search). Also pick up a tweezer set for the fine adjustments - once everything is exactly aligned and you tack down the corners, it's actually pretty easy to do these thin pitches, and might be similar to how you did the larger pitch. It's a bit harder to remove the bridges as you suspect, so tread lightly on the solder and enhance your braid skills.

I screwed up a couple chips - but I had a heat gun for paint, and it worked perfectly to remove the mistakes. Mask off the area with tinfoil, hit the chip with heat, and keep poking it with a tweezer until it slides off. Warning: don't touch it for a few minutes after, haha.

Are you sure? [yes] / [no]

Hacker404 wrote 4 months ago point
Hi again,
I played around with timings to see how the monitor reacts (LCD).

What I found is that it really doesn't matter where the sync pulses are as long as they are there and (I would assume) there is sufficient front an back porches.

Auto adjust will detect where the start and end of a H line by where there is color info. If you make the last cell black on all lines then the remainder will be horizontally stretched to fill the screen width when you auto adjust.

Not so with lines. The monitor detects VGA timing model by H and V sync frequency as well as polarity. If you generate less lines the screen will still start with the first line and there will be a black area at the bottom where the lies are missing, no stretching to fill the height.

So given that there is no vertical stretching, any changes to horizontal resolution will also result in a change to the aspect ratio. So this is probably not all that useful in most cases.

I have a timing glitch that puts an extra half a pixel at the end of a line because the counter registers AND active area register are updated on the same rising_edge(CLK).

I read your code and see that you are using CLK'EVENT and I will give that another go. I couldn't do it before because I was coding it wrong.

I have been using registers for the sync pulses (and H & V active) instead of combination logic like your code. I thought combination logic could introduce unwanted transitions due to timing delays in the counter chain. I will try your method as well. So far, I see in my synthesis reports that I am using extra macro's for combination logic rather than registers so the register method may well be fine for this device. Will see what is better.

I looked at some old retro computers and the timing models they used. Aspect ratios were essentially ignored and timings were chosen so that simple combination logic could generate Sync's, Active's and counter resets. Most of them had a much smaller active area as they worked with glass tube monitors that were rounded on the corners.

I also thought that if I have a graphics mode (in a BMP like format) that has 8x8 px in a 8x8 cell and then have a simultaneous text mode that has 5x7 px in a 6x8 cell then I could squeeze more text per line. This would slow text but that doesn't matter if the graphics is still fast.

I will write back later.

Are you sure? [yes] / [no]

PK wrote 4 months ago point
Awesome - please keep us posted as it seems you're nearing the heavily detailed oriented part of the project. I'll tell you that I eliminated a bunch of "off by one" type errors even in the posted code, and a few minor timing errors that caused vertical banding due to rounded clocks.

And yes, horizontal timing you may as well hit - at least with your pulses. You can double up lines by hitting your memory twice if you're memory constrained though. But 320x240 or something is only easier on the horizontal side since you have to hit the 480 lines anyway.

You've probably done some testing, but I should mention it anyway - if you think you're working, try it on a few monitors. For me, that was the best for my NTSC work, as it revealed some rather hilarious color differences... but it might reveal something important for VGA as well.

Are you sure? [yes] / [no]

Hacker404 wrote 3 months ago point
I am stuck waiting for parts now. The next step to get this working with some RAM. The only RAM I have in DIP is 70nS so it is too slow. I have 10nS RAM in a SOJ36 package but I can only find SOJ to DIP adapters up to 32 pins. I have ordered some 10nS RAM in a TSOP 32 package and I should have adapters here.

I still can't work out what format to use. If I go 400x300px then I have 40nS per px. If I use a BMP style layout then there is 60,000K RAM at 4 bits per px.

BMP will take up a lot of address space and the CPU will be slowed down by having to do so many writes to update the screen. I can fit tiled format into a much smaller address space which would be faster overall but tiled will be more than one read per px.

The object of this for me is to have a Z80 working with VGA. If I also include a atMEGA1284 for IO, keyboard etc then I can have it do most of the work and the the CPLD only has to do the fast stuff. ie I could get the CPLD just to do one line at a time under the control of the atMEGA.

Timing is going to be the challenge - VGA at 50Mhz with a 25MHz dot clock, an atMEGA at 20 MHz with one clock per instruction and a Z80 at 20 MHz with 3 or 4 clocks per instruction all time sharing the same RAM and busses.

I have a Papilio one (500K) here and I think it has about 16K BRAM so I might play with that while I am waiting for parts. I just have to work out how to use BRAM.

Are you sure? [yes] / [no]

Hacker404 wrote 4 months ago point
Hi, Now I have a checker board pattern on my monitor. I have definitely moved on from flashing a LED on an Arduino lol.

I am trying to use the standard SVGA (I think) at 800px 48Khz / 600px 72Hz and 50Mhz px clock.

My actual output is 400 x 300 px / 50 x 37.5 char in a 8x8 px cell at 25MHz. There is no real 25MHz px clock as the cells (color boxes) are 16x16px in the original 800x600px.

All the standards that I can find say that both sync signals should be positive for this mode but my monitor will only auto adjust correctly if I invert the hsync. The ysync polarity makes no difference.

I think in your code you ordered the signals: sync - front porch - active area - back porch.

I have ordered them: active area - back porch - sync - front porch.

Could this be causing my problem?

I still can't drive ISE but I have discovered that if I keep impact open I can re-program without re-entering the programing config (It won't save the config).

I am wondering if it really matters what the px clock is? Can't I use an arbitrary px clock as long as the active / sync timing conforms to some standard?

I will go and try the 25.175 MHz standard at 25.000 MHz and see what happens. I will try it two ways.

1) Everything running slower so that the sync etc are longer.

2) Correction for the slower clock so the sync etc are the correct length.

I am using the LogicStart MegaWing off my Papilio One for the VGA port so the signal voltages should be right. Only eight colors though.

Are you sure? [yes] / [no]

PK wrote 4 months ago point
"I am wondering if it really matters what the px clock is? Can't I use an arbitrary px clock as long as the active / sync timing conforms to some standard? " - yes, you've got it. The most important thing is sticking very close to the published timings, and, as you expected, to keep the states in a consistent order. Your prior art can be my Arduino example - I use a sloppy hacked/doubled 16MHz clock at 32 MHz to hit the 25.175MHz timings... with slightly hilarious results. . Just calculate how many clock cycles make up each state you're targeting, and be willing to experiment by adding or subtracting a few until your monitor is happy.

Also, as long as you do the syncing, actives, and the porches in the right order, the monitor should be able to lock on to the signal you're sending... it's your choice (or, possibly, dictated by your coding style) the actual order you check/program for them in the code.

Are you sure? [yes] / [no]

Hacker404 wrote 4 months ago point
PS: I am using the 800x600 SVGA mode that has a 50Mhz pixel clock as my board has a 50MHz active oscillator. I was going to try to clock out at 25MHz and repeat each line to get an effective resolution of 400x300. Once it is up and running (just as a test pattern) then I will play with using 25MHz instead of 25.175MHx in a resolution of 640x480 VGA and 320x240 QVGA. I will probably end up going with 400x300 as it is 50x37 chars which is easier to read text from at 8x8 pixels per char, than lower resolutions.

My code is linked below if you are interested. It's a mess and the front and back porches may be reversed. I will fix it tomorrow.

Are you sure? [yes] / [no]

PK wrote 4 months ago point
I *think* I know what happened (I won't dig too far as you seem to have gotten past the initial hurdle) - you tried to update a variable on two clock edges. While you can do that with the newer Coolrunners, the XC95s that we are using won't be able to do that. It's not fatal - you just need to fake it (and you've got 50 MHz, so you can do the same interleaving). Details for my memory scheme are here:

Basically, Use the 50MHz clock as is, but divide it into reads & writes. It gets hacky, but you can then use your clock in your combinatorial logic to pulse reads/writes:

CYCLE just goes from 0 to 1 - basically, a 25MHz clock from a 50.
Output enable from your memory when CYCLE is 1
Write enable when CYCLE is 1 and CLOCK is 0 (this will be a 10ms pulse for you)
Address is enabled only when outputting
Data (be careful here, as it's two way) - High Z normally, only active write write enable

Most modern monitors should be able to lock to your 25MHz @ 640x480; I even have an example of monitors doing it at 32 MHz (haha):

On another note, thanks for sticking around - my motivation is a bit sapped, but this will gnaw at me until I finish the last couple of features. Please let me know how I can help you further, and if I disappear, you can summon me from my other site as well (

Are you sure? [yes] / [no]

PK wrote 4 months ago point
If you do end up sticking with 400x300, you can still do it - but you'll probably have to move your writes to the blanking intervals. That's roughly 30% updates per frame (we can technically do 100% with the current scheme on these parts, but in practice you can't, haha).

Are you sure? [yes] / [no]

Hacker404 wrote 4 months ago point
I got some horizontal and vertical counters happening, just enough to generate HSYNC, VSYNC and the mask for the active time of the display. That's my first VHDL that does more than flash LED's. Your code helped heaps. Thank you for that. I think I am finally on the way with VHDL. I loaded the code into my XC9572XL board and read the signals back with my OpenBench Logic Sniffer. It is running as coded but I think I may have the front and back porch back to front. Depends if there front and back to the active area or front and back to the sync. No big problem to change. Next step is RGBHV and after that RRGGBBBHV. I will probably use a RAMDAC as a color pallet so 8 bits is fine. The RAMDAC I have is 8 bit select and 3 x 8 bit to analog.

Thanks again.

Are you sure? [yes] / [no]

Hacker404 wrote 4 months ago point
Back again.
My computer died about a month ago. It's up an running again now. I now have a Xilinx DLC9-LP programmer. An I have loaded the Xilinx ISE.

I had only just started VHDL and then resorted to schematic entry when the computer died. This time I tried schematic entry again and found it just too frustrating with the ISE. When I went back to VHDL entry I discovered that I had completely forgotten the little that I had learnt lol. Still lots of bugs with ISE that I am working trough. It seems to be having trouble with windows long file names and keeps reporting that it can't find files and for some reason I have to reconfigure the programming software every time I want to program.

I am just at the stage of writing enough VHDL to flash a led on the board I have -
It's much like yours but has onboard regulation and a 50 MHz active oscillator. It based on the XC9572XL.

I looked up specs for the Z80 and the above chip and found that the Voh of the XC9572XL (3.3Volt chip) is above the Vih of the Z80 so that's a good sign lol.

I am going to plod along with this chip for now even if it lacks enough macros for the end project. I want to try different timings to see what works best.

I saw another project on HAD today -
Where the designer used a window within the full screen size to ease the timing demands. I am wondering if the pixel clock frequency is all that important with a modern monitor. Perhaps - as long as the active time and syncs are right then you could display a full screen with a different pixel clock. I will play with this and see. If it gives trouble then I will try different sync frequencies (different res for the monitor) and use a pixel clock that is an integer division of the expected frequency. ie monitor expects 25.175 but gets half that frequency. I will see what I can do from 50 MHz / x first as it's easy to get 50 MHz xtals but not so easy for 25.175 MHz and the like.

100 MHz would be good stating point if I can get away from anything derived from 25.175. Then I could divide to 20 MHz for the CPU and atMEGA1284, if is use one and 25 MHz for the pixel clock. I will also try clocking a 20 MHz Z80 at 25 MHz and 25.175 MHz. I know the atMEGA is easily overclocked as long as I use an active oscillator and not the internal crystal driver.

I am still waiting on fast SRAM (10nS) but I have some older 55nS SRAM to play with for now. I also have a color palate / RAMDAC to play with. Even if I don't have enough macros for a full interface I should still have enough to make some test patterns as proof of concept.

One thing that is obvious from your pic above is just how much board real estate is taken up by a LQFP 100 to 0.1" adapter. The adapter is half the size of the completed board. This is going to be a problem I have to face if I am going to use 0.1" pin spacings. I have considered PLCC sockets as they are 0.1" but also and extra expense both for the socket and the more expensive chip. Smaller 44 pin chips like a LQFP Z80 can easily sit on a LQFP to DIP adapter but 44 pins is probably not going to be enough IO for the CPLD.

Can I ask what CAD you using for your boards? I have to learn this to lol. I am just learning to make single sided boards by toner transfer. I don't want to take on double sided, they will have to come from a PCB manufacturer. I have used expressPCB and DIPTrace as they suit the manual manufacture process well but I expect they are not good for a PCB manufacturer. Any adapters will have to be double sided as there's just not enough room to do it on a single sides board for DIP adapters.

I know some of the XC95xx series come in a 84 pin PLCC, I am not sure if they come in a 84 pin LQFP but if they did then this may be a good compromise.

Anyway I will do some VHDL tutorials and have a look at your code.

Thanks, and keep up the good work!

Are you sure? [yes] / [no]

Hacker404 wrote 6 months ago point
Can I ask which breakout board you are using in the picture - and where you bought it?

Are you sure? [yes] / [no]

PK wrote 6 months ago point
Sure thing - I broke down both adapters I purchased and took another photo in the recent entry.

Are you sure? [yes] / [no]

Starhawk wrote 7 months ago point
Just wanted to say: way cool project, and way cool results so far! Skull given, and project followed ;) Can't wait to see where this goes.

Are you sure? [yes] / [no]

PK wrote 7 months ago point
Thank you! I've got some other stuff I just need to write up - documenting can sometimes be the greatest challenge, haha.

Are you sure? [yes] / [no]

Darren wrote 7 months ago point
Why not use r2r resistor networks?

Are you sure? [yes] / [no]

PK wrote 7 months ago point
For which schematic? I think you might be looking at my non-related AVR VGA post - I have the CPLD schematic with the output stages/ladders on page two.

For the AVR, they're actually implied - you'd have to look at the original on my site for my output stage, but it's all 510 ohm resistors as well ( I had a reel of like 200 of them - close enough to the 470 ohm I wanted in that).

Are you sure? [yes] / [no]

Darren wrote 7 months ago point
The prepackaged ones like what bournes and others make.

Are you sure? [yes] / [no]

PK wrote 7 months ago point
To be honest? A surplus of 510 ohm resistors in the parts drawer, and I didn't want to buy anything else. I had a reel of 510s for a computer project I worked on some time back - worked out well enough for this.

Are you sure? [yes] / [no]

Benchoff wrote 7 months ago point
NTSC and VGA? Nice job.

You *are* entering this into the hackaday prize, right? All you need to do is tag the project with "TheHackadayPrize"

Are you sure? [yes] / [no]

PK wrote 7 months ago point
That would have been a pretty bad oversight, eh? Thanks for the heads up!

Are you sure? [yes] / [no]

Hacker404 wrote 7 months ago point
I am going to try something similar with a XC9572XL. Perhaps QVGA. I want it to work in with a Z80 and SRAM. I chose the lower pin count chip because it's easier to adapt to DIL.

I am new to HDL. I tried VHDL and I can do most things but I still lack experience. I tried Verilog and it's much easier to code with but I have trouble imagining how the code is implemented unlike VHDL. Now I have resorted to schematic entry.

It would be great to see your HDL as it will get me to understand it better.

Are you sure? [yes] / [no]

PK wrote 7 months ago point
I learned Verilog first, but didn't touch any HDLs for a few years. When I came back to the game, I picked up VHDL and haven't looked back... and I write C++ at my day job (go figure). I prefer the strongly typed statements and the 'compiler' telling me what's sloppy - I think this project will be a lot more thought through than if I used verilog.

I definitely think you'll have a lot to reference with this project. Also, I think QVGA or even quarter-NTSC would be a reasonable target for a Z80. Have you thought about color depth yet? If you can accept 4 bit color instead of 8, you can do 160x120x4 = 76.8 kbits which is cheap and you can easily do in a DIP package... and everything will refresh 2x as fast as 8 bit.

I'll post a bit of VHDL soon - I want to record a demo working for video, as well as show my first draft on my SPI input scheme in the next few days.

Are you sure? [yes] / [no]

Similar projects