Graphical LCD basic operation

Graphical LCD basic operation [VIDEO]

Platform Test Tools SAM3U2 Firmware nRF51422 Firmware Software
MPG2 USB RS-232 Converter MPG User Code AP2 Emulator TeraTerm

Prerequisite Modules


Dot matrix displays allow a lot of freedom in how information is displayed in an embedded system. Each dot (pixel) in the LCD is addressable and can be turned on and off independently from the other pixels. The MPG2 is 128 pixels wide by 64 pixels high. The pixel addresses are shown here:

|########################## BLACK EPOXY #############################|
|0,127 0,0|
| |
| |
| |
| |
| |
| |
| |
|63,127 63,0|

In general, dot matrix LCDs are written with various bitmaps or functions that can create basic geometric shapes like lines, boxes and circles. Characters are displayed in the same way – bitmaps for each letter are simply loaded into the LCD’s display RAM and in most cases the LCD has no idea it is displaying a letter vs. some random shape.

The driver to use the LCD can be quite involved and could include a lot of different features. The driver for MPG is fairly comprehensive and provides two fonts, bitmap functions, and string functions which will cover all of the basic needs of a system. We must be mindful of the resources required to update the LCD since an entire screen refresh requires 1024 bytes of data, and likewise storing a full-screen image also requires 1 kB of flash space. The main font is made up of equally-spaced characters 7 pixels high and 5 pixels wide

API Description

This API will seem far more cumbersomme than the majority of other modules for the development board as the code remains fairly low-level. Further abstraction is of course possible, but would like be more application-specific for how exactly the LCD was being used.

Type Definitions
To use the API, you need the following from the types defined in lcd_NHD-C12864LZ.h:

LcdFontType – enumerated type that selects the font to use when sending strings.

PixelAddressType – Pixel address struct
u16 u16PixelRowAddress;
u16 u16PixelColumnAddress;

PixelBlockType – Address struct to define a box of pixels
u16 u16RowStart; Address of top left pixel row
u16 u16ColumnStart; Address of top left pixel column
u16 u16RowSize; Number of rows in block
u16 u16ColumnSize; Number of columns in block
e.g. A twenty-five pixel high by thirty pixel wide box in the top-left corner would be

initialized like this:
PixelBlockType sBox = {0, 127, 25, 30};

The box is always defined right-of (decreasing column addresses) and down-from (increasing row addresses) the top left pixel

The lcd_NHD-C12864LZ.c file provides some globally defined PixelBlockType variables for clearing lines of text.

Public Functions
The driver API functions work with a copy of the LCD RAM in the processor’s RAM. This allows changes to be made quickly without worrying about updating the LCD. The driver automatically
refreshes the LCD every LCD_REFRESH_TIME ms (currently 40 times per second). The following functions may be used by any application in the system.

  • void LcdSetPixel(PixelAddressType* sPixelAddress_) – Turn on one pixel in the LCD RAM.
  • void LcdClearPixel(PixelAddressType* sPixelAddress_) – Turn off one pixel in the LCD RAM.
  • void LcdClearPixels(PixelBlockType* sPixelsToClear_) – Clears the selected block of pixels. A custom area can be provided to this function, but several commonly used predefined areas are included.
  • void LcdClearScreen(void) – Clears all of the current pixel data.
  • void LcdLoadString(const unsigned char* pu8String_, LcdFontType eFont_, PixelAddressType* sStartPixel_) – Updates the local LCD memory with an ASCII string in the font specified. Any pixels that will not fit on the LCD are ignored. sStartPixel_ is the location where the top left pixel of the first character bitmap square is specified.
  • void LcdLoadBitmap(u8* aau8Bitmap_, PixelBlockType* sBitmapSize_) – Places a bitmap into the LCD RAM. Bit maps are 2D arrays of pixels; the size of the bitmap must be in SBitmapsSize).
  • bool LcdCommand(u8 u8Command_) – Sends a control command to the LCD. The commands relevant to tasks using the LCD are: LCD_DISPLAY_ON, LCD_DISPLAY_OFF, LCD_PIXEL_TEST_ON, LCD_PIXEL_TEST_OFF.


Turn on a pixel at the center of the screen:
PixelAddressType sTargetPixel = {32, 64};

Turn off a pixel in the center of the screen:
PixelAddressType sTargetPixel = {32, 64};

Clear a 25 x 30 block of pixels in the top-left corner of the LCD:
PixelBlockType sPixelsToClear = {0, 127, 25, 30}
sPixelsToClear.u16RowStart = 0;
sPixelsToClear.u16ColumnStart = 0;
sPixelsToClear.u16RowSize = 25;
sPixelsToClear.u16ColumnSize = 30;

Clear a 25 x 30 block of pixels in the bottom-right corner of the LCD:
PixelBlockType sPixelsToClear;
sPixelsToClear.u16RowSize = 25;
sPixelsToClear.u16ColumnSize = 30;
sPixelsToClear.u16RowStart = LCD_BOTTOM_MOST_ROW – sPixelsToClear.u16RowSize;
sPixelsToClear.u16ColumnStart = LCD_RIGHT_MOST_COLUMN – sPixelsToClear.u16ColumnSize;

Load a string on the bottom text line left justified.
PixelAddressType sTestStringLocation = {LCD_SMALL_FONT_LINE3, LCD_LEFT_MOST_COLUMN);
u8 au8TestString[] = “Testing”;
LcdLoadSting(au8TestString, LCD_FONT_SMALL, &sTestStringLocation);

Load logo in the top left corner of the screen
PixelBlockType sEngenuicsImage;
sEngenuicsImage.u16RowStart = 0;
sEngenuicsImage.u16ColumnStart = 0;
sEngenuicsImage.u16RowSize = 50;
sEngenuicsImage.u16ColumnSize = 50;
LcdLoadBitmap(&aau8EngenuicsLogoBlack[0][0], sEngenuicsImage);


In this exercise you will write your name on the screen and move it down when BUTTON0 is

pressed and up when BUTTON1 is pressed.

  1. Pull the latest Master code from Github.
  2. Add UserApp_au8Name[] in the global variable section that is acessible to all functions

    in UserApp.

  3. Use LcdClearScreen() to clear the LCD in UserAppInitialize.
  4. Write your name in UserAppInitialize. The starting pixel address is LCD_TOP_MOST_ROW and


  5. Build and run the code to ensure that it does what you expect.

The algorithm to move your name around has the following features:

  • If BUTTON0 was pressed and there is an empty row below the current row, erase the

    current row and re-write the name string to the new row; if the name is already at the bottom,

    do nothing (or alternatively, wrap it back to the top row).

  • If BUTTON1 was pressed and there is an empty row above the current row, erase the

    current row and re-write the name string to the new row; if the name is already at the top do

    nothing (or alternatively, wrap it back to the bottom row).

Implement the code as follows:

  1. Add static u8 u8CurrentRow = 0 to UserAppSM_Idle.
  2. Check if BUTTON0 was pressed.
  3. If BUTTON0, check that u8CurrentRow is not currently = LCD_SMALL_FONT_ROWS.
  4. If there is room, use LcdClearPixels to clear the name from the current row.
  5. Increment u8CurrentRow and write your name to the new row.
  6. Build and test that the code will move your name all the way to the bottom of the


  7. Copy the code and make adjustemnts to move your name back up the screen with BUTTON1.