//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();
}
//============================================================================