circuitben

Driving Graphic LCDs with an FPGA

I'm specifically talking about LCD screens with drivers but no controller, which means that they must be constantly refreshed by control circuitry. Having built-in drivers means that you don't have to provide circuitry to switch the weird voltages that the actual elements need. These screens are available from surplus electronics places and, for a (much) higher price, new from the usual suppliers.

These displays require almost the same signals as a VGA monitor, with a few differences:

LCD screens are raster-scan just like CRTs, but the scan rate can be completely different and is dependent on the size of the screen.

Color TFT

This display is part G13752 from The Electronic Goldmine. The datasheet for the screen can easily be found online.

This screen has a resolution of 240x160 and 9-bit color. Pixels are clocked in one at a time. Pixel data consists of 3 bits for each color component. According to the datasheet, the screen requires supplies of 3.00V and 3.80V, but the absolute maximum ratings are generous and I have had no problems running both supplies at 3.3V. The screen has a connection for a microphone but the parts aren't there, so you could use it for something else.

Connection

I connected my screen to port A1 of a Digilent D2FT board via the pin headers on the breadboard add-on board.

Since the screen has a fine-pitch flex cable, I built an adapter by soldering a connector for the flex cable (Digi-Key part OR690CT-ND) onto a 0.5mm TSSOP-40 surface-mount adapter board (from BelDynSys P507). The connector has 22 pins but the adapter board only has 20 pads on one side, so I left the two microphone pins hanging off the end of the row of pads. When connecting the flex cable, the copper pads point towards the board.

Color LCD connector
The connector and adapter board for the color LCD screen.
The two unconnected pins are on the right.
All color LCD hardware
The complete setup.

Both power supplies for the LCD screen (Vcc1 and Vcc2) are connected to 3.3V from the D2FT board. The LED backlight runs off unregulated power from the adapter (~7V in my case) through a 150-ohm resistor. This is really the wrong way to power the backlight, since there is no current regulation. According to the datasheet, the LEDs should be run at up to 15mA. My resistor provides only 6.7mA. At this current, the backlight drops 6.13V.

Code

The code consists of two VHDL files: test.vhd and lcd_sync.vhd.

test.vhd contains code specific to the D2FT board and my test code. It generates the LCD dot clock (MCLK) from the 50MHz clock provided by the board, does some simple animation, and connects signals from LCD_Sync to the LCD screen.

lcd_sync.vhd contains the code specific to this LCD screen. It generates the horizontal and vertical sync signals, keeps track of the position of the pixel currently being sent to the LCD screen, and generates a pixel enable signal so that the pixel data can be forced to zero when no visible pixel is being scanned out.

The datasheet shows the correct timing waveforms. The timing characteristics in the datasheet show that the sync pulses can have more convenient timing than the example waveforms show - the examples would require more tests on the pixel position that my code uses, but my code's output is within the datasheet's limits. The example waveforms show shorter sync pulses, but the Operating Conditions on page 8 indicate that the pulses can start at the end of visible data and continue until the last cycle before visible data is sent. This makes the sync generation code very simple.

The VHDL code can be downloaded here.

Color LCD running
The LCD with the test code running.

Notes

For some reason, outputting pixel data during a blanking interval causes the screen to get confused and the display is shifted. Outputting all zeros for pixel data when the horizontal or vertical position is outside the range of visible pixels prevents this. This is why the LCD_Sync module generates the pixel_en signal.

The line

led <= (led_counter(23) and led_counter(17) and led_counter(16) and led_counter(15)) or active;

in test.vhd is a neat trick: It makes the LED flash dimly when active is low, and stay on brightly when active is high. led_counter is a 24-bit counter clocked by the 50MHz clock provided by the D2FT board. The terms for bits 15-17 effectively pulse-width-module the LED. The term for bit 23 flashes the LED a few times per second. This is one of those things that are much simpler in hardware than in software.

Monochrome Passive-Matrix LCD

I salvaged this screen from a dead copier. It has a CCFL backlight with a seperate inverter and a 10-pin connector. It has two possible part numbers printed on it: CCL-E145V and 56AAA1357B. I could not find any information on the display itself, but I found the datasheets on the chips and from that figured out the required timing. The display has one M5839B and three M5260 driver chips. The screen's resolution is 192x64.

Front of LCD
Front of LCD
Back of LCD
Back of LCD

Pinout

Pin 1 is labelled on the back of the board. It is the pin near the center of the board.

PinDescription
1Vcc (+5V)(connected to pin 10)
2GND (connected to pin 9)
3/POFF (1 = LCD bias enabled)
4Not connected (could be connected to DF)
5RDI (row data input)
6RCP (row clock pulse), column LOAD, 4017 /CP1
7CCP (column clock pulse)
8CDI (column data input)
9GND (connected to pin 2)
10Vcc (connected to pin 1)
All signals are inputs.

Electrical notes

Drive /POFF high to turn on the display.
A 4017 and 7474 on the board are used to change the polarity of the voltage applied to the LCD elements periodically so that the average voltage is zero.

An SCI7661M is used to generate the negative supply (about -10V). Two of the three capacitors it used were bad, resulting in a negative supply voltage of about -6V. This prevented the LCD elements from being driven hard enough to show a pattern when a correct waveform was given to the drivers. This confused me for a while because without a description of the correct timings I couldn't tell if I was driving the screen correctly, and nothing showed up unless multiple rows were driven at the same time (with the same data, so the display was blurred). The replacement caps are visible on the back of the LCD.

Row driver LOAD is tied high.
4017 drives 7474 which drives DF.

Drivers shift on the falling edge of CCP and RCP.
Max clock frequency is 3.3MHz.

Pulse RCP at the end of each line.
RCP must not be high during falling edge of CCP.
RDI must be high during falling edge of RCP at the end of the first line.

FIXME - Block diagram, and explain how it works.
FIXME - Timing diagram

Connection

I removed the connector on the LCD screen and soldered color-coded wires to the pads. I only used one of each power supply pad. I crimped a pin header socket contact to each wire and insulted it with heat-shrink tubing. I didn't make a nice connector like I did for the color LCD above because there aren't that many wires and I ran out of header housings anyway.

This screen requires 5V which is supplied by a 7805 on the breadboard. The 7805 is powered by unregulated power from the adapter powering the D2FT board.

Code

The code is organized the same way as for the color LCD above. LCD_Sync generates the dot clock for the LCD because RCP must change on a different clock edge from CCP.

Monochrome LCD running
The LCD with the test code running.

The VHDL code can be downloaded here.