Switching LCD modes

bwhiten

New member
I am using a CFAG16080A-TMI-TZ display in Graphics mode. This uses the LC7981 controller. I would like to conserve some space in my PIC uC by using the built-in character generator of the display instead of having to keep an ascii character map in the PIC. Is there a method to use the internal character memory while in graphics mode or will the graphics continue to display if I switch to character mode temporarily to write characters?
Thanks.
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 

CF Tech

Administrator
Sorry about the delay. I must have missed the post. Thanks for bringing the thread back up.

The LC7981 can either be in graphics mode or text mode, not both at the same time.

I think the T6963 displays can have graphics and text on at the same time, I know that the S1D13700 can do text and graphics at the same time.

The controllers are listed here, just for a "Ctrl + F" to find the controller you want.

http://www.crystalfontz.com/products/index-grph.html

Alternatively, you could use an external EEPROM or flash to store the fonts, and keep using the LC7981 in graphics mode.
 

bwhiten

New member
Thanks for the reply. I missed yours as well. I must not have the email alert system turned on.
This is what I thought. I will probably just draw a graphic opening page then switch over to text for the user interface as it's 99% full of text anyway. I'm hoping the draw speed will be faster with text as well. I love the quality and price point for this size display so I would like to keep it in the product design.
 

bwhiten

New member
Special characters

On the same theme :D Can any special characters be added to the character map in this display? Since I will use the character mode for the bulk of the screens I would like to use a couple of custom characters for indicators if possible.
 

CF Tech

Administrator
It does not look like you can define a custom character. I think the controller can have a RAM added that would contain character patterns, but this module does not look like it supports it.

I think in the end you will be better off if you use it in graphics mode, and draw the text under software control. I sent you some sample code for reference.
 

bwhiten

New member
Too slow it seems

Drawing text in graphics mode is way too slow from what I have been able to see. The write byte command has to be done 20 x 80 times to display an entirely new screen of text whereas in character mode the write command only needs to be done 20 x 8 times to show entirely new text over the entire screen, unless I'm missing something. Plus, no automatic cursor or blinking in graphics mode unless you write code for that as well.
 

CF Tech

Administrator
The way I did it, you reserve a memory image in the processor that mirrors the LCD.

All your operations are done on that image. Since that image is in fast local processor RAM, it should be pretty fast to draw text, lines and such.

Maybe 5 or 10 times per second, that buffer is copied in bulk to the display. With the AVR I used, this update operation took 13mS:
Code:
//============================================================================
void LC7981_Instruction_And_Data_Write(ubyte instruction, ubyte data)
  {
  //Aim at the instruction register
  PORTG=PG_E_LO|PG_RW_LO|PG_RS_HI|PG_RES_NOT_HI|PG_CS_NOT_LO;
  //Meet the control setup time (90nS)
   _delay_cycles(1);
  //Start the write pulse
  PORTG=PG_E_HI|PG_RW_LO|PG_RS_HI|PG_RES_NOT_HI|PG_CS_NOT_LO;
  //Put the data on the LCD's pins.
  PORTA=instruction;
  //Meet the "data setup time, write" (220nS)
   _delay_cycles(2);
  //End the write pulse, clocking the data into the command register.
  //Aim at the data register.
  PORTG=PG_E_LO|PG_RW_LO|PG_RS_LO|PG_RES_NOT_HI|PG_CS_NOT_LO;
  //Writing to the command register is "fast" so we do not have to
  //worry about checking busy flag, etc.
  //Meet the control setup time (90nS)
   _delay_cycles(1);
  //Start the write pulse
  PORTG=PG_E_HI|PG_RW_LO|PG_RS_LO|PG_RES_NOT_HI|PG_CS_NOT_LO;
  //Put the data on the LCD's pins.
  PORTA=data;
  //Meet the "data setup time, write" (220nS)
   _delay_cycles(2);
  //End the write pulse, clocking the data into the command register.
  PORTG=PG_E_LO|PG_RW_LO|PG_RS_LO|PG_RES_NOT_HI|PG_CS_NOT_LO;
  //Writing to the data register starts some execution, and the busy
  //flag will go high. However, since this function is only called
  //during initialization, and to setup the address before full-screen
  //updates, we will just delay a tad instead of messing with waiting
  //for the busy bit.
  //Max execution time (assuming 400KHz osc) should be around 25uS.
   _delay_cycles(500);
  }
