Interfacing 128x64 pixel graphics LCD with μC

Well, I wanted to integrate a touch screen in a project that used a 8-bit PIC and nothing else was more resource friendly to use, other than a 128x64 graphics LCD with a resistive touchscreen overlay.

Before this, I had only worked with the conventional JHD402A controller based 16x2 line LCD modules - and those were pretty easy to work with; mainly because of the ease of sending desired data to be displayed. Manufacturer datasheet and various application notes also provides comprehensive interfacing algorithms which gives a quick start. Moreover, it's the favorite child of the open source community which means enormous online support without the need of any licensing worries.

A graphics LCD (GLCD) does not have an inbuilt ASCII converter/generator; rather you can control state of a single pixel and hence its not easy to send data to it. Well, that is the primary reason to use GLCD. If you just want to display alphanumeric characters, a 16x2 or a 16x4 LCD is a better choice.

I bought a NT7108C controller based GLCD (which is quite similar to KS0108B module). Even though being a more complicated device than a 16x2 LCD, the datasheet that manufacturer provided along with the module was poorly written and technically insufficient - and I realized this after getting one. When I developed the code referring the provided timing diagram, GLCD just didn't respond. It took better part of my time to fully iron out all the assumptions that I had made due to lack of relevant information in the datasheet and optimize the firmware, before the GLCD gleamed with a Hello World!

I would like to document the architecture here for my own ready reference, and for anyone who would like to have a quick start.

Architecture:

A 128X64 GLCD has 128 columns and 64 rows:

  1. The 128 columns are divided into sets of two 64 columns; each controlled by independent NT7108C controller (yes - there are two NT7108C chips). The columns are addressed by Y address. Thus, for both the sets (both the controllers), Y varies from 0 to 63 (0x00 to 0x3F).
  2. The 64 rows are divided into 8 pages of 8 rows (bits) each. Each page can be addressed by X address (or a page address) which varies from 0 to 7 (0x00 to 0x07).
  3. Each page comprises of 8 bits x 128 columns (Y address) = 1024 pixels. A byte is a row of a page with its LSB (i.e. D0) on top and MSB (i.e. D7) at bottom. Writing digital '1' to a pixel, turns it on and darkens it. Thus, if you send 8 bit data, say 0xFF to (X,Y) = (0,0), all the 8 pixels of 1st column of 1st page turns on.

To control the other half - the right side of the display, you need to activate the NT7108C controller of that section and repeat the procedure. There are hardware pins to select a specific controller.

Pin Layout:

The pin layout is comparable to the 16x2 LCD module. Let me quickly go through pin functionality:

  • Pin 1 & 2: These are chip selection lines. A low on CS1 selects the NT7108C of right half of the screen and low on CS2 selects the other half. If you want to write simultaneously on both the halves, you can select both. CAUTION: Refer your manufacturer datasheet to know active levels of these pins.
  • Pin 3 & 4: These are power supply lines for the module. Works on +5VDC.
  • Pin 5: This is GLCD contrast control. Connect this pin to the viper of a 10kΩ pot. One end of the pot goes to gnd and the other goes to pin 18 (Vee) of the GLCD. If you prefer programmatic control over the contrast, connect it to PWM output of you microcontroller and drive via that.
  • Pin 6: RS (D/I) - This is data / instruction selection pin. A high on this pin indicates to the NT7108C that a data byte is being written and a low indicates that an instruction is being fed.
  • Pin 7: RW - Read/Write pin - A high on this pin enables reading from NT7108C and low enables writing to it.
  • Pin 8: E - Enable pin - A high on this pin enables the GLCD and a high to low transition latches the data (read or write). For exact timings of these, refer the datasheet of your specific module.
  • Pin 9 to 16: Data lines from LSB, D0 to MSB, D7.
  • Pin 17: RST - Reset line - A low on this resets the module. While working with GLCD, this must be held high. If you have a spare IO, use it to reset the module programmatically.
  • Pin 18: Vee - Negative voltage output pin - refer description of pin 5, above.
  • Pin 19 & 20: These are back light LED lines. +5V with proper polarity on these lines lights up the back light. Although GLCD internally consists of a limiting resistor and you can directly feed in +5V to these lines, I would recommend to add a small resistor of 20Ω in between. To control the backlight, you need to give PWM signal via a switching transistor like BC846. Again, If you prefer programmatic control over the contrast, connect it to PWM output of you microcontroller and drive via that.

Data v/s Instructions:

To control the page, line and cursor positions, we need to send instruction bytes over the data bus. The module needs to be told that it is an instruction as opposed to a data byte by pulling RS (D/I) (pin 6) low.

Line number (row selection): There are 8 lines (rows) and any of them can be selected by setting the L2, L1 & L0 bits in this instruction byte:

|1|0|1|1|1|L2|L1|L0|

Cursor location (column selection): Once the row is set, any of the 64 columns within that row can be selected by setting the C5 through C0 bits of the following instruction byte:

|0|1|C5|C4|C3|C2|C1|C0|

Algorithm:

Ok, now with the details aside, this is what needs to be done to start writing to the GLCD:

  1. Select page: By driving appropriate CSx line.
  2. Select line:
    1. Pull RS (D/I) (pin 6) low and E (pin 8) low.
    2. Send instruction byte (0xB8|L); where L ∈ [0, 8].
    3. Latch the instruction by creating L-H-L of at least 75 ms width.
  3. Select column:
    1. Pull RS (D/I) (pin 6) low and E (pin 8) low.
    2. Send instruction byte (0x40|C); where C ∈ [0, 63].
    3. Latch the instruction by creating L-H-L of at least 75 ms width.
  4. Send data:
    1. Pull RS (D/I) (pin 6) high and E (pin 8) low.
    2. Send data byte.
    3. Latch the instruction by creating L-H-L of at least 75 ms width.

Here is the full set of instruction set from manufacturer:

References & Further Reading:

Related but unrelated:

  • To the processor: "Why don't you open up and display something?" (On debugging a 8-bit processor with display)