본문 바로가기
기술정보 및 자료/EBTB1000

3.2 inch 320*240 TFT LCD 제어하기


ILLUMIINANT사의 3.2 inch TFT LCD를 제어하는 방법에 대해 알아 보도록 하겠습니다.


TFT LCD 패널에서는 보통 HSYNC, VSYNC, PCLK, DATA(n)등의 핀이 있습니다.
이 핀들을 제어하기 위해서는 PCLK 수십MHz 와 HSYNC, VSYNC에 동기된 각픽셀의 데이타를 계속 입력해야 합니다. 그래서 일반적인 MPU에서 컨트롤 하기 적합 하지 않습니다.

그래서 TFT LCD 컨트롤러가 내장된 LCD를 사용합니다.
EBTB1000의 TFT LCD에 내장되어 있는 컨트롤러는 HX8347 이라는 칩 입니다.


첨부파일 'I3202-7HMT2432A.pdf'은 LCD DATASHEET입니다.
첨부파일 'HX8347-A_T_DS_preliminary_01_070409.pdf'은 컨트롤러 DATASHEET입니다.

LCD DATASHEET를 보면 Supply voltage가 2.2V~3.3V입니다.
EBTB1000은 ATmega128을 사용하여 5V 동작하도록 되어 있습니다.
따라서 신호레벨이 맞지 않기 때문에 74ALVC164245를 사용하여 level shift 하여 데이터를 주고 받습니다.
나머지 /CS, /RD, /WR, RS, /RESET 단방향 신호들은 저항을 통해 전압분배 되도록 구성이 되어 있습니다.
보드 전원 입력시 5V로 입력 하십시오. 주의하시기 바랍니다.

HX8347의 인터페이스 방식은 M80 Parallel / M68 Parallel 방식을 지원합니다.
M80과 M68의 차이점은 M80은 /RD와 /WR을 사용하고 M68은 R/W와 /E 방식을 사용합니다.
M80의 Read
/RD=0    /WR=1
M80의 Write
/RD=1    /WR=0
M68의 Read
R/W=1   E=Active
M68의 Write
R/W=0   E=Active

LCD에는 M80인터페이스로 핀이 나와 있으니 M80인터페이스에 맞게 제어를 하면 되겠습니다.

아래는 LCD의 M80 register wrtie cycle 타이밍도 입니다.

NCS는 CS핀, DNC_SCL은 RS핀, RW_NRD는 /RD핀, E_NWR는 /WR핀을 의미 합니다.
타이밍도에 따르면.. 
/CS를 low active하고 RS를 low(register)로 두고 D0~D7에 register번지를 출력 한 뒤 /WR 를 low후 high로 전환 하여 register번지를 먼저 write합니다.
그 다음 RS를 high(data)로 두고 D0~D7에 command 출력 한 뒤 /WR 를 low후 high로 전환 하여 register command를 write합니다.

위의 타이밍에 따르는 c언어 register write함수를 아래와 같이 만들 수 있습니다.

#define LcdBl(X)      PORTE.4=X
#define LcdDirWR(X)   PORTD.5=(!X)

#define LcdRd(X)      PORTA.7=(!X)
#define LcdWr(X)      PORTA.6=(!X)
#define LcdRs(X)      PORTA.5=X
#define LcdCs(X)      PORTA.4=(!X)

#define LcdDataH(X)   PORTB=X
#define LcdDataL(X)   PORTC=X


void LcdSetReg(unsigned char reg, unsigned char cmd)
{           
  LcdCs(1);

  LcdRs(0);   //register
  LcdDataH(0x00);
  LcdDataL(reg);
  LcdWr(1);
  LcdWr(0);
 
  LcdRs(1);   //command
  LcdDataL(cmd);
  LcdWr(1);
  LcdWr(0);

  LcdCs(0);
}


LCD의 M80 register read cycle 타이밍은 아래와 같습니다.


타이밍도에 따르면.. 
/CS를 low active하고 RS를 low(register)로 두고 D0~D7에 register번지를 출력 한 뒤 /WR 를 low후 high로 전환 하여 register번지를 먼저 write합니다.
그 다음 RS를 high(data)로 두고 /RD 를 low로 전환 하고 D0~D7을 통해 register data를 read한후 /RD를 다시 high로 전환 합니다.

위의 타이밍에 따르는 c언어 register write함수를 아래와 같이 만들 수 있습니다.

unsigned char LcdGetReg(unsigned char reg)
{
  unsigned char cmd;

  LcdCs(1);

  LcdRs(0);   //register
  LcdDataH(0x00);
  LcdDataL(reg);
  LcdWr(1);
  LcdWr(0);
                           
  DDRB=0x00; DDRC=0x00; LcdDirWR(0); // ReadMode

  LcdRs(1);   //command
  LcdRd(1);
  cmd=PINC; 
  LcdRd(0);

  LcdCs(0);
                                               
  LcdDirWR(1); DDRB=0xff; DDRC=0xff; // WriteMode 

  return cmd;
}


