Oscilloscope Graphics with the TI 99/4A Computer
I recently came across videos on YouTube showing how to use an arduino to create graphics on an oscilloscope. The basic idea was to use a digital to analog converter (DAC) to convert digital signals from the arduino into analog voltages which could be then fed into an oscilloscope set up in XY mode to create what essentially amounts to cartesian drawings. It certainly looked simple enough conceptually, and I figured I should be able to use the TI 99/4A computer's parallel port to re-create the same thing.
First off, I needed to make sure that I had the proper oscilloscope. We are all familiar with the standard oscilloscope mode, which is voltage against time. However, most 2 channel oscilloscopes have a special mode called XY mode, where one channel would be X (horizontal) and the other channel would be Y (vertical) in cartesian geometry, with the oscilloscope displaying a point of light at the intersection of the X and Y voltages. So in essence, by varying the X and Y voltages appropriately and rapidly enough, one could draw an image on the screen.
While one could use a modern digital oscilloscope for this, the latter would require quite a high rate of data transmission in order to give a decent image. Far better is to use an old school CRT based oscilloscope where the the phosphorous on the screen will decay relatively slowly and thus give a usable image at much lower data transfer rates. As luck would have it, I had picked up a used but perfectly functional Tektronics 2213A 2-channel oscilloscope a couple of years ago for under $100, and it was the perfect device for this project.
Next I focused on constructing a simple DAC based on the R2R ladder design. Here's an excellent tutorial video which goes into all the gory details about that particular type of DAC:
The TI's parallel port is an 8-bit port, and therefore if I want to output 2 channels (one for X and another for Y), I would be limited to a 4-bit resolution for each channel. In other words, I can only output digital values from 0-15 for each. That's a pretty low resolution, but it is what I have to work with. I suppose I could have created some form of multiplexer to expand my channel resolution, but I wanted to keep the external hardware as simple as possible.
Here's the circuit I came up with:
Technically the resistors should have been at an exact ration of 1:2, but it's really not that critical as long as they're close enough to that ratio. I used 1K and 2.2K resistors because that's what I had on hand, but you can use any other values you want as long as the 1:2 ratio is maintained. The capacitors' value is very important in order to bridge the gap between the points on the oscilloscope screen. If they are skipped then all you get is points with no lines connecting them. Too low a value and the lines are very faint, too high and you get distortions. I came up with the 4.7nF value through trial and error, although there has got to be a more scientific way to go about it
The DAC is divided into 2 separate sections, one for each channel. Since the voltage increases from left to right, it is important to pay particular attention to the wiring of the parallel port data lines which go from D0 (MSB) to D7 (LSB) as noted in the schematic. Initially I had wired it straight from D0 to D7, and it took me a while to figure out why the darn thing was not working since the higher order bits were producing less, not more voltage than the lower order ones!
And here's the finished product. I just used a proto board and did point to point connections for simplicity.
I use a parallel port breakout board to access the various lines on the parallel port.
The breakout board is connected via a ribbon cable to the PIO port on the RS232 card in the TI Peripheral Expansion box.
The oscilloscope probes attach to the board as seen above. Yup, it's a rat's nest of wires, but it works!
With the hardware in place, it was time to start working on the software side of things.
Drawings are encoded using a simple cartesian system. Since we have only a 4-bit resolution per channel, each X and Y axis will go from 0 to 15, and for each point we want to send out all we have to do is figure out its coordinates on the 16x16 grid and convert that into a single binary number we can put out to the parallel port. The X axis uses the upper 4 bits of the port, the Y channel uses the lower 4 bits. Therefore, the formula for converting the cartesian coordinates to a binary number is X*16+Y.
For example, if X=5 and Y=1, then we would output 5*16+1=81 (01010001 in binary). What the DAC will see is 0101 (5 decimal) on X and 0001 (1 decimal) on Y, and therefore it is obvious that the voltage on X will be higher than on Y, so the point displayed on the oscilloscope screen will be 5 units to the right and one unit upwards, with the 0,0 origin being on the lower left corner.
With that in mind, I wanted to create a program with an integrated drawing editor which I could use to create the drawings on a grid, then have the program do the appropriate coordinate conversions and send out the result to the parallel port. I was initially hoping to use Rich Extended Basic exclusively taking advantage of its CALL IO feature to access the parallel port, however it turned out that it was not fast enough to beat the phosphorous excitation decay time on the oscilloscope screen and all I was getting was points. So I ended up using Extended Basic for the editing and conversion functions, along with a support assembly subprogram to actually send the data to the parallel port with a maximal rate measured at about 27.3 kHz.
That output frequency was barely enough however to give a good image on the oscilloscope without flicker and nice lines between points, but adding even a simple keyboard scanning routine to allow the assembly subroutine to return to Basic would slow things down causing the lines between the points to start fading as the phosphorous excitation decayed. Therefore, once the port output was initiated, there was no way to return to editing and the computer would have to be rebooted...
I also wanted to have the option of rotating the drawing in the X axis, and this worked, but delays needed to be introduced after each rotation frame during data output to the port in order to not have all the frames blurred together, and this led to very faint lines between the points since the output frequency went down accordingly...
Here's the Extended Basic program
All the calculations are being done in XB, and then the final data is sent to a reserved memory area in lower memory where the assembly subprogram accesses it and sends it out to the parallel port. That way the throughput speed of the port is maximized. Rotation of the drawing is actually done by using a sine function to remap the coordinates of the drawing around its center, thus giving the illusion of rotation around the X axis. Only a total of 16 frames are pre-calculated given the low resolution of the drawing as more frames would not result in a significant improvement in the rotation effect.
And here's the assembly support subroutine:
Notice that it does not return to XB once an image is sent out the parallel port, and just loops around.
And finally a short video demonstrating the project:
On to the next thing