Back to the lab
80 column PIC video terminal
You can get this 80 character by 25 line video terminal out of a PIC18F26J11 microcontroller using only 4 resistors and a crystal*
80 x 25 character display on $99 Coby 12" LCD television using composite video input.
*You need a 48mHz PIC with 3700+ bytes of RAM. For 40 column mode you only need 1536 bytes of RAM.
The complete hookup:
R2 and R3 form a primitive 2-bit DAC. The television itself is an important part of the DAC because it provides 75 ohm termination. If you are measuring the voltage output without a TV attached be sure to add a 75 ohm resistor between video output and ground. The resistor values were chosen to get as close to the standard video levels as possible: 0.0 volts (sync), 0.3 volts (black), and 1.0 volts (white). If you substitute a 5.0 volt PIC you will need to change the resistor values.
Pin C2 is the sync pin.When it's high the video signal is ~0.3 volts (black). When it's low the video signal is ~0 volts (sync). Pin C7 is output from the video shift register. When the sync pin is high a high on C7 produces ~1.0 volt which is our white level. When it's low the output is ~0.3 volts which is our black level. It is possible to get gray scale pixels by raising C7 and lowering C2 but I do not use this combination.
Timer2 is programmed to trigger an interrupt at the beginning of each scan line. With a 14.31818 mHz crystal it fires every 908 instruction clocks (it would be perfect if it fired every 909.09 clocks).
The PIC's EUSART is used in master synchronous transmit mode as a high speed video shift register. The baud rate generator is set to zero which give us one pixel per instruction cycle (14.31818 megapixels/second). A tight loop written in assembly language loads the character code from RAM, converts it to a bitmap via a second lookup from the character generator (in ROM), and writes the byte into the transmit register. Each pass through the loop takes 16 instruction cycles and outputs two characters.
Because the user program only runs when the interrupt handler is not busy we try to spend as little time inside the interrupt as possible. Upon entering the ISR we start our 4 microsecond sync pulse before we save the CPU registers. Once the registers are saved we turn the sync off. Right now we are not doing any useful work during the backporch (8 microseconds per line) so this would be a good time to do something like service a PS/2 keyboard port.
I originally tried to implement 40 column mode by using a lower baud rate. I found that the EUSART would leave a one pixel gap between characters when I did that. As a workaround I created a lookup table which translates 8-bit wide font data into double pixel 16-bit wide output. This consumes 512 bytes of precious RAM. Another solution would be to use a 27mHz (or 28.636)crystal in HS mode (no PLL) This would give a pixel clock of 6.75 mHz (or 7.159). This would save the 512 bytes wasted on lookup table RAM and allow you to use almost any PIC without overclocking. The downside is that user programs would only have half as many CPU cycles available. Maybe I'll post a 40 column version of the code for a 27mHz crystal.
I did try to use the MSSP (SPI & I²C module) instead of the EUSART but it is not capable of continuous transmission and it left a gap between characters. If you don't "mind the gap" you could use the MSSP and free up the EUSART for communications.
The PS/2 keyboard interface is implemented using two pullup resistors and the SPI peripheral. Because of the start bit inherent in the PS/2 protocol this is only a 7-bit interface which leads to a couple of limitations with the scancodes. The numeric keypad zero key works but only transmits a code upon key release (or typematic repeat). The F5 and F7 keys cannot be distinguished- pressing F5 is the same as F7. Otherwise I was able to communicate with the 8-bit keyboard (plus parity) using only 7-bits. The PS/2 keyboard handler runs during the horizontal back porch. The PS/2 assembly code always take the same number of instruction cycles no matter which code path is taken in order to prevent glitching the video output. When the CAPS LOCK key is pressed we must disable interrupts briefly in order to transmit two bytes to toggle the LED. Hitting the CAPS LOCK key glitches the video output for a moment.
It is possible to use keyboard scanset-1 (XT keyboard) to restore the functionality of the F7 key and the numeric keypad zero but many modern keyboards only support the default scanset-2. If you're interested in the details take a look at this site http://www.computer-engineering.org/ps2keyboard/. Some legacy keyboards also support scanset-3 but it's not even mentioned in the latest Microsoft keyboard specification.
This project was inspired in part by Rickard Gunée's PIC video PONG and Tetris and partly by Don Lancaster's 1978 classic The Cheap Video Cookbook.
The next step is to finish support for a PS/2 keyboard interface. Once that's done and the PIC18F26K22 becomes available (later this quarter) we can use the second EUSART as standard serial port, creating a full fledged ANSI video terminal using only a single chip. Stay tuned!
If you have questions or comments send me some email:
This board has some extra features. The MAX3232 is optional for adding RS-232 voltage levels. The 23K256 is for future use. The audio circuit has not been tested.
This single layer board was built using PCB-GCODE for Eagle PCB 5.6 and a Tormach PCNC1100 milling machine. Zero ohm resistors on schematic may be replaced with jumper wires.
( CCS C-compiler)
|80 column HEX file||80terminal.hex|
|Eagle PCB Schematic||80terminal.sch|
|Eagle PCB Board||80terminal.brd|
September 12, 2010