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
가 되겠습니다.
기술정보 및 자료/EBTB1200