CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to

Rich featured graphic LCD driver PG12864

Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message

Joined: 29 Sep 2006
Posts: 111

View user's profile Send private message

Rich featured graphic LCD driver PG12864
PostPosted: Sun Oct 07, 2012 10:31 am     Reply with quote

This post contains code for the Powertip PG12864 graphic LCD screen. It uses the Serial interface.

This code is pretty compact with a lot of graphic features:
- Fixed and variable font use
- Single, double and quadrupple height
- Single and double width
- Toplined, bottomlined
- Boxed
- Inverted
- Any sensible combination of the above

It makes use of just 1 font array. This is a 7*5 font.
The buildup of this font is "byte-vertically". This buildup makes al the graphic features possible.
Indeed, the LCD buildup is byte-horizontally. Thus the code rotates each 8*8 pixels before writing.

An advantage of this mechanism is that although the screen is adressed byte columns (thus addres 0-16) now it is also possible to start text a each of the 0-127 pixels!
A limitation is printing text too close to the previous text on the same line. The new text must fall in a new column, otherwise some pixels of the previous text will be cleared.

I think this code is easy adaptable for other LCD drivers.

Have Fun!

Example program:

/*    program       : Pg12864
/*    module        :
/*    file          : PgSerTest.c
#include <18F6722.H>                               
#use Delay(Clock=32Mhz)                           

//--- IO assignment for LCD PG12864 --------------------------------------------
#use     fast_io(D)
#byte    PortD=0xF83
#bit     RS  = portD.1 
#bit     CS  = portD.2
#bit     CLK = portD.0
#bit     SD  = portD.3
#bit     RST = portD.4

//--- Add modules headers ------------------------------------------------------
#include "Pg_Ser.h"
#include "font_eb.h"

//--- Add module code ----------------------------------------------------------
#include "Pg_Ser.c"


void main() {
  char item0[30]="Hello!";
  char item1[30]="A rather long line this is.";
  char item2[32]="Boxed";
  char item3[30]="Hi!";
  char item4[30]="Hi-di-ho!";
  setup_oscillator(OSC_32MHZ );
  Set_tris_d(0x00);                                                             // data: graphic lcd control lines all output
  glcd_printf(0,0,item0, gVar+gH4+gW2);                                         
  while (1) {};

module PG_ser.h

//--- Global Function definitions ----------------------------------------------
void glcd_WriteData(int8 data);
void glcd_WriteCmd(int8 data);
void glcd_Init();
void glcd_printf(int8 row, int8 col, char *cstring, int8 mode);
void glcd_SetRowCol(int8 row, int8 col);
void glcd_DispClr();

#define nop(x) delay_cycles(x);

#define gFix       0       //fixed font 
#define gVar       0x01    //variable font
#define gH2        0x02    //2x font height
#define gH4        0x04    //4x font heigt
#define gW2        0x08    //2x font weight
#define gInvert    0x10    //invert font
#define gTL        0x20    //Topline (merges with top pix of font)
#define gBL        0x40    //BottomLine H1: touches font H2&H4: free underline
#define gBox       0x80    //Box

Typedef struct {    // This structure typedef can be used for easy acces
  int1 var;         //var=1, fix=0; (bit0)
  int1 h2;          //2x font height
  int1 h4;          //4x font heigt
  int1 w2;          //2x font weight
  int1 inv;         //invert font
  int1 tl;          //TopLine
  int1 bl;          //BottomLine
  int1 box;         //boxing
} gbf;              //"graphic bitfield"

//specific bittest macro for function glcd_printf()
#define dBT(x)       (((gbf)mode).x)             

typedef struct{                 
  int1 b0,b1,b2,b3,b4,b5,b6,b7;
} BitField8;

typedef union {
  BitField8 bit;
  int8 All;
} BitUnion8;

module Pg_ser.c

void glcd_WriteData(int8 data) {
   int8 i;
   CS=0;                                                                        // chip enable
   RS=0;                                                                        // select RAM data write
   for (i=0; i<8; i++) {
     CLK = 0;
     SD = 0; if (bit_test(data,7)) SD=1;                                        //fastest compiled bit copy
     data<<=1;                                                                  //shift left D0->1.. D6->7
     CLK = 1;
   CS=1;                                                                        // chip disable

void glcd_WriteCmd(int8 data) {
   int8 i;
   CS=0;                                                                        // chip enable
   RS=1;                                                                        // select REGISTER write
   for (i=0; i<8; i++) {
     CLK = 0;
     SD=0; if (bit_test(data,7)) SD=1;                                          //Out D7   
     data<<=1;                                                                  //shift left D0->1.. D6->7
     CLK = 1;
   CS=1;                                                                        // chip disable

void glcd_Init() {
  CS=1; RST=0; CLK=0; SD=0; RS=0;     // init IO levels, screen in hardware reset
  RST=1;                              // release reset
  delay_ms(10);                       // startup display??

  glcd_WriteCmd(0xB1);                // Power Control reg1: ALC initialization on
  glcd_WriteCmd(0xB2);                // Power Control reg1: Pon, ALC off
  glcd_WriteCmd(0x89);                // Display control register, Shift=1, display ON
  glcd_WriteCmd(0xDC);                // Power Control reg2: drive voltage some about "have to set this"
  glcd_WriteCmd(0xA2);                // auto increment Y ONLY
  glcd_WriteCmd(0x92);                // Swap=1="normal" mode
  glcd_WriteCmd(0x40);                // set the Startline(=0) Low nibble
  glcd_WriteCmd(0x50);                // set the Startline(=0) Hi nibble

void glcd_DispClr() {
  int16 i;
  glcd_WriteCmd(0xA3);                // auto increment XY cooperative
  glcd_WriteCmd(0x00);                // row=0 
  glcd_WriteCmd(0x20);                // column=0
  for(i=0; i<1024; i++) {             // 16 bytes per line 64 lines
    glcd_WriteData(0);                // write empty byte
  glcd_WriteCmd(0xA2);                // auto increment Y only

void glcd_SetRowCol(int8 row, int8 col) {   // Col=0..15, Row=0..63
  int8 rw;
  glcd_WriteCmd(col&0x0F);               // set the X adr=0 (0-15)
  rw=(row&0x0F)+ 0x20;                   // concat command to Ynibble low
  glcd_WriteCmd(rw);                     // set the Yadr low nibble  (0-63)
  rw=(swap(row)&0x0F)+0x30;              // concat command to Ynibble high
  glcd_WriteCmd(rw);                     // set the Yadr hi nibble   (0-63)

void glcd_printf(int8 row, int8 col, char *cstring, int8 mode) {
  int8 cl,c,i,j;                        // col counter     
  int8 si;                              // string index
  int8 bi;                              // font byte index 
  int8 fi;                              // font array index
  int8 ri;                              // ri rotatie index
  BitUnion8 rf[8];                      // rotated font buffer
  int8 BoxSm;                           // box State machine 0=no box
  int8 W2Sm;                            // width2 state machine
  int8 Lmax;                            // number of lines in casde of magnify       
  Lmax=1;                                 //H1 line
  if ( dBT(h2) ) Lmax=2;                  //H2 line
  if ( dBT(h4) ) Lmax=4;                  //H4 line
  for(i=0; i<Lmax; i++) {                 // line loop
    rf[0]=rf[1]=rf[2]=rf[3]=0;            // new line: clear rotated font buffer
    cl=col>>3;                            // load current col with start colum
    for (j=col&0x7; j<7; j++) ri<<=1;     // calc ri from col.b2-b0 (000:ri=128, 111:ri=1)
    si=0;                                 // clear string index
    bi=0;                                 // clear font byte line index       
    fi=0;                                 // clear from 255;
    w2Sm=0;                               // clear width state machine
    boxSm=0; if dBT(box) BoxSm=1;         // arm box statemachine   
    if dBT(inv) BoxSm=1;                  // invert mode add 1 vertical black line (more readable)
    do {
      if dBT(w2) W2Sm=2;                  // arm width2 statemachine
      if (!bi) {
        if (BoxSm==1) {
          BoxSm=2;                        // advance state machine "print chars"
          if dBT(inv) BoxSm=3;            // invert mode add 1 vertical black line then stop BoxSM.
          si--;                           // need to correct the bi==5 increment.
          bi=5;                           // force next line to be a space line
          c=0xFF;                         // load the vertical line
          goto pf_next_bx;                // skip font[]{bi] reading stuff
        } else { 
          fi = cstring[si];               // get string character
          if (fi==0) {                    // string end read. But:
            if (BoxSm==2) {
              BoxSm=3;                    // advance state machine
              c=0xFF;                     // load the vertical line
              goto pf_next_bx;            // skip font[]{bi] reading stuff
            } else { 
              fi=255;                     // load sting end value need to exit while
              if (ri) goto pf_next1;      // ri<>0 thus still need to print 'left over' set
              goto pf_next2;              // ri==0 thus we are done for this line
          fi-=32;                         // substract font array offset
      if (bi<5) {                         // still reading font
        c = font5x7[fi][bi];              // read font data
        if (c==0x99) {                    // T: font end marker detected
          c=0;                            // replace with empty
          if dBT(var) {                   // var font requested..
            bi=0; si++;                   // so 0x99 ends character
      } else {                           
        c=0;                              // bi=5 always a space line       
        bi=0; si++;                       // clear byte line index and increase character index.


      if dBT(h2) {                        // T: double magnefy character
        if (i) swap(c);                   // line2; need upper nible as magnefy index
        c&=0x0F;                          // get rid of unwanted nibble
        c = mgnfy2[c];                    // get the magnefied font byte

      if dBT(h4) {                        // T: quadruplle magnefy character
        if (i&0x2) swap(c);               // line2 or 3; need upper nible as magnefy index
        if (i&0x1) c>>=2;                 // need b3&2 on spot b1&0
        c&=0x03;                          // get rid of unwanted bits       
        c = mgnfy4[c];                    // get the magnefied font byte
      //===== linestuf
      if (i==0) {
        if dBT(box) c|=0x01;                                                    // add boxing topline
        if dBT(tl) c|=0x01;                                                     // add just topline
        if (!dBT(h2) && !dBT(h4) ) {                                            // T: Height -SINGLE-
          if dBT(box) c|=0x80;                                                  // add boxing botline 
          if dBT(bl) c|=0x80;                                                   // add touching botline
      if ((i==1) && dBT(h2)) {                                                  // last line Height -DOUBLE-
        if dBT(box) c|=0x80;                                                    // add boxing botline (free botline)
        if dbt(bl) c|=0x80;                                                     // add free botline
      if ((i==3) && dBT(h4)) {                                                  // last line Height -QUADRO-
        if (c==0xFF) c=0x3F;                                                    // correct left right vertical boxing line for i==3
        if dBT(box) c|=0x20;                                                    // add boxing botline 
        if dBT(bl) c|=0x20;                                                     // add free botline
        if dBT(inv) c|=0xC0;                                                    // correct inversion to come
      if dBT(inv) c=~c;                                                         // T: invert font.
      do {
      if (c&1)   rf[0].all += ri;          //if c.b0==1 then rf[0]+=ri          //font rotation
      if (c&2)   rf[1].all += ri;          //if c.b1==1 then rf[1]+=ri
      if (c&4)   rf[2].all += ri;          //if c.b2==1 then rf[2]+=ri
      if (c&8)   rf[3].all += ri;          //if c.b3==1 then rf[3]+=ri
      if (c&16)  rf[4].all += ri;          //if c.b4==1 then rf[4]+=ri
      if (c&32)  rf[5].all += ri;          //if c.b5==1 then rf[5]+=ri
      if (c&64)  rf[6].all += ri;          //if c.b6==1 then rf[6]+=ri
      if (c&128) rf[7].all += ri;          //if c.b7==1 then rf[7]+=ri
      ri>>=1;                                                                   //shift the single bit mask
      if (!ri) {                                                                //rotated byte ready
        glcd_SetRowCol(row,cl++);                                               //set printing adress and increase cl.
        glcd_WriteData(rf[0].all);                                              //8 separate calls compiles
        glcd_WriteData(rf[1].all);                                              //shorter than putting
        glcd_WriteData(rf[2].all);                                              //it in an for-loop
        rf[0]=rf[1]=rf[2]=rf[3]=0;                                              // clear rotated font buffer
      if (w2Sm) w2Sm--;                                                         //countdown w2 state machine
      } while (w2Sm>0);
    } while( (cl<16) && (fi!=255));                                             // until colum 16 is written or end sign set
    row+=8;                                                                     // next line

module font_eb.h

// Font below is called 5*7. Buildup each byte -vertically printed left to right
// It is adapted to be used fixed (5+1 space) size and as variable font
// special codes:
// - 0x99 = variable font end code
// when printed as fixed font, code is replaced by '0x00'

int8 const Mgnfy2[16] = {0x00,0x03,0x0C,0x0F,0x30,0x33,0x3C,0x3F,
int8 const Mgnfy4[4] =  {0x00,0x0F,0xF0,0xFF};                         

int8 const Font5x7[97][5] =
                        {0x00, 0x00, 0x99, 0x99, 0x99,  // SPACE
                         0x00, 0x5F, 0x99, 0x99, 0x99,  // !
                         0x00, 0x03, 0x00, 0x03, 0x99,  // "
                         0x14, 0x3E, 0x14, 0x3E, 0x14,  // #
                         0x24, 0x2A, 0x7F, 0x2A, 0x12,  // $
                         0x43, 0x33, 0x08, 0x66, 0x61,  // %
                         0x36, 0x49, 0x55, 0x22, 0x50,  // &
                         0x00, 0x05, 0x03, 0x99, 0x99,  // '
                         0x00, 0x1C, 0x22, 0x41, 0x99,  // (
                         0x00, 0x41, 0x22, 0x1C, 0x99,  // )
                         0x14, 0x08, 0x3E, 0x08, 0x14,  // *
                         0x08, 0x08, 0x3E, 0x08, 0x08,  // +
                         0x00, 0x50, 0x30, 0x99, 0x99,  // ,
                         0x08, 0x08, 0x08, 0x08, 0x08,  // -
                         0x00, 0x60, 0x60, 0x99, 0x99,  // .
                         0x20, 0x10, 0x08, 0x04, 0x02,  // /
                         0x3E, 0x51, 0x49, 0x45, 0x3E,  // 0
                         0x00, 0x04, 0x02, 0x7F, 0x99,  // 1
                         0x42, 0x61, 0x51, 0x49, 0x46,  // 2
                         0x22, 0x41, 0x49, 0x49, 0x36,  // 3
                         0x18, 0x14, 0x12, 0x7F, 0x10,  // 4
                         0x27, 0x45, 0x45, 0x45, 0x39,  // 5
                         0x3E, 0x49, 0x49, 0x49, 0x32,  // 6
                         0x01, 0x01, 0x71, 0x09, 0x07,  // 7
                         0x36, 0x49, 0x49, 0x49, 0x36,  // 8
                         0x26, 0x49, 0x49, 0x49, 0x3E,  // 9
                         0x00, 0x36, 0x36, 0x99, 0x99,  // :
                         0x00, 0x56, 0x36, 0x99, 0x99,  // ;
                         0x08, 0x14, 0x22, 0x41, 0x99,  // <
                         0x14, 0x14, 0x14, 0x14, 0x14,  // =
                         0x00, 0x41, 0x22, 0x14, 0x08,  // >
                         0x02, 0x01, 0x51, 0x09, 0x06,  // ?
                         0x3E, 0x41, 0x59, 0x55, 0x5E,  // @
                         0x7E, 0x09, 0x09, 0x09, 0x7E,  // A
                         0x7F, 0x49, 0x49, 0x49, 0x36,  // B
                         0x3E, 0x41, 0x41, 0x41, 0x22,  // C
                         0x7F, 0x41, 0x41, 0x41, 0x3E,  // D
                         0x7F, 0x49, 0x49, 0x49, 0x41,  // E
                         0x7F, 0x09, 0x09, 0x09, 0x01,  // F
                         0x3E, 0x41, 0x41, 0x49, 0x3A,  // G
                         0x7F, 0x08, 0x08, 0x08, 0x7F,  // H
                         0x00, 0x41, 0x7F, 0x41, 0x99,  // I
                         0x30, 0x40, 0x40, 0x40, 0x3F,  // J
                         0x7F, 0x08, 0x14, 0x22, 0x41,  // K
                         0x7F, 0x40, 0x40, 0x40, 0x40,  // L
                         0x7F, 0x02, 0x0C, 0x02, 0x7F,  // M
                         0x7F, 0x02, 0x04, 0x08, 0x7F,  // N
                         0x3E, 0x41, 0x41, 0x41, 0x3E,  // O
                         0x7F, 0x09, 0x09, 0x09, 0x06,  // P
                         0x1E, 0x21, 0x21, 0x21, 0x5E,  // Q
                         0x7F, 0x09, 0x09, 0x09, 0x76,  // R
                         0x26, 0x49, 0x49, 0x49, 0x32,  // S
                         0x01, 0x01, 0x7F, 0x01, 0x01,  // T
                         0x3F, 0x40, 0x40, 0x40, 0x3F,  // U
                         0x1F, 0x20, 0x40, 0x20, 0x1F,  // V
                         0x7F, 0x20, 0x10, 0x20, 0x7F,  // W
                         0x41, 0x22, 0x1C, 0x22, 0x41,  // X
                         0x07, 0x08, 0x70, 0x08, 0x07,  // Y
                         0x61, 0x51, 0x49, 0x45, 0x43,  // Z
                         0x00, 0x7F, 0x41, 0x99, 0x99,  // [
                         0x02, 0x04, 0x08, 0x10, 0x20,  // \
                         0x00, 0x41, 0x7F, 0x99, 0x99,  // ]
                         0x04, 0x02, 0x01, 0x02, 0x04,  // ^
                         0x40, 0x40, 0x40, 0x40, 0x40,  // _
                         0x00, 0x01, 0x02, 0x04, 0x99,  // `
                         0x20, 0x54, 0x54, 0x54, 0x78,  // a
                         0x7F, 0x44, 0x44, 0x44, 0x38,  // b
                         0x38, 0x44, 0x44, 0x44, 0x44,  // c
                         0x38, 0x44, 0x44, 0x44, 0x7F,  // d
                         0x38, 0x54, 0x54, 0x54, 0x18,  // e
                         0x04, 0x04, 0x7E, 0x05, 0x05,  // f
                         0x08, 0x54, 0x54, 0x54, 0x3C,  // g
                         0x7F, 0x08, 0x04, 0x04, 0x78,  // h
                         0x00, 0x44, 0x7D, 0x40, 0x99,  // i
                         0x20, 0x40, 0x44, 0x3D, 0x99,  // j
                         0x7F, 0x10, 0x28, 0x44, 0x99,  // k
                         0x00, 0x41, 0x7F, 0x40, 0x99,  // l
                         0x7C, 0x04, 0x78, 0x04, 0x78,  // m
                         0x7C, 0x08, 0x04, 0x04, 0x78,  // n
                         0x38, 0x44, 0x44, 0x44, 0x38,  // o
                         0x7C, 0x14, 0x14, 0x14, 0x08,  // p
                         0x08, 0x14, 0x14, 0x14, 0x7C,  // q
                         0x00, 0x7C, 0x08, 0x04, 0x04,  // r
                         0x48, 0x54, 0x54, 0x54, 0x20,  // s
                         0x04, 0x04, 0x3F, 0x44, 0x44,  // 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, 0x41,  // {
                         0x00, 0x7F, 0x00, 0x99, 0x99,  // |
                         0x41, 0x41, 0x36, 0x08, 0x99,  // }
                         0x02, 0x01, 0x02, 0x04, 0x02  // ~                         

Regards, Edwin. PCWHD v5.097
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2001, 2005 phpBB Group