LCD 컨트롤러 칩인 HX8347의 데이타포트는 D0~D17까지 있으나 LCD에는 D0~D15로 총 16bit 만 나와 있습니다.
데이타 출력시 16bit로 1pixel출력하는 포맷은 아래 그림과 같습니다.


위의 그림과 같이 RGB565 포맷으로 출력 하면 되겠습니다.


이제 화면으로 데이타를 출력하는 방법에 대해 알아 보겠습니다.
우선 현재 LCD에 맞게 컨트롤러 칩을 설정해야 됩니다.
대부분의 LCD판매처에서 initial코드라고 하여 컨트롤러 설정 소스를 제공하며,
LCD사이즈, 파워설정, Gamma설정 등에 대한 코드가 포함되어 있습니다.

이제 원하는 영역에 데이타를 write하기만 하면 됩니다.
우선 write하기 원하는 영역을 설정해야 합니다.





위와같이 컨트롤러 데이타시트에 'Column Address Start'레지스터, 'Column Address End'레지스터, 'Row Address Start'레지스터, 'Row Address End'레지스터 가 있습니다.
write하기 원하는 영역을 설정하기 위해 이 레지스터들을 설정합니다.

예를 들어 LCD의 (5,10)에서 부터 (15,20)까지의 영역에 데이타를 write하고 싶다면,
Column Address Start Register Upper Byte(R02h) = 0
Column Address Start Register Low Byte(R03h) = 5
Column Address End Register Upper Byte(R04h) = 0
Column Address End Register Low Byte(R05h) = 15

Row Address Start Register Upper Byte(R06h) = 0
Row Address Start Register Low Byte(R07h) = 10
Row Address End Register Upper Byte(R08h) = 0
Row Address End Register Low Byte(R09h) = 20
이렇게 설정 하면 되겠습니다.
이것을 보통 LCD 윈도우(window) 설정이라 합니다.

위의 내용을 C함수로 아래와 같이 구현 할 수 있습니다.

void LcdSetWindow(unsigned short x, unsigned short y, unsigned short width, unsigned short height)
{         
  unsigned short ex,ey;
  LcdSetReg(0x02,(x>>8)&0xff);  //Column Address Start Register HighByte
  LcdSetReg(0x03,x&0xff);       //Column Address Start Register LowByte
  LcdSetReg(0x06,(y>>8)&0xff); //Row Address Start Register HighByte
  LcdSetReg(0x07,y&0xff);       //Row Address Start Register LowByte
 
  ex = x+width-1;
  ey = y+height-1;
 
  LcdSetReg(0x04,(ex>>8)&0xff); //Column Address End Register HighByte
  LcdSetReg(0x05,ex&0xff);      //Column Address End Register LowByte
  LcdSetReg(0x08,(ey>>8)&0xff); //Row Address End Register HighByte
  LcdSetReg(0x09,ey&0xff); //Row Address End Register LowByte

}

윈도우 설정 후 'Write Data Register'(R22h)레지스터에 윈도우 사이즈 만큼 데이터를 써 넣으면 됩니다.

다음은 데이터를 써 넣을 경우 wirte되는 방향 설정에 대해 알아 보겠습니다.




위의 그림과 같이 MY, MX, MV의 값을 변경하여 LCD의 write방향을 정할 수 있습니다.

C함수로 아래와 같이 구현 할 수 있습니다.

void LcdSetDirection(unsigned short angle) // 0,90,180,270

   switch(angle)
    {
      case 0:
      LcdSetReg(0x16,0xc8);
      break;
     
      case 90:
      LcdSetReg(0x16,0xa8);
      break;
     
      case 180:
      LcdSetReg(0x16,0x08);
      break;
     
      case 270:
      LcdSetReg(0x16,0x68);
      break;
     
      default:
      LcdSetReg(0x16,0xc8);
      break;
    }
}


정리하면
1. LCD Reset & BackLight On
2. LCD컨트롤러 설정(initial code)
3. LCD 쓰기방향 설정
4. 윈도우설정 후 데이타 write
가 되겠습니다.

* BackLight 밝기 조정
EBTB1000 회로도를 보면 2N7002 FET를 통해 LCD BackLight On/Off를 할 수 있도록 되어 있습니다.
포트로 단순 On/Off가 아닌 밝기 조정을 PWM방식으로 할 수 있습니다.
BackLight 제어 신호가 AVR의 OC3B 포트에 연결 되어 있으므로 포트를 PWM 출력으로 설정하고 DutyRatio를 조정하여 밝기를 변경 할 수 있겠습니다.