My original final project plan was to do something like this: a self-stabilizing handheld projector. I still like the idea, so I hoped to do half of it this week (output to VGA) and half in two weeks (input from gyroscope). As you can guess from "hoped" and "try", I didn't quite make it. I felt ambitious this week so I decided to try to get VGA output from an ATMega328p.
Step 1: What is VGA?
VGA is a surprisingly simple protocol. It was designed for CRT displays, so there are just three analog pins for R/G/B and two timing pins for syncing horizontally and vertically.
Step 2: Do the impossible
VGA resolution is 640 x 480 with a refresh rate of 60Hz. This adds up to (480 * 640 * 60) = 48 million pixels per second (1 pixel every ~40 nanoseconds). Even with an external 20Mhz resonator, this is just faster than the atmega can handle, even in theory (this is just as well, since even at 1 bit per pixel, 640 x 480 is also more data than it could store). So full-resolution, color, or bitmaps are all independently (not to mention jointly) impossible.
But that doesn't mean we can't get it to display things! Nick Gammon has a beautiful writeup on this exact problem. His solution was to relax the resolution and display 4x1 blocks of pixels (4 wide and 1 tall), which is possible because the horizontal sync pulse has a width of 96 pixels (once every ~3.8 microseconds), so we can set each pixel slower and the display will interpret it as a chain of pixels of the same color. This is more manageable!
Step 3: Break everything
I bought a VGA header on Amazon and then lost it.
I designed a fabricated a new board, based on the hello.arduino,with more LEDs. Something about the board was wrong - either designed or soldering - because after making a second one I couldn't get either to program.
I then just milled the exact hello.arduino board. But I accidentally tore the data pins off the board, ripping up the traces in the process. I performed emergency surgery to repair the board with a long FTDI header soldered to the opposite end.
This one programmed just fine. I modified Nick Gammon's code with updated timing calculations for 20Mhz and wired the board directly into the monitor.
It didn't work. The oscilloscope shows the expected timings: fast pixel signals (~50 microseconds), medium horizontal pulses (~5 milliseconds), and long vertical pulses (~15 milliseconds). It's possible that the voltage was too far off or that my jumper wires were too long. I also sort of suspect that an actual, analog CRT display would be more lenient in what it displays, so I'm trying to hunt one of them down to debug on as well.