Interfacing a graphical LCD to a micro-controller is an interesting stuff beyond a character LCD or a LED matrix display. Most of graphical LCD has a built-in controller for example a well known KS0108 controller chip had been widely used for many years. A monochrome graphical LCD has various size and resolutions, 128x32, 128x64, 128x128, 128x160 and 240x128 etc.
TG12864A-04A 128x32 Dot-matrix and ATMega644P Interfacing
![]() |
| TG12864A-04A and ATMega644P Interfacing |
I bought an old graphical LCD TG12864A-04A that is a 128x32 dot-matrix display with its controller chips SBN0064G (64-row x 64-column). So this 128x32 dot-matrix LCD needs two SBN0064G chip that will selecting via CS pin.
![]() |
| TG12864A-04A LCM Module Spec |
It controlling method is very similar to the KS0108 controller chip. I will not explain it here.
I bought this LCD module nearly 20 years now since I was at high school writing code for the 8051 micro-controller.
This LCM module use a parallel port interface, 8-bit data bus and a few control lines as shown in the picture above. It allow data read and write via R/W pin. Command and data is set by the D/I (Data/Instruction) pin. However for most text displaying application we just need to write data to this display.
The example below the ATMega644P send some texts to this LCM display.
main.c
- /*
- * 8-TG12832A-04A _Text.c
- *
- * Created: 1/29/2026 5:51:25 PM
- * Author : Admin
- */
- #include <avr/io.h>
- #include <avr/pgmspace.h>
- #include "font5x8.h"
- #include <util/delay.h>
- #define F_CPU 16000000UL
- #define LCD_DATA PORTB
- #define LCD_CONT PORTD
- #define LCD_EN 0
- #define LCD_DI 1
- #define LCD_CS 2
- #define LCD_RET 3
- unsigned char dotCount=0;
- /*
- cs = 1 left screen area is selected
- cs = 0 right screen area is selected
- */
- void lcdCommand(unsigned char cmd,char cs){
- if(cs==1) LCD_CONT|=(1<<LCD_CS);
- else LCD_CONT&=~(1<<LCD_CS);
- LCD_CONT&=~(1<<LCD_DI);
- LCD_DATA=cmd;
- LCD_CONT|=(1<<LCD_EN);
- _delay_us(10);
- LCD_CONT&=~(1<<LCD_EN);
- //if(cs==1) LCD_CONT&=~(1<<LCD_CS);
- //else LCD_CONT&=~(1<<LCD_CS);
- }
- void lcdData(char data,char cs){
- if(cs==1) LCD_CONT|=(1<<LCD_CS);
- else LCD_CONT&=~(1<<LCD_CS);
- LCD_CONT|=(1<<LCD_DI);
- LCD_DATA=data;
- LCD_CONT|=(1<<LCD_EN);
- _delay_us(10);
- LCD_CONT&=~(1<<LCD_EN);
- //if(cs==1) LCD_CONT&=~(1<<LCD_CS1);
- //else if (cs==2) LCD_CONT&=~(1<<LCD_CS2);
- }
- void lcdHorizontal(unsigned char horizontal){
- lcdCommand(0x40+horizontal,1);
- lcdCommand(0x40+horizontal,0);
- }
- void lcdVerticalLine(unsigned char line){
- lcdCommand(0xB8+line,1);
- lcdCommand(0xB8+line,0);
- dotCount=0;
- }
- void lcdSetZ(unsigned char zAxis){
- lcdCommand(0xC0+zAxis,1);
- lcdCommand(0xC0+zAxis,0);
- }
- void lcdXy(unsigned char x,unsigned char y){
- if(x<64){
- lcdCommand(0x40+x,1);
- lcdCommand(0x40+0,0);
- }
- else{
- lcdCommand(0x40+0,1);
- lcdCommand(0x40+x-63,0);
- }
- lcdCommand(0xB8+y,1);
- lcdCommand(0xB8+y,0);
- dotCount=x;
- }
- void writeChar(unsigned char aph){
- for (int i=0;i<5;i++)
- {
- char font = pgm_read_byte(&font5x8[((aph-32)*5)+i]);
- if(dotCount<64) lcdData(font,1);
- else lcdData(font,0);
- dotCount++;
- }
- lcdData(0,(dotCount<64)?1:0);
- dotCount++;
- if (dotCount>127)
- {
- dotCount=0;
- }
- }
- void writeCharDelay(unsigned char aph,unsigned int dT){
- for (int i=0;i<5;i++)
- {
- char RomReader = pgm_read_byte(&font5x8[((aph-32)*5)+i]);
- if(dotCount<64) lcdData(RomReader,1);
- else lcdData(RomReader,0);
- if(dT!=0) for(int i=0;i<dT;i++) _delay_us(1000);
- dotCount++;
- }
- lcdData(0,(dotCount<64)?1:0);
- dotCount++;
- if (dotCount>127)
- {
- dotCount=0;
- }
- }
- void lcdString(char *str){
- while(*str)
- writeChar(*str++);
- if (dotCount>=127)
- {
- dotCount=0;
- }
- }
- void writeStringDelay(char *str,unsigned int dT){
- while(*str){
- if(dT!=0) writeCharDelay(*str++,dT);
- else writeChar(*str++);
- }
- }
- void lcdInit(void){
- DDRB=0xFF;
- DDRD=0xFF;
- /*Display On*/
- lcdCommand(0x3F,1);
- lcdCommand(0x3F,0);
- dotCount = 0;
- }
- void lcdClearScreen(){
- for (int i=0;i<4;i++)
- {
- lcdXy(0,i);
- for(int j=0;j<127;j++){
- lcdData(0,1);
- lcdData(0,0);
- }
- }
- dotCount=0;
- lcdXy(0,0);
- }
- void lcdClearSection(unsigned char x,unsigned char y,unsigned char dot){
- lcdXy(x,y);
- dotCount=x;
- for (int i=0;i<dot;i++)
- {
- if(dotCount<64) lcdData(0,1);
- else lcdData(0,0);
- dotCount++;
- }
- if (dotCount>128)
- {
- dotCount=0;
- }
- }
- int main(void)
- {
- //_delay_ms(500);
- lcdInit();
- lcdClearScreen();
- lcdString("ATMega644P AVR GLCD");
- lcdXy(0,1);
- lcdString("TG12864A-04A 128x32");
- lcdXy(0,2);
- lcdString("Programming With C in");
- lcdXy(0,3);
- lcdString("Microchip Studio IDE");
- while (1)
- {
- }
- }
font5x8.h
- //#ifdef __AVR__
- //#include <avr/pgmspace.h>
- //static const char PROGMEM font5x8[] = {
- //#else
- const char font5x8[] PROGMEM= {
- //#endif
- 0x00, 0x00, 0x00, 0x00, 0x00,// (spacja)
- 0x00, 0x00, 0x5F, 0x00, 0x00,// !
- 0x00, 0x07, 0x00, 0x07, 0x00,// "
- 0x14, 0x7F, 0x14, 0x7F, 0x14,// #
- 0x24, 0x2A, 0x7F, 0x2A, 0x12,// $
- 0x23, 0x13, 0x08, 0x64, 0x62,// %
- 0x36, 0x49, 0x55, 0x22, 0x50,// &
- 0x00, 0x05, 0x03, 0x00, 0x00,// '
- 0x00, 0x1C, 0x22, 0x41, 0x00,// (
- 0x00, 0x41, 0x22, 0x1C, 0x00,// )
- 0x08, 0x2A, 0x1C, 0x2A, 0x08,// *
- 0x08, 0x08, 0x3E, 0x08, 0x08,// +
- 0x00, 0x50, 0x30, 0x00, 0x00,// ,
- 0x08, 0x08, 0x08, 0x08, 0x08,// -
- 0x00, 0x30, 0x30, 0x00, 0x00,// .
- 0x20, 0x10, 0x08, 0x04, 0x02,// /
- 0x3E, 0x51, 0x49, 0x45, 0x3E,// 0
- 0x00, 0x42, 0x7F, 0x40, 0x00,// 1
- 0x42, 0x61, 0x51, 0x49, 0x46,// 2
- 0x21, 0x41, 0x45, 0x4B, 0x31,// 3
- 0x18, 0x14, 0x12, 0x7F, 0x10,// 4
- 0x27, 0x45, 0x45, 0x45, 0x39,// 5
- 0x3C, 0x4A, 0x49, 0x49, 0x30,// 6
- 0x01, 0x71, 0x09, 0x05, 0x03,// 7
- 0x36, 0x49, 0x49, 0x49, 0x36,// 8
- 0x06, 0x49, 0x49, 0x29, 0x1E,// 9
- 0x00, 0x36, 0x36, 0x00, 0x00,// :
- 0x00, 0x56, 0x36, 0x00, 0x00,// ;
- 0x00, 0x08, 0x14, 0x22, 0x41,// <
- 0x14, 0x14, 0x14, 0x14, 0x14,// =
- 0x41, 0x22, 0x14, 0x08, 0x00,// >
- 0x02, 0x01, 0x51, 0x09, 0x06,// ?
- 0x32, 0x49, 0x79, 0x41, 0x3E,// @
- 0x7E, 0x11, 0x11, 0x11, 0x7E,// A
- 0x7F, 0x49, 0x49, 0x49, 0x36,// B
- 0x3E, 0x41, 0x41, 0x41, 0x22,// C
- 0x7F, 0x41, 0x41, 0x22, 0x1C,// D
- 0x7F, 0x49, 0x49, 0x49, 0x41,// E
- 0x7F, 0x09, 0x09, 0x01, 0x01,// F
- 0x3E, 0x41, 0x41, 0x51, 0x32,// G
- 0x7F, 0x08, 0x08, 0x08, 0x7F,// H
- 0x00, 0x41, 0x7F, 0x41, 0x00,// I
- 0x20, 0x40, 0x41, 0x3F, 0x01,// J
- 0x7F, 0x08, 0x14, 0x22, 0x41,// K
- 0x7F, 0x40, 0x40, 0x40, 0x40,// L
- 0x7F, 0x02, 0x04, 0x02, 0x7F,// M
- 0x7F, 0x04, 0x08, 0x10, 0x7F,// N
- 0x3E, 0x41, 0x41, 0x41, 0x3E,// O
- 0x7F, 0x09, 0x09, 0x09, 0x06,// P
- 0x3E, 0x41, 0x51, 0x21, 0x5E,// Q
- 0x7F, 0x09, 0x19, 0x29, 0x46,// R
- 0x46, 0x49, 0x49, 0x49, 0x31,// S
- 0x01, 0x01, 0x7F, 0x01, 0x01,// T
- 0x3F, 0x40, 0x40, 0x40, 0x3F,// U
- 0x1F, 0x20, 0x40, 0x20, 0x1F,// V
- 0x7F, 0x20, 0x18, 0x20, 0x7F,// W
- 0x63, 0x14, 0x08, 0x14, 0x63,// X
- 0x03, 0x04, 0x78, 0x04, 0x03,// Y
- 0x61, 0x51, 0x49, 0x45, 0x43,// Z
- 0x00, 0x00, 0x7F, 0x41, 0x41,// [
- 0x02, 0x04, 0x08, 0x10, 0x20,// "\"
- 0x41, 0x41, 0x7F, 0x00, 0x00,// ]
- 0x04, 0x02, 0x01, 0x02, 0x04,// ^
- 0x40, 0x40, 0x40, 0x40, 0x40,// _
- 0x00, 0x01, 0x02, 0x04, 0x00,// `
- 0x20, 0x54, 0x54, 0x54, 0x78,// a
- 0x7F, 0x48, 0x44, 0x44, 0x38,// b
- 0x38, 0x44, 0x44, 0x44, 0x20,// c
- 0x38, 0x44, 0x44, 0x48, 0x7F,// d
- 0x38, 0x54, 0x54, 0x54, 0x18,// e
- 0x08, 0x7E, 0x09, 0x01, 0x02,// f
- 0x08, 0x14, 0x54, 0x54, 0x3C,// g
- 0x7F, 0x08, 0x04, 0x04, 0x78,// h
- 0x00, 0x44, 0x7D, 0x40, 0x00,// i
- 0x20, 0x40, 0x44, 0x3D, 0x00,// j
- 0x00, 0x7F, 0x10, 0x28, 0x44,// k
- 0x00, 0x41, 0x7F, 0x40, 0x00,// l
- 0x7C, 0x04, 0x18, 0x04, 0x78,// m
- 0x7C, 0x08, 0x04, 0x04, 0x78,// n
- 0x38, 0x44, 0x44, 0x44, 0x38,// o
- 0x7C, 0x14, 0x14, 0x14, 0x08,// p
- 0x08, 0x14, 0x14, 0x18, 0x7C,// q
- 0x7C, 0x08, 0x04, 0x04, 0x08,// r
- 0x48, 0x54, 0x54, 0x54, 0x20,// s
- 0x04, 0x3F, 0x44, 0x40, 0x20,// t
- 0x3C, 0x40, 0x40, 0x20, 0x7C,// u
- 0x1C, 0x20, 0x40, 0x20, 0x1C,// v
- 0x3C, 0x40, 0x30, 0x40, 0x3C,// w
- 0x44, 0x28, 0x10, 0x28, 0x44,// x
- 0x0C, 0x50, 0x50, 0x50, 0x3C,// y
- 0x44, 0x64, 0x54, 0x4C, 0x44,// z
- 0x00, 0x08, 0x36, 0x41, 0x00,// {
- 0x00, 0x00, 0x7F, 0x00, 0x00,// |
- 0x00, 0x41, 0x36, 0x08, 0x00,// }
- 0x08, 0x08, 0x2A, 0x1C, 0x08,// ->
- 0x08, 0x1C, 0x2A, 0x08, 0x08 // <-
- };
- //
Schematic:

