After building one of Geoff Graham's ASCII video terminals for my Arduino Altair simulator, I found myself with a couple extra PIC32MX250 microcontrollers I had ordered and was looking for a project to use them in.
Since the PIC32 could obviously be used to generate a video image, I looked into what kind of graphics extensions existed for the Altair and found two main contenders. There was Processor Technologies VDM-1 display board. However, the VDM-1 was mainly a text terminal that connects directly to the S-100 bus. Interesting - but not very different from just a regular serial terminal.
Then I came across the Cromemco Dazzler board, released in 1976. A real graphics card for the Altair (or other S-100 computers) that could produce a picture with a resolution of up to 128x128 pixels in single-color mode or 64x64 pixels in multi-color mode with 15 different colors.
According to Stan Veit, who in 1976 placed a TV connected to a Dazzler in his computer store's window in NYC: “People driving by began to stop and look – they had never seen anything like it before. In a short time the Dazzler had caused a traffic jam on 5th Avenue!” The police had to contact the building landlord and make him disconnect the television [Wikipedia].
That seemed like a worthy project to devote some time and energy to!
BTW - the program Stan was running on the Dazzler was this:
Here's a video filmed directly off my TV. It really looks much better in in real life - my camera(-work) is less than stellar.
Ultimately I imagined a separate board that could be plugged into the Altair simulator's native USB port (since that port is not generally used).
Note that the original Dazzler, as it produced the picture line by line, read the video data directly from the Altair's memory via DMA, so in the above architecture the arrow from Altair to Dazzler would go the other way and use the Altair's address/data bus instead of USB.
Doing the same in this project would require too much data constantly being sent over USB. It wouldn't actually saturate the USB bandwidth but it would likely slow down the Altair simulation. A more efficient solution was to keep a copy of the screen memory in the simulated Dazzler and send updates to the Dazzler whenever the memory area devoted to the Dazzler was modified in the Altair.
Before starting to work on any hardware I wanted to make sure that the basic concept would work. So to start I wrote a Windows application that just runs on a PC which connects to the Altair simulator via USB. Working out the details of how the Dazzler produces the picture in its different video modes took a while but was certainly easier to debug on Windows than when running on a PIC. I was also able to confirm that the communication between Arduino and Dazzler client would not slow down the Altair emulation, even when running a demanding program with fast picture changes like the Kaleidoscope.
The Windows client is included in the GIT repository, so anyone wanting to try out this project can do so without any extra hardware (assuming they already have the Altair simulator). If you are not interested in building the hardware you can just skip ahead to the "Using the Dazzler" section below.
Of course running the Dazzler application on a PC is less satisfying than having a complete hardware implementation of a Dazzler. So the next part of the project was to (a) figure out how to produce a video signal on a PIC32 and (b) how to connect the PIC32 to the Arduino via USB.
Producing a video picture directly requires exact timing - otherwise the picture becomes distorted or wobbly. Geoff's terminal implementation uses the SPI device in the PIC32 to push out the video data to a pin. While that produces very precise timing, I couldn't use it because SPI only outputs 1 bit. That works for a single-color video terminal but is not enough for a 15-color graphics card - I needed to output 4 bits of color information synchronously.
Searching the web for solutions that others may have come up, I found Paul Boddie's blog post about his color VGA signal generation on a PIC32. Paul did an awesome job describing the challenges and his solutions to them. Instead of the single-channel SPI he ingeniously used the DMA device in the PIC32 to write out pixel data, 7 bits at a time for an impressive 128 colors - all while keeping the CPU load to a minimum!
While - for various reasons - I ended up not using the DMA implementation and instead am pushing out pixel data directly from the CPU, Paul's great write-up of his endeavor was immensely helpful to get me on the right track. Thanks Paul!
After a lot of more experimentation, frustration and finally success, the result is a pretty stable VGA picture that (I believe) reproduces the Dazzler output pretty well. The reason it produces a VGA signal instead of a more time-period appropriate Composite video is two-fold: for one, creating a color composite signal requires much more precise timing than VGA. Secondly, few monitors these days even accept a composite signal. VGA too is becoming rarer but there was no way I could produce HDMI without adding more specialized hardware, so VGA it is.
After getting the VGA picture generator to work I set out to implement the actual Dazzler client code on the PIC32. That wasn't too hard (since I had already figured out most of the details when writing the Windows client). Communicating with the Altair/Arduino however was another matter. USB is a very versatile protocol but that versatility comes with the cost of high complexity. In order to not get lost, I started by using serial communication instead of USB. Turns out both the Arduino Due and the PIC32 can communicate via serial at exactly 750000 baud. That was plenty fast for the communication and allowed me to focus on getting the Dazzler emulation to work.
The last piece of the puzzle was to finally tackle USB. I wanted to use the Arduino Due's native USB port which is mostly unused in the Altair Simulator. The Due can operate its native USB port as a host, so client devices can be plugged in. However, the Due's firmware is quite restricted in the kind of devices it can support. I needed serial-over-USB communication, and that is not supported. However, the PIC32 can also operate as a USB host and its firmware does support serial-over-USB clients. And the Due's native port can act as a serial-over-USB client. So, from the USB point of view in my implementation the Dazzler is the host and the Arduino is a device plugged into the Dazzler. Sort of the wrong way around but it works.
Note that the Due actually provides 5V on the USB port even though it is running as a device (not a host). The Dazzler (host) uses the power provided by the device. Also the wrong way around and certainly not conforming to USB specifications but this is not supposed to be a generic USB host - it only needs to work with the Arduino Due. And that it does:
The VGA standard requires 5 signals to define the picture:
- Horizontal sync (TTL level, signifies the end of a line)
- Vertical sync (TTL level, signifies the end of a frame - i.e. a full picture)
- Red, green and blue color data (0-0.7V)
The 3.3V-level output pins of the PIC can be directly connected to the TTL-level VGA sync signals so that's simple. The software running on the PIC generates the SYNC signals using a timer and output compare functionality available on the PIC32, see the comments in the source code for more information.
For the pixel data, the PIC software outputs the same 4 bits of color information as the Dazzler: red on/off, blue on/off, green on/off and intensity on/off (RGBI). If intensity is on, the pixel should be bright otherwise it should be darker. If all color bits are off, the intensity bit is ignored (i.e. there is no bright black). That results in 15 possible colors.
In addition to color mode the Dazzler can be switched into gray-scale mode. In that mode the four color bits are used as a scale to define the brightness: all off is black, all on is white and in between are different levels of gray.
Converting the five digital bits of information coming out of the PIC to the three analog 0-0.7V levels required some more hardware, but not much:
- Resistors to drop the voltage for the color channels
- Three AND gates and resistors to boost the voltage if the intensity bit is on
- Four diodes and a four-resistor ladder to generate the gray-scale levels
- A 4053 analog switch to switch between the color and gray-scale output
The final circuit looks like this:
I determined the resistor values by experiment. They work fine on the three monitors I have tested them on and I verified the signal levels on a scope. Still, I'm just a hobbyist and can't guarantee that this will work on every monitor. Build/use at your own risk!
The Dazzler itself was just a graphics card but Cromemco also offered the D+7A digital/analog I/O card as well as the JS-1 joysticks which could be plugged into the D+7A. Some of the software available for the Dazzler (mostly games) is only usable with a joystick so it seemed like a waste to not also support joysticks.
The PIC32 has built-in A/D converters, so hooking up a thumb joystick is simple. I wanted to support two joysticks and since each joystick has four buttons I ran out of GPIO pins on the PIC. A shift register was the solution for that problem.
The prototype joysticks I built are not exactly pretty but they work very well (you can see them in the picture in the "Final thoughts" section).
To build the Dazzler hardware, please refer to the schematics (available in Fritzing and Eagle format). I personally like to build my projects on stripboard, so the Fritzing file contains the stripboard layout I used for my prototype here:
I don't really have plans for making a PCB but maybe somebody else will...
Not all parts included in the schematics are required, the video circuit will work fine without these:
- The joystick part. If you do leave it out, I would recommend grounding pins 2, 3, 25 and 26 of the PIC32 via 100k resistors to prevent the Dazzler from continuously updating the Altair simulator with random joystick positions.
- The ICSP connector is only necessary if you want to program the PIC32 within the circuit. If you have other means to program the PIC32 you can leave it out. Just make sure to pull pin 1 high via a 4.7k resistor.
- The Reset and Test buttons are also not necessary (but are very useful for testing).
The firmware for the PIC32 is in the GIT repository (PIC32/firmware). You can either use the MPLAB IPE to upload the dazzler-usb.hex file directly or load the project in the MPLAB IDE to compile from scratch and upload.
If you end up building the hardware, there are a few test modes built into the software that allow you to test the video generator and joysticks:
Holding the Test button (connected to pin 17 of the PIC) down during power-up or reset will first display a color test picture. Each following press of that button cycles through three different screens: the color test screen, a gray-scale test screen and a black-and-white grid pattern.
Holding any button on one of the joysticks down displays a joystick test screen that shows a white pixel representing the joystick position in the center of the screen and four blue/green pixels in the top-center that represent the state of the four buttons:
Once you have tested the basic video functionality I would suggest to run the "Kaleidoscope" program first, as it does not require any inputs and should immediately start filling the screen.
This works just the same whether you're using the Windows software client or the hardware implementation.
- First you need to update the Altair simulator to include Dazzler support. Download the latest firmware for the simulator from its GIT archive.
- Load the
config.hfile into an editor and change
#define USE_DAZZLER 0to
#define USE_DAZZLER 1
- Upload the new firmware to the Arduino Due using the Arduino IDE
- Enter the configuration menu and set the Dazzler option to "USB Native port"
Now connect the USB cable from the Arduino's native USB port to your PC or the PIC. If you are using Windows, you may have to select the proper serial port in the application (tip: if you start the Windows application first and then connect the USB cable, the application should automatically select the correct port).
The updated Altair simulator firmware includes a the Kaleidoscope program (program #16). To start it, set SW7-0 switches to 00010000 and press AUX1 down.
A number of additional examples are provided on a disk (disk #16 or #10h). Mount the disk and run the boot loader. This will boot CP/M. You can now start the different programs on the disk from within CP/M. Note that none of these programs have any exit mechanism, so to run a different program you will have to stop and reset the Altair and boot into CP/M again.
- DazzleDoodle (very basic drawing program operated by joystick)
- DazzleMation (basic animation program, needs text input, see below)
- DazzleWriter (allows to type text, reads text input from 2-SIO card)
- Life (Conway's game of life, needs text input, see below)
- Track (needs joystick)
- Chase (needs two joysticks)
- Space War! (needs two joysticks)
- Gotcha! (needs two joysticks)
- Tank War! (needs two joystick and Z80 processor)
- Ambush (needs one joystick and Z80 processor)
- Dogfight (needs two joystick and Z80 processor)
- Chess (Microchess using the Dazzler as a graphics display)
The DazzleMation, DazzleWriter and 4d Tic-Tac-Toe programs require keyboard input from a Cromemco serial interface. This serial interface behaved very similar to (but not the same as) a SIO card. The new Altair simulator firmware includes an option for the SIO card to emulate the Cromemco serial interface. To activate, go into the configuration menu, select the SIO configuration option and then change the "Revision" setting to "Cromemco".
Note that the Windows Dazzler client application will recognize joysticks plugged into the Windows PC and send the joystick data to the Altair. It will also capture keypresses and send them to the Altair as if they were coming through the SIO input, which is helpful for DazzleMation and DazzleWriter.
Here are some screen shots from the programs:
The final step for me will be to find a project box to put this in (maybe I should have thought about the box dimensions before making the stripboard layout...).
All in all I'm pretty happy with the way this turned out, most notably that the end result functions exactly as initially imagined - not every project works out like that. There are a few artifacts in the video generator that I could live without (see the black stripes in the grayscale test picture) but overall the picture is really crisp and stable.
I would like to thank Paul Boddie for his very useful information about VGA picture generation using a PIC32, as well as Udo Munk of z80pack for tracking down and collecting the original Cromemco software and documentation.