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

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

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


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

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_H  (GPIOA->BSRR = GPIO_Pin_8)  // 1
#define LcdBl_L  (GPIOA->BRR = GPIO_Pin_8)   // 0

#define LcdRd_H  (GPIOB->BRR = GPIO_Pin_4)   // 0  Low Active
#define LcdRd_L  (GPIOB->BSRR = GPIO_Pin_4)  // 1

#define LcdWr_H  (GPIOA->BRR = GPIO_Pin_15)  // 0  Low Active
#define LcdWr_L  (GPIOA->BSRR = GPIO_Pin_15) // 1

#define LcdRs_H  (GPIOA->BSRR = GPIO_Pin_14) // 1
#define LcdRs_L  (GPIOA->BRR = GPIO_Pin_14)  // 0

#define LcdCs_H  (GPIOA->BRR = GPIO_Pin_13)  // 0  Low Active
#define LcdCs_L  (GPIOA->BSRR = GPIO_Pin_13) // 1

#define LcdData     (GPIOC->ODR)    // format : (rrrrrggg gggbbbbb)binary

#define LcdReset_H  (GPIOB->BRR = GPIO_Pin_3) // 0  Low Active
#define LcdReset_L  (GPIOB->BSRR = GPIO_Pin_3)// 1

void LcdSetReg(unsigned char reg, unsigned char cmd)
{           
  LcdCs_H;

  LcdRs_L;   //register
  LcdData=reg;
  LcdWr_H;
  LcdWr_L;
 
  LcdRs_H;   //command
  LcdData=cmd;
  LcdWr_H;
  LcdWr_L;

  LcdCs_L;
}



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 int LcdGetReg(unsigned char reg)
{
  unsigned int cmd;

  LcdCs_H;

  LcdRs_L;   //register
  LcdData=reg;
  LcdWr_H;
  LcdWr_L;

  GPIOC->CRL=0x44444444;   // LCD_D0 ~ LCD_D7 : INPUT_FLOATING
  GPIOC->CRH=0x44444444;   // LCD_D8 ~ LCD_D15 : INPUT_FLOATING

  LcdRs_H;   //command
  LcdRd_H;
  cmd=GPIOC->IDR; 
  LcdRd_L;

  LcdCs_L;
                             
  GPIOC->CRL=0x33333333;   // LCD_D0 ~ LCD_D7 : OUTPUT_PUSH-PULL 
  GPIOC->CRH=0x33333333;   // LCD_D8 ~ LCD_D15 : OUTPUT_PUSH-PULL 

  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
가 되겠습니다.


 

Posted by E2BOX