Clearing CFAG160160B graphic LCD displaly

NRW898

New member
Is there an easier way to clear a cfag160160b display without having to write 0's to all memory locations? This works but it's slow. I'm using 1us waits in the code, but by the time it writes to all memory locations the user can see the screen being cleared.
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 

CF Tech

Administrator
I believe that writing 0 to the display is the only way to clear it.

I wrote some AVR demo code for the 240x128 (1.2x the area, also using the LC7981). It takes about 14mS to completely update the display from a memory buffer.

Here is the code:
Code:
//From Headers

//============================================================================
//PORTA is the LCD data.
//============================================================================
. . . .
//============================================================================
#define PORTG0_LCD_E                 0x01
#define PORTG1_LCD_RW                0x02
#define PORTG2_LCD_RS                0x04
#define PORTG3_LCD_RESET_NOT         0x08
#define PORTG4_LCD_CS_NOT            0x10
#define PORTG5_NC                    0x20
#define PORTG6_NC                    0x40
#define PORTG7_NC                    0x80
//Shorter HI/LO defines
#define PG_E_HI                     0x01
#define PG_RW_HI                    0x02
#define PG_RS_HI                    0x04
#define PG_RES_NOT_HI               0x08
#define PG_CS_NOT_HI                0x10
#define PG_E_LO                     0x00
#define PG_RW_LO                    0x00
#define PG_RS_LO                    0x00
#define PG_RES_NOT_LO               0x00
#define PG_CS_NOT_LO                0x00
//============================================================================


//============================================================================
// CFAG20128D Demonstration code
// LOW_LCD.C: Low-level lcd display routines.
// Samsung LC7981 LCD Controller
// Atmel ATMega32 processor @ 16MHz
// WinAVR / AVR GCC + Atmel AVR Studio
// Copyright 2008, Crystalfontz America, Inc. http://www.crystalfontz.com
//============================================================================
#include <avr/io.h>
#include <avr/iom128.h>
#include <avr/pgmspace.h>

#include "typedefs.h"
#include "utils.h"
#include "delay_x.h"
#include "low_lcd.h"
#include "lcd_draw.h"

//============================================================================
#define CLR_E (PORTG&=~PORTG0_LCD_E)
#define SET_E (PORTG|=PORTG0_LCD_E)

#define CLR_RW (PORTG&=~PORTG1_LCD_RW)
#define SET_RW (PORTG|=PORTG1_LCD_RW)

#define CLR_RS (PORTG&=~PORTG2_LCD_RS)
#define SET_RS (PORTG|=PORTG2_LCD_RS)

#define CLR_RESET_NOT (PORTG&=~PORTG3_LCD_RESET_NOT)
#define SET_RESET_NOT (PORTG|=PORTG3_LCD_RESET_NOT)

#define CLR_CS_NOT (PORTG&=~PORTG4_LCD_CS_NOT)
#define SET_CS_NOT (PORTG|=PORTG4_LCD_CS_NOT)
//============================================================================
//This is the display memory image inside the processor.
ubyte
  display[128][30];  //3840 bytes
//============================================================================
ubyte
  display_status;
//============================================================================
// 0 = backlight off.
// 1-19 = variable brightness
// 20 = backlight on
// You must call timer::Initialize_And_Start_Timer_2() before this will work.
//============================================================================
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;
      }
  }
//============================================================================
void InitializeLCD(void)
  {
  ubyte
    i;
  i=0;

  //PORTG=PG_E_HI|PG_RW_HI|PG_RS_HI|PG_RES_NOT_HI|PG_CS_NOT_HI;
  //   0001 1111 DDRG (1 = out, 0 = in)
  //   0000 0000 PORTG
  //   |||| ||||--PG0(WD)    = PORTG0_LCD_E
  //   |||| |||---PG1(RD)    = PORTG1_LCD_RW
  //   |||| ||----PG2(ALE)   = PORTG2_LCD_RS
  //   |||| |-----PG3(TOSC2) = PORTG3_LCD_RESET_NOT
  //   ||||-------PG4(TOSC1) = PORTG4_LCD_CS_NOT
  //   |||--------PG5        = (Debug, unused, set to input)
  //   ||---------PG6        = (Debug, unused, set to input)
  //   |----------PG7        = (Debug, unused, set to input)

 
  //Idle the control lines (E=0,RW=0,RS=0,CS_NOT=0) & reset the display (RESET_NOT=0)
  PORTA=0;
  PORTG=PG_E_LO|PG_RW_LO|PG_RS_LO|PG_RES_NOT_LO|PG_CS_NOT_LO;
  Sleep(10);
  //Bring the display out of reset, and select it. In this simple demo application,
  //we will leave the controller selected (CS_NOT=0) from here on out. In a more
  //complex application, all the LCD pins except CS_NOT and RESET_NOT could be
  //shared with other peripherals.
  //Bring the controller out of reset.
  PORTG=PG_E_LO|PG_RW_LO|PG_RS_LO|PG_RES_NOT_HI|PG_CS_NOT_LO;
  Sleep(10);

  //MOV     COMM_REG,#00H           ;Command code--Mode control
  //MOV     DATA_REG,#32H           ;Set 00110010
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x00,0x32);

  //MOV     COMM_REG,#01H           ;Character pitch setting
  //MOV     DATA_REG,#77H           ;Set 10010111
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x01,0x77);

  //MOV     COMM_REG,#02H           ;Character number setting
  //MOV     DATA_REG,#29            ;240/8=30 Char in one line
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x02,29);

  //MOV     COMM_REG,#03H           ;Display duty setting
  //MOV     DATA_REG,#MaxRow_1      ;Set 1/160 duty
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x03,127);

  //MOV     COMM_REG,#08H           ;Display low address setting
  //MOV     DATA_REG,#00H           ;Low address start from 00H
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x08,0x00);

  //MOV     COMM_REG,#09H           ;Display high address setting
  //MOV     DATA_REG,#00H           ;High address start from 00
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x09,0x00);

  //Clear the display memory
  Clear_Screen();
  }
//============================================================================
 

NRW898

New member
Also, can I go from graphics mode to text mode by changing the settings (mode control, character pitch, etc.) or does the unit need to reboot?
 
Top