TFT LCD 디바이스 드라이버
LCD 구조
Color filter Backlight 에서 나온 백색광이 액정 셀을 통과하면서 투과율이 조절되고 red, green, blue 의 color filter 를 투과해 나오는 빛의 혼합을 통해 색이 구성됨 Color filter 는 셀사이의 빛을 차단하는 black matrix, 색상을 구현하는 RGB pattern, 전압을 인가하기 위한 공통전극으로 구성
LCD 동작원리
LCD 동작원리
LCD 동작원리
XHYPER270-TKU Block Diagram
PXA270 LCD Control Block Diagram FCLK: LCD 패널에 수직신호를 인가한다. high로 되었을 때 Horizontal Sync 시그널이 시작된다. 즉, LCD data에 데이터 출력을 시작 할 준비를 한다. LCLK: LCD패널에 수평신호를 인가한다. 수평신호가 high일 때, Line데이터 시작을 의미 하고, Low로 되었을 때 Line 데이터가 유효하 다. PCLK: LCD pixel clock, active mode에서 lcd controller가 enable 동안 계속적으로 toggle 한다. BIAS: PCLK을 이용하여 BIAS가 assert되었 을때 LCD는 LDD data를 latch한다. Output enable LCD에 출력한 line data[0:14]
LCD Driver 이해 LCD Driver 이해(1) User level에서전송한frame buffer data를LCD driver가수신하여LCD controller가TFT-LCD에출력한다. User level과driver간에“/dev/fb0”라는node를통하여data를전송하며, driver가할당한memory를user application에서도사용할수있도록memory mapping을한다. Device Driver Source는 \PAX270\linux-2.6.11-h270-tku_v1.1\drivers\video\pxafb.c 에 위치.
LCD Driver 이해 LCD Driver 이해(2) PXA270는초기화로4가지registers를setting한다. LCCR0 : LCD Controller Configuration Register0 LCD의종류(color or monochrome), Enable/Disable등을선택(0x000000F9) LCCR1: LCD Controller Configuration Register1 horizontal signal에관련된값(0x06020CEF) LCCR2 : LCD Controller Configuration Register2 vertical signal에관련된값(0x0102053F) LCCR3 : pixel clock frequency setting(0x04700005) TFT-LCD 640 * 480 Pixel Size
LCD Driver 이해 LCD Driver 이해(3) Driver가 하는 주 역할 DMA에 프레임버퍼의 포인터를 주어주는 일 Passive인지 Active인지 설정하는 일 Dither Logic을 설정하는 일 LCD로 데이터를 보내기 위한 각 클럭과 시그널들의 타이밍을 설정하는 일
Frame Buffer
Frame Buffer Frame Buffer란 Linux system에서 그래픽을 표현할 수 있는 hardware PC라면 그래픽카드, PXA270의 경우 LCD controller frame buffer를 user level application이 제어할 수 있도록 만들어진 device driver를 frame buffer driver라고 함
LCD에 출력하는 원리 LCD 출력 원리 User level에서 전송한 frame buffer data를 LCD driver가 수신하여 LCD controller가 TFT-LCD에 출력 User level과 driver간에 “/dev/fb0”라는 node를 통하여 data를 전송하며, driver가 할당한 memory를 user application에서도 사용할 수 있도록 memory mapping을 한다.
LCD 정보 정보 얻어오기 LCD 정보얻어오기(1) XHYPER270-TKU 실습 보드에 있는 TFT-LCD의 해상도와 할당된 메모리의 크기 등 LCD에 관한 정보를 얻어보자. 위의 정보들은 <linux/fb.h>에 정의되어 있는 fb_var_screeninfo와 fb_fix_screeninfo라는 구조체에 들어있다. 알고자 하는 LCD 정보 x-resolution y-resolution x-resolution(virtual) y-resolution(virtual) bpp(bit per pixel) length of frame buffer memory
LCD 정보 얻어오기 LCD 정보얻어오기(2) #include <stdio.h> #include <stdlib.h> /*for exit*/ #include <unistd.h>/*for open/close..*/ #include <fcntl.h> /*for O_RDWR*/ #include <sys/ioctl.h> /*for ioctl*/ #include <linux/fb.h> /*for fb_var_screeninfo, FBIOGET_VSCREENINFO*/ #define FBDEVFILE “/dev/fb” int main(){ int fbfd; int ret; struct fb_var_screeninfo fbvar; struct fb_fix_screeninfo fbfix;
LCD 정보 얻어오기 LCD 정보얻어오기(3) fb_var_screeninfo구조체
LCD 정보 얻어오기 LCD 정보얻어오기(4) fb_fix_screeninfo
LCD 정보 얻어오기 LCD 정보얻어오기(5) fbfd= open(FBDEVFILE, O_RDWR); //frame buffer의 node인 /dev/fb를 open if(fbfd<0){ perror("fbdevopen"); exit(1); } ret = ioctl(fbfd, FBIOGET_VSCREENINFO, &fbvar); if(ret< 0){ perror("fbdevioctl(FSCREENINFO)"); ret = ioctl(fbfd, FBIOGET_FSCREENINFO, &fbfix);
LCD 정보 얻어오기 LCD 정보얻어오기(6) // x-resolution printf("x-resolutionnn: %d\n", fbvar.xres); //y-resolution printf("y-resolution: %d\n", fbvar.yres); //virtual x-resolution printf("x-resolution(virtual): %d\n", fbvar.xres_virtual); //virtual y-resolution printf("y-resolution(virtual): %d\n", fbvar.yres_virtual); //bpp(bit per pixel) printf("bpp: %d\n", fbvar.bits_per_pixel); //the size of frame buffer memory printf("lengthof frame buffer memory: %d\n", fbfix.smem_len); close(fbfd); exit(0); return 0; }
LCD 정보 얻어오기 LCD 정보얻어오기(7) compile 한다. minicom이나 NFS 방식을 이용하여 target으로 fbinfo라는 실행 파일을download한다.
LCD에 점 찍기 LCD에 점찍기(1) XHYPER270-TKU 보드의 LCD는16bpp를 지원한다. 즉, 한 pixel를 표현하기 위해16bit의 색 정보가 필요하다. MSB에서 LSB 쪽으로 R,G,B 순이다. 참고로 R=0, G=0, B=0은 black이며, R=255, G=255, B=255는 white이다.
LCD에 점 찍기 LCD에 점찍기(2) makepixel() 함수는 r, g, b 3개의 byte(0~255) 값을 받아서 16bit pixel 값을 만들어 내는 함수이다. unsigned short makepixel(ubyte r, ubyte g, ubyte b) {return (unsigned short)(((r>>3)<<11)|((g>>2)<<5)|(b>>3));} 각 색별로 아래 3bit는 버린다. lseek() 함수를 사용하여 offset을 계산하여 점을 찍는다. offset=ypos*(한 줄의 바이트 수)+ xpos*(한 픽셀당 바이트수) 한 픽셀당 바이트 수=16/8(16bpp이므로.) 한 줄의 바이트 수=(한 줄의 픽셀 수)* (한 픽셀당 바이트 수)=xres*(16/8) offset=ypos*xres*(16/8)+xpos*(16/8)
LCD에 점 찍기 LCD에 점찍기(3) lseek() : 파일 포인터 이동할 때 쓰는 함수 #include <sys/types.h> #include <unistd.h> off_tlseek(int fildes, off_t offset, int start_flag); fildes: 읽고 쓰기 위한 파일지시자 offset : 시작 위치에서 더할 바이트 수 start_flag: 시작 지점 지정 off_t: typedef long off_t; start_flag SEEK_SET : 파일 포인터가 어디 있든지 맨 앞으로 옮긴다. SEEK_CUR : 현재의 파일포인터에서부터 읽고 쓴다. SEEK_END : 파일 포인터를 맨끝으로 옮긴다.
LCD에 점 찍기
LCD에 점 찍기 LCD에 점찍기(4) #include <stdio.h> #include <stdlib.h>/* for exit */ #include <unistd.h> /* for open/close.. */ #include <fcntl.h> /* for O_RDONLY */ #include <sys/ioctl.h> /* for ioctl*/ #include <sys/types.h> /* for lseek() */ #include <linux/fb.h> /*for fb_var_screeninfo, FBIOGET_VSCREENINFO*/ #define FBDEVFILE “/dev/fb” typedef unsigned char ubyte; //색 정보를 16bit로 변환해 주는 함수 unsigned short makepixel(ubyte r, ubyte g, ubyte b) {return (unsigned short)(((r>>3)<<11)|((g>>2)<<5)|(b>>3));}
LCD에 점 찍기 LCD에 점찍기(5) int main(){ int fbfd; int ret; struct fb_var_screeninfo fbvar; unsigned short pixel; int offset;//frame buffer driver file point를 얻는다. fbfd= open(FBDEVFILE, O_RDWR); if(fbfd< 0){perror("fbdevopen");exit(1);} // 커널로부터 LCD에 관한 정보를 fbvar에 저장한다. ret = ioctl(fbfd, FBIOGET_VSCREENINFO, &fbvar); if(ret< 0) { perror("fbdevioctl"); exit(1); }
LCD에 점 찍기 LCD에 점찍기(6) if(fbvar.bits_per_pixel!=16) { //bpp가 16bit인지 check printf(stderr, "bpp is not 16\n"); exit(1); } //red 점을(0,0)에찍는다. if(lseek(fbfd, 0, SEEK_SET) < 0){ //file pointer를 맨 앞으로 옮김 perror("fbdevlseek");exit(1); pixel = makepixel(255, 0, 0); /*red pixel*/ write(fbfd, &pixel, 2); /*write 2bytes (16bit)*/ //green점을(100,50)에 찍는다. offset = 50*fbvar.xres*(16/8)+100*(16/8); if(lseek(fbfd, offset, SEEK_SET) < 0){ //file point를 맨 앞에서 offset만큼 옮김perror("fbdevlseek");exit(1); pixel = makepixel(0, 255, 0); /*green pixel */ write(fbfd, &pixel, 2); /*write 2bytes (16bit)*/
LCD에 점 찍기 LCD에 점찍기(7) //blue점을 (50,100)에 찍는다. offset = 100*fbvar.xres*(16/8)+50*(16/8); if(lseek(fbfd, offset, SEEK_SET)<0){ //file pointer를 맨 앞에서 offset만큼 옮김 perror("fbdevlseek");exit(1); } pixel = makepixel(0,0,255); /*blue pixel */ write(fbfd, &pixel, 2); /*write 2bytes (16bit)*/ //white점을(100,100)에 찍는다. offset = 100*fbvar.xres*(16/8)+100*(16/8); if(lseek(fbfd, offset, SEEK_SET) < 0){ //file point를 맨 앞에서 offset만큼 옮김 perror("fbdevlseek");exit(1); pixel = makepixel255, 255, 255); /*white pixel */ write(fbfd, &pixel, 2); /*write 2byte(16 bit)*/ close(fbfd); return 0; } // end of main
LCD에 점 찍기 LCD에 점찍기(8) Host에서 소스를 fbpixel.c로 저장한 후 아래와 같이compile한다. minicom이나 tftp를 이용하여 target으로 fbpixel이라는 실행파일을 download한다. Target에서 실행하여 결과를 확인한다. # ./fbpixel