Schematic

AVR Prototype Board Test:
![]() |
| AVR Prototype Board Test |
This PCB was offered from PCBWay.
I have been using PCBWay for many years now. PCBWay fabricate PCBs at low cost, fast processing time for only 24 hours, and fast delivery time using any carrier options. This double side 10cmx10cm can be fabricate at only 5USD for 5 to 10pcs by PCBWay. It's a standard PCB with silk screen and solder mask.
![]() |
| 10 PCBs for only 5USD |
For different size of PCB we can instantly quote on PCBWay website using a zip PCB Gerber file without account.
![]() |
| PCBWay Instant Quote |
RT12864J-1 KS0108 128x64 Dot-matrix and ATMega644P Interfacing
The KS0108 is a popular dot matrix display driver many years now. Currently there are a lot of low power, low cost display driver controllers that are equivalent to this chip. They have many interfaces beyond the parallel port such as SPI and I2C that implements only a few wires.
| RT12864J-1 KS0108 128x64 Dot-matrix - TOP |
| RT12864J-1 KS0108 128x64 Dot-matrix - BOTTOM |
I have an RT12864J-1 128x64 Graphical Display I bought I from Ebay many years now. But it has some defect due to aging.
| A Tested Program Using ATMega32 |
| A Tested Program Using ATMega32 |
However this large display use an 8-bit parallel port with some control pins that is very boring for newer electronic hobbyists. There are some wiring issue when installing this display on breadboard that needed to make sure all wires connection.
To display a graphic we need to create a 128x64 monochrome bitmap image using a PC software for example Adobe Photoshop. Then save it a a monochrome bitmap file.
| LCD Assistance |
The LCDAssistant.exe tool convert any monochrome bitmap image to a C graphical data that works with any C compilers.
Source Code:
- /*
- * 8-RT12864J-1.c
- *
- * Created: 1/30/2026 9:13:54 AM
- * Author : Admin
- */
- #include <avr/io.h>
- #include "font5x8.h"
- #include "diy-logo.h"
- #include <util/delay.h>
- #define F_CPU 16000000UL
- #define LCD_DATA PORTB
- #define LCD_CONT PORTD
- #define LCD_EN 0
- #define LCD_RS 1
- #define LCD_CS1 3
- #define LCD_CS2 2
- #define LCD_RST 4
- unsigned char dotCount=0;
- void lcdCommand(unsigned char cmd,char cs){
- if(cs==1) LCD_CONT|=(1<<LCD_CS1);
- else if(cs==2) LCD_CONT|=(1<<LCD_CS2);
- LCD_CONT&=~(1<<LCD_RS);
- LCD_CONT|=(1<<LCD_EN);
- LCD_DATA=cmd;
- LCD_CONT&=~(1<<LCD_EN);
- _delay_us(10);
- if(cs==1) LCD_CONT&=~(1<<LCD_CS1);
- else if(cs==2) LCD_CONT&=~(1<<LCD_CS2);
- }
- void lcdData(char data,char cs){
- if(cs==1) LCD_CONT|=(1<<LCD_CS1);
- else if(cs==2) LCD_CONT|=(1<<LCD_CS2);
- LCD_CONT|=(1<<LCD_RS);
- LCD_CONT|=(1<<LCD_EN);
- LCD_DATA=data;
- LCD_CONT&=~(1<<LCD_EN);
- _delay_us(10);
- if(cs==1) LCD_CONT&=~(1<<LCD_CS1);
- else if (cs==2) LCD_CONT&=~(1<<LCD_CS2);
- }
- void lcdHorizontal(unsigned char horizontal){
- lcdCommand(0x40+horizontal,1);
- lcdCommand(0x40+horizontal,2);
-
- }
- void lcdVerticalLine(unsigned char line){
- lcdCommand(0xB8+line,1);
- lcdCommand(0xB8+line,2);
- dotCount=0;
- }
- void lcdSetZ(unsigned char zAxis){
- lcdCommand(0xC0+zAxis,1);
- lcdCommand(0xC0+zAxis,2);
- }
- void lcdXy(unsigned char x,unsigned char y){
- if(x<64){
- lcdCommand(0x40+x,1);
- lcdCommand(0x40+0,2);
- }
- else{
- lcdCommand(0x40+0,1);
- lcdCommand(0x40+x-63,2);
- }
-
- lcdCommand(0xB8+y,1);
- lcdCommand(0xB8+y,2);
- dotCount=x;
- }
- void writeChar(unsigned char aph){
- for (int i=0;i<5;i++)
- {
- if(dotCount<64) lcdData(font5x8[((aph-32)*5)+i],1);
- else lcdData(font5x8[((aph-32)*5)+i],2);
- dotCount++;
- }
- lcdData(0,(dotCount<64)?1:2);
- dotCount++;
- if (dotCount>127)
- {
- dotCount=0;
- }
- }
- void writeCharDelay(unsigned char aph,unsigned int dT){
- for (int i=0;i<5;i++)
- {
- if(dotCount<64) lcdData(font5x8[((aph-32)*5)+i],1);
- else lcdData(font5x8[((aph-32)*5)+i],2);
- if(dT!=0) for(int i=0;i<dT;i++) _delay_us(1000);
- dotCount++;
- }
- lcdData(0,(dotCount<64)?1:2);
- dotCount++;
- if (dotCount>127)
- {
- dotCount=0;
- }
- }
- void lcdString(char *str){
- while(*str)
- writeChar(*str++);
- }
- void writeStringDelay(char *str,unsigned int dT){
- while(*str){
- if(dT!=0) writeCharDelay(*str++,dT);
- else writeChar(*str++);
- }
- }
- void lcdInit(void){
- DDRB=0xFF;
- DDRD=0xFF;
- /*Display On*/
- lcdCommand(0x3F,1);
- lcdCommand(0x3F,2);
- dotCount = 0;
- }
- void lcdClearScreen(){
-
- for (int i=0;i<8;i++)
- {
- lcdXy(0,i);
- for(int j=0;j<128;j++){
- lcdData(0,1);
- lcdData(0,2);
- }
- }
- dotCount=0;
- lcdXy(0,0);
- }
- void lcdClearSection(unsigned char x,unsigned char y,unsigned char dot){
- lcdXy(x,y);
- dotCount=x;
- for (int i=0;i<dot;i++)
- {
- if(dotCount<64) lcdData(0,1);
- else lcdData(0,2);
- dotCount++;
- }
- if (dotCount>127)
- {
- dotCount=0;
- }
- }
- void showGraphic(void){
- unsigned int kCount=0;
- for (int i=0;i<8;i++)
- {
-
- dotCount=0;
- lcdXy(0,i);
- for (int j=kCount;j<kCount+128;j++)
- {
- if(dotCount<64) lcdData(logo[j],1);
- else lcdData(logo[j],2);
- dotCount++;
- }
- kCount+=128;
- }
- }
- int main(void)
- {
- _delay_ms(100);
- lcdInit();
- lcdClearScreen();
- while (1)
- {
- lcdXy(25,0);
- lcdString("HELLO WORLD!");
- lcdXy(0,1);
- lcdString("ATMEGA644P Graphic");
- lcdXy(0,2);
- lcdString("Programming in C With");
- lcdXy(0,3);
- lcdString("Microchip Studio");
- lcdXy(0,4);
- lcdString("DIY-Instruments");
- lcdXy(0,5);
- lcdString("KS0108 LCD Controller");
- lcdXy(0,6);
- lcdString("RT12864J-1 128x64");
- lcdXy(0,7);
- lcdString("Graphical LCD Module");
- _delay_ms(5000);
- lcdClearScreen();
-
- lcdXy(0,0);
- showGraphic();
- _delay_ms(5000);
- lcdClearScreen();
- }
- }
Schematic and Simulation:
| Simulation Using Proteus |
| Simulation Using Proteus |
In software it worked fine. But in hardware experiment it has problem due to device defect. I need to fix it later.
For more detail about using this display please see this post. CCS PICC also has a C driver of this LCD. It's very easy to use. This example the PIC16F877A interfaces with a 128x64 KS0108 graphical display.
Click here to download this example.

.png)





No comments:
Post a Comment