UPDATE: a version with everything running directly on the FPGA including the printer can be found here.
I’ve started getting into using FPGAs. They’re really cool because when you use them you’re essentially creating hardware by typing. When you code in a hardware description language like VHDL or Verilog, you’re not writing code that a microcontroller or other processor will execute, you’re actually coding the processor itself, the actual layout of logic gates and connections between them. I had seen an example of driving an VGA monitor with an FPGA to show a pattern on the screen. I decided to see if I could do the same with a Macintosh Classic CRT and maybe push it further.
Here’s the project in action:
Here are the old Developer Notes for the Mac Classic and Mac Classic II which I found helpful:
Especially this info about the CRT timing and the power/sweep connector pinout since it was the same for both these models:
With this info I was able to write some VHDL to drive the Mac Classic’s CRT. Only 4 wires are needed, GND, VSYNC, HSYNC, and VIDOUT. As luck would have it, 3.3V is enough to trigger a logic high on this connector so I was able jump the wires straight to headers on my FPGA. I used a Mojo FPGA for this project but others should also work fine.
I built up my ability to work with this hardware in steps. First I started with displaying simple checkerboard patterns, just based on pixel position. Setting pixels either black or white as I clocked them out. Then I setup memory blocks on the FPGA and had the code clock pixel data out of that. The smiley face at the beginning of the video is from that stage. Then I setup the functionality to receive new pixel data over serial which gets placed into that memory. Since at that point I already had it clocking out of memory, anything placed into memory would show right away. Lastly, I wanted to add at least one effect, so since I had a button directly available on the board, I set it up to toggle a negative image effect.
For this first cut, I wanted to send data to the FPGA that could be used as is. So I setup a Processing sketch to capture data from my laptop’s camera and send that over serial to the FPGA. This CRT setup only does 1-bit color, only black or white. So to do even shades of gray requires dithering. I found a Processing sketch in an article from Evil Mad Scientist Laboratories that demos using Atkinson Dithering to convert an image to 1-bit:
Atkinson Dithering, Live in Processing
This was an awesome starting point, I only now had to connect to my USB to Serial cable, pack up the data and send it over. You’ll notice that the frames show with a second or so delay in-between. This is the time it takes to send all the bytes over serial. The FPGA is still clocking out frames at the CRT’s 60 fps, even as the data is slowly coming in. I could have dumped the data to a second buffer off-screen, then switched over only when all the data is sent, but I kinda like watching it as it comes in(good for initial debugging also). This does highlight another cool thing about FPGAs, you can set up as many concurrent processes as you can fit in the available gates on your chip. One could setup multiple video sources and outputs all going at the same time running off the same FPGA chip if they wanted.
I’ve posted the Xilinx project and Processing code on GitHub at:
Here’s some closeups of the project:
Some other details:
-Working with these CRTs can be dangerous(hence the “High Voltage” labels). So I don’t advise anyone to play with CRT connections unless they know what they are doing. On the really old Macs, they’ll hold their charge a long time even after being unplugged. That said, this project doesn’t involve the HV connections, and can be done in a safe manner if you’re careful. Last warning on this note, be careful of where your hand will jerk as you work a connection free. To pull that connector free don’t set yourself up such that when it gives, your hand flies up and hits the CRT.
-I used a Prolific USB to Serial cable I had on hand to send the data over from Processing, but any serial cable such as an FTDI one would work also, as long as the voltage matches what the FPGA is configured for and expecting(3.3V in my case). To make the connection in my case I stripped the ends of some short lengths of wire that I could use to jump the serial cable connections to the header on my FPGA.
-To make a tighter connection to the power/sweep connector I found it useful to fold the stripped end of the wire over itself once as pictured.