January 11, 2007

Fun with cheap graphic LCDs

The goofballs over at Marlin P Jones had these huge (8.5" x 4.5") 480-pixel by 128-line graphic LCDs on sale for $7/each. Surplus, you know. The gotcha: no controller! Gotta roll yer own. And the data sheet isn't all that informative. So what to do?

In the pile of electronic stuff in my lab, I have a Xilinx Spartan3 FPGA development board from Digilent and a Prototype board for Silicon Labs' C8051F340 8-bit microcontroller. All of that, plus some ribbon cable, a power supply and the necessary development tools (Xilinx' ISE 7.1 and Keil's C51 compiler), and a few hours on a weekend were all that was needed to make this work.

An easy demonstration design is to use the display as a text terminal. I could have put a micro of some sort into the FPGA but the '340 is more convenient, and I figured I'd use the micro's USB interface as the data source. So anyways, I partitioned the design and put some of the smarts into the micro and some into the FPGA. The basic breakdown is as follows:

FPGA: The GLCD interface is in the FPGA. Here, we generate all of the lclocks and strobes and data lines needed by the GLCD. The FPGA also contains the dual-port display buffer, implemented using Xilinx block RAMs. The top-level module is glcdtest.vhdl.

The FPGA gets its 48 MHz global clock from the micro's SYSCLK output. The FPGA interfaces one side of the display buffer block RAMs to the micro's EMIF. Note that the micro side of the display buffer is read/write, so if the micro wishes to read a location (useful for blinking characters at the cursor location), it can do so. This is handled by the dispbufctrl.vhdl module.

The 48 MHz clock is also fed into a DCM where it is divided down to a 4.8 MHz clock (which is four times the 1.2 MHz LCD clock). This "4x pixel clock" runs the GLCD timing and buffer memory access. The DCM is instantiated in gdcm.vhdl.

glcd.vhdl contains the logic that interfaces to the GLCD. It has counters that keep track of the current display row and column as well as generating the display buffer address for the current pixels. All clocks and strobes for the GLCD are generated here.

ps2kbdif.vhdl provides the logic that reads keypresses from a standard PS/2 keyboard. (The Digilent board has a PS/2 port.) The raw keycode bytes are then sent to the micro over SPI using the spimaster.vhdl module. The SPI clock is sourced by the FPGA and is the same as the 4x pixel clock. This means the SPI port is clocked at 4.8 MHz.

Micro: The C8051F340 micro gives us an RS-232 interface (see uart.c) to a host computer (USB at some point). It implements the character generator ROM (see charmap.h), and deals with writing to and reading from the display buffer (display.c). The main program loop (in main.c) keeps track of the current cursor location, which is given in terms of character size (8 x 8 pixels). This means that when the cursor is at location (4, 2), the upper-left corner of the cursor is at pixel location (32, 16). Note that (0, 0) is always the upper left corner.

It's interesting to note that the microcontroller sees the display buffer memory as 8 bits wide but the display controller sees it as 4 bits wide. This is further complicated by the fact that the display is divided into four quadrants, and the display interface's 4-bit data bus loads one pixel for each quadrant at a time. The micro sees the display buffer as 8 bits wide and loads 8 pixels in the same quadrant at a time. The comments in the sources should (hopefully) explain how each side of the dual-port buffer addresses things, as it's not exactly straight-forward.

Here are the FPGA sources, fitter project and test bench. The fitter project is compatible with Xilinx ISE 7.1i SP4 tools. The test bench has been tested using ModelSim XE III 6.0a.

Here are the microcontroller sources. The project file is for Keil uVision 2 and C51 version 7.04.

To Do:

Note that the micro doesn't do anything with the SPI input as of now (11 Jan 2007 with firmware rev r840). This means you can't connect a keyboard to the FPGA board's PS/2 port and have things you type show up on the display.

I have a LinkSys NSLU2 network-attached storage device running Debian Linux (instead of its native firmware) and it'd be nice to use this thing as a display terminal, so (for example) when booting I can see console messages.

It'd be great to make the display a generic graphic display, instead of a text terminal display. The FPGA logic should remain the same as it's just the display buffer and timing control. The question then becomes how should the micro handle writing to the display?

Obviously, communicating to the host over USB instead of RS-232 would be cool. One thought is to make the display compliant with the USB Video class, advertising itself as a simple monochrome graphics terminal. Then we'd have to handle how we draw things. This could be interesting.

Posted by Andy at January 11, 2007 03:26 PM
Comments