//============================================================================
// Takes about 13.3mS (288 KB/S) reading busy flag
void UpdateLCD(void)
  {
  register ubyte
    row,col,timeout;
 
  //Reset the address to position 0
  LC7981_Instruction_And_Data_Write(0x0A,0x00); //Cursor low address setting
  LC7981_Instruction_And_Data_Write(0x0B,0x00); //Cursor high address setting

  //Give the "Write Data" command.
  //Aim at the instruction register
  PORTG=PG_E_LO|PG_RW_LO|PG_RS_HI|PG_RES_NOT_HI|PG_CS_NOT_LO;
  //Meet the control setup time (90nS)
   _delay_cycles(1);
  //Start the write pulse
  PORTG=PG_E_HI|PG_RW_LO|PG_RS_HI|PG_RES_NOT_HI|PG_CS_NOT_LO;
  //Put the data on the LCD's pins.
  PORTA=0x0C; //"Write Display Data" instruction
  //Meet the "data setup time, write" (220nS)
   _delay_cycles(2);
  //End the write pulse, clocking the data into the command register.
  //Aim at the data register.
  PORTG=PG_E_LO|PG_RW_LO|PG_RS_HI|PG_RES_NOT_HI|PG_CS_NOT_LO;
  //Writing to the command register is "fast" so we do not have to
  //worry about checking busy flag, etc.

  for(row=0;row<=127;row++)
    for(col=0;col<=29;col++)
      {
      //Load the data into the port A output latches
      PORTA=display[row][col];
      //We need to check the busy flag before writing. Make port A input
      DDRA= 0x00;
      //Tell the controller we will want the busy flag on DB7
      PORTG=PG_E_LO|PG_RW_HI|PG_RS_HI|PG_RES_NOT_HI|PG_CS_NOT_LO;
      //Set out timeout count, which will also meet the
      //control setup time (90nS)
      timeout=255;
      //Start the read pulse
      PORTG=PG_E_HI|PG_RW_HI|PG_RS_HI|PG_RES_NOT_HI|PG_CS_NOT_LO;
      //Meet the data delay time (read) (140nS)
      _delay_cycles(1);
      //Wait for DB7 (busy) to drop, or timeout.
      while((PINA&0x80)&&timeout--);
      //End the read pulse, set the lines up for a write.
      PORTG=PG_E_LO|PG_RW_LO|PG_RS_LO|PG_RES_NOT_HI|PG_CS_NOT_LO;
      //Make port A output, the latch is already loaded with display[row][col]
      //This also meets the control setup time (90nS)
      DDRA= 0xFF;
      //Start the write pulse
      PORTG=PG_E_HI|PG_RW_LO|PG_RS_LO|PG_RES_NOT_HI|PG_CS_NOT_LO;
      //Meet the "data setup time, write" (220nS)
      _delay_cycles(2);
      //End the write pulse, clocking the data into the command register.
      PORTG=PG_E_LO|PG_RW_LO|PG_RS_LO|PG_RES_NOT_HI|PG_CS_NOT_LO;
      }
  }
//============================================================================
This architecture is a lot "cleaner" (easier to understand, simpler code) than directly messing with the LCD, but it does take more RAM and maybe more MIPS. This architecture does allow much better portability if you want or must change the LCD.

Keep in mind that processors have improved by leaps and bounds over the last 20 years, and that the LC7981 LCD controller is probably a 20-year old design.
 

bwhiten

New member
Similar method

Very similar to what I am doing. 8 x 20 image lines stored in memory that are updated to the display at processor speed. I'm using a PIC16F887 at 20MHz. This PIC is a slave to another PIC over I2C and that is where the images are coming from.
I did have some early speed troubles with the I2C bus that led me to move to character mode, that are now resolved. I think I'll try going back to graphics mode to verify the draw speed again. I'm now also only updating the lines that need updating instead of redrawing the entire screen every update.
 

bwhiten

New member
Font to map conversion

Thanks for the code samples. Can you point out where you do the font(character) to memory-image conversion in the files I received?
 

CF Tech

Administrator
lcd_draw.c:
void put_letter(ubyte x, ubyte y, ubyte letter)
void put_string_P(ubyte x, ubyte y, ubyte Field_Width,const prog_char *input) //Flash
void put_string(ubyte x, ubyte y, ubyte Field_Width, const char *input) //ram
 
Top