Terminalscope Serial Console

February 2010

IMG_0377

Jan might have created a cool scope terminal, but I've done him one better. ;-) The Terminalscope is a full, bidirectional serial terminal that uses a PS/2 keyboard for input and displays 54x24-character output on an oscilloscope or XY display. It can be connected to a PC via USB-to-TTL adapter or directly to another microcontroller.

Features include:

IMG_0393
IMG_0395
Close-ups of the screen. Terminalscope is connected to a Linux box as a serial console.
More photos on flickr.

hardware

A great thing about the Terminalscope is its simplicity. Other scope projects require an expensive DAC or an inaccurate R-2R ladder. Rather than draw each character with individual strokes, op-amps are used to generate a raster scan across the screen (like a TV) and the Z axis (beam intensity) is modulated directly by the microcontroller.

Two op-amps are used as integrators to generate the X and Y linear ramps. A high slew rate, single-supply chip like the MC34074 works. (A TL3474 might work as well.) Since the op-amps are single-supply, a 2.4V zener diode is used to create a virtual ground. To generate the positive-going sweep for the X axis, a constant voltage slighly below virtual ground is fed into the X integrator. (Remember, the output of an integrator is inverted.) To generate the negative-going sweep for the Y axis, a constant voltage slightly above virtual ground is fed into the Y integrator. The two trimpots controlling these voltages can be adjusted to change the size of the image or even flip it. Due to the virtual ground, the output of the integrators has a significant dc offset. To compensate for this, large ac-coupling capacitors are placed inline with the X and Y outputs.

The video generation and serial communication is handled by an ATmega328P. (1296 bytes of RAM are required for a 54x24 character matrix, but if you'd like a lower-resolution display, an ATmega168 would work just fine.) The microcontroller sends horizontal and vertical "sync" pulses to a 4066 quad bilateral switch; closing a switch discharges the respective integrating capacitor, resetting the sweep. Since the timing of the video generation is critical, the ATmega328P can't read asynchronous events from the keyboard without mangling the picture. So an ATtiny45 is used to read the PS/2 keyboard lines. It converts scancodes to ASCII values (and non-ASCII keypresses to special values) and stores them in a queue. After the 'mega is done outputting a frame, it pulls the typed characters out of the 'tiny's buffer over SPI.

software

The time-critical display routine is written in assembly language. The ATmega328P outputs one pixel every 5 clock cycles. It runs at 20MHz, thus the pixel frequency is 4MHz. Thus, your scope or monitor must have at least 4MHz of Z-axis bandwidth.

The rest of the code, including a fairly complete video library, is written in C. It emulates "most of" a VT100; that is, enough escape sequences are implemented so that Unix console applications display correctly. I've made the code available at the bottom of the page, and it might be useful for anyone looking to implement their own terminal. Escape sequence handling are pretty much a nightmare.

connecting to a linux box

With a USB-to-TTL serial adapter (I use the one made by SparkFun), the Terminalscope can be connected to a computer. In Linux, you can talk to it using screen, like this:

screen /dev/ttyUSB0 38400
(assuming the adapter is at /dev/ttyUSB0 and the Terminalscope is set at 38400 baud, 8 data bits, no parity, 1 stop bit.) If you want to give Terminalscope a login process, so you can shell into your machine from it, you'll have some configuration files to tweak. In Ubuntu (Karmic and newer), paste the following into /etc/init/ttyUSB0.conf:
start on stopped rc RUNLEVEL=[2345]
stop on runlevel [!2345]

respawn
exec /sbin/getty -L 38400 ttyUSB0 vt100
You can now start the login process with the command sudo start ttyUSB0.

One last thing. When you log in, Linux will think the terminal is 80 columns wide (it's really 54) and will assume it supports UTF-8 (which it doesn't). To fix this, you should add the following to your .bash_profile (assuming you use bash):

if [ "$TTY" == '/dev/ttyUSB0' ]; then
    stty cols 54
    stty rows 24
    export ROWS=24
    export LINES=24
    export COLUMNS=54
    export LANG=POSIX
fi

making your own

Be warned if you're going to make your own: your mileage may vary. A big XY monitor will probably work better than an oscilloscope. I haven't been able to get a clean picture on my Tektronix 464, but there may be something wrong with its Z axis. Some things to note:

code

The code is on GitHub and is released under the msarnoff.org license. Includes a Makefile for avr-gcc. The firmware for the ATtiny45 keyboard buffer is in the keybuffer/ folder, and the display font (as well as a Ruby script to create your own font from an ASCII .pgm image) is in the fonts/ folder.

Feel free to use parts of it in other projects; I've written a fairly complete escape sequence parser that might be useful for other terminal projects. The code is released under the "do whatever you want with it, but if you make something cool, let me know and give me credit" license.

links/resources

photos

Photo gallery is on Flickr.

schematic


(click to enlarge)

Download gEDA schematic: scoperaster.sch
May require custom symbols from my symbols directory.

pcb

IMG_0413

The Terminalscope is now officially off a breadboard and on a PCB. It's a dual layer board, but the top layer is entirely a ground plane. The circuit would probably fit fine on a single-sided board. Here are some things I've noticed:

Aside from that, it's not too bad for a first prototype. If you want to make your own, download the following: