# Interfacing with a graphic lcd

I am ordering a graphic lcd NHD‐12864AZ‐FL‐YBW and most of the interface code seems pretty simple. On the datasheet it has the following list of commands

I don't understand what is put in the write display data command to draw something to the screen. For example, how would the pixel at (5, 8) be turned dark). I looked through the datasheet but could not find anything.

As Wouter pointed out, you cannot directly write to a single pixel.

The display matrix basically behaves as a monochromatic bitmap. It is physically divided between two identical controllers, one for the left half, the other for the right half. Their data/strobe lines are wired together and you can select the one to talk to by the chip select pins, CS1B and CS2B. Both are active high and both halves of display would be written simultaneously if you had asserted both CS pins.

The display is vertically divided into eight pages, which are laid atop one another, making eight pixel high rows. These vertical eights of pixels are connected with bytes of the page and each page has 64 bytes. Hence,

• 8 pages * 8 bits = 64 rows
• 2 controllers * 64 bytes per page = 128 columns

for the whole display. Nice picture of the memory layout can be found here.

For example, how would the pixel at (5, 8) be turned dark).

I assume that with (5,8) notation you mean fifth column from the left and eighth row from the top, as is widely used in computer graphics. Unfortunately, manufacturer of the controller calls the vertical coordinate (page index) X, which is pretty confusing.

1. Row no. 8 belongs to page no. 1. You need to issue Page Select command with the argument 1, that is 00 10111001 for bit values in the table.

2. After this, you need to issue Set address command to set the column index 5, that means bit values of 00 01000101. Now the "cursor" of the display is set to the byte containing the specified pixel.

3. Now you can write desired contents of the byte via command Write Display Data. Eighth row is the LSB of page 1 and a logical one on this bit makes your desired pixel dark.

Unfortunately, you can only write a whole byte. Thus, you need either a copy of the display contents in your MCU's RWM, or first read the current value from the LCD (command Read Display Data), perform logical OR with 0b00000001 and write back.

Note that the address on the page (Y register) advances automatically as you write data. You can easily fill the whole page just by sequential writes - if you have enough memory in your controlling MCU, you could just allocate a block of 2*8*64=1024 bytes, keep and manipulate the bitmap there and send the whole display contents/modfied pages upon request. This depends on your application.

This protocol is very common for the GLCD 128x64 displays. I believe you could also find a ready-to-use library for your MCU, providing you with some basic graphics (line, rectangle, possibly even ellipse) and/or text output without directly manipulating the LCD.

That looks like a PCD8544 LCD controller (as found in the common Nokia 84 x 48 BW display). The full explanation is in the datasheet :) There is no command to change a single pixel, but you can write a byte (8 pixels, oriented vertically). To change a single pixel, you must either remember the byte value (store it in the uC in an array), or read it first. Then change the one pixel, then write the byte to the LCD. This is (part of) my driver for such an LCD. It stores the 'image' on the uC, so at the cost of some RAM (504 bytes) it avoids having to read each byte first.

void lcd5510_pixels( unsigned char x, unsigned char y, unsigned char d ){
lcd5510_command( 0x80 | x );
lcd5510_command( 0x40 | y );
lcd5510_data( d );
}

unsigned char lcd5510_buf[ 504 ];

void lcd5510_write( unsigned int x, unsigned int y, unsigned char d ){
unsigned int a = x + ( y / 8 ) * 84;
unsigned int m = 1 << ( y % 8 );

if(( x >= 84 ) || ( y >= 48 )){
return;
}

if( d ){
lcd5510_buf[ a ] |= m;
} else {
lcd5510_buf[ a ] &= ~m;
}

lcd5510_pixels( x, y / 8, lcd5510_buf[ a ] );
}


A probelm with this group of LCDs is that there seem to be at least two different conytrollers (the real PCD8544 and some clone) that require silgtly different initialization to work at all. My init code is (after pin configure, reset etc.(:

   // inspired by https://www.sparkfun.com/products/10168
lcd5510_command( 0x21 );  // select exteded instructions
lcd5510_command( 0xC8 );  // Vop = 110000b
lcd5510_command( 0x06 );  // TCx = 00b
lcd5510_command( 0x13 );  // BSx = 100b
lcd5510_command( 0x20 );  // select basic instructions, horizontal addressing
lcd5510_command( 0x0C );  // normal mode