Frame Buffer
Frame Buffer를 이용한 Programming / Frame Buffer란 frame buffer란 linux system에서 그래픽을 표현할 수 있는 hardware를 말함. PC라면 그래픽 카드, Rebis같으면 LCD controller를 frame buffer 장치라고 함. frame buffer를 user level application이 제어할 수 있도록 만들어진 device driver를 frame buffer driver라고 함 The frame buffer device provides an abstraction for the graphic hardware. It represents the frame buffer of some video hardware and allows application software to access the graphics hardware through a well-defined interface, so the software doesn’t need to know anything about the low-level (hardware register) stuff. The device is accessed through special device nodes, usually located in the /dev directory, i.e. /dev/fb* The frame buffer devices are also normal memory devices, this means, you can read and write their contents. You can, for example, make a screen snapshot by cp /dev/fb0 myfile
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을 한다. User application TFT-LCD LCD driver (frame buffer driver) LCD controller (frame buffer) Frame buffer data 프레임버퍼 메모리에 해당정보를 써넣으면 클럭에 맞추어 LCD의 reflash에 DMA에 의해 행당 정보가 LCD로 전송되어 그림, 도형등을 표시한다.
LCD 정보 얻어오기 LCD 정보 얻어오기(1) 실습보드에 있는 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
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; x-resolution, y-resolution, x-resolution(virtual), y-resolution(virtual), bpp (bit per pixel) 에 대한 정보가 들어 있는 구조체 length of frame buffer memory에 대한 정보가 들어있는 구조체
LCD 정보 얻어오기 LCD 정보 얻어오기(3) fb_var_screeninfo 구조체 __u32 는 asm/type.h에 unsigned int로 정의 되어 있음.
LCD 정보 얻어오기 LCD 정보 얻어오기(4) fb_fix_screeninfo
LCD 정보 얻어오기 LCD 정보 얻어오기(5) fbfd = open(FBDEVFILE, O_RDWR); //frame buffer의 node인 /dev/fb 를 open if(fbfd<0){ perror("fbdev open"); exit(1); } ret = ioctl(fbfd, FBIOGET_VSCREENINFO, &fbvar); if(ret < 0){ perror("fbdev ioctl(FSCREENINFO)"); ret = ioctl(fbfd, FBIOGET_FSCREENINFO, &fbfix); Kernel로 부터 fb_var_screeninfo 정보를 가져올 때 쓰는 옵션, fbvar에 저장한다. Kernel로 부터 fb_fix_screeninfo정보를 가져올 때 쓰는 옵션, fbfix에 저장한다. FBIOGET_VSCREENINFO와 FBIOGET_FSCREENINFO는 linux/fb.h에 정의 되어 있음.
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("length of frame buffer memory: %d\n", fbfix.smem_len); close(fbfd); exit(0); return 0; }
LCD 정보 얻어오기 LCD 정보 얻어오기(7) Host에서 위에서 배운 source를 fbinfo.c로 저장한 뒤에 아래와 같이 compile 한다. minicom이나 NFS 방식을 이용하여 target으로 fbinfo라는 실행 파일을 download한다.
TFT - LCD LCD에 점 찍기 LCD에 점 찍기(1) TFT-LCD 해상도 : 240 * 320 240 320 (0,0) (239,0) TFT - LCD (0,319) (230,319)
LCD에 점 찍기 LCD에 점 찍기(2) 보드의 LCD는 16bpp를 지원한다. 즉, 한 pixel를 표현하기 위해 16bit의 색 정보가 필요하다 MSB에서 LSB 쪽으로 R,G,B 순이다. 참고로 R=0,G=0,B=0은 black이며, R=255, G=255, B=255는 white이다. RED (5 bit) Green (6 bit) Blue (5 bit)
LCD에 점 찍기 LCD에 점 찍기(3) 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) (MSB)15 ~ 11 10 ~ 5 4 ~ 0(LSB)
LCD에 점 찍기 LCD에 점 찍기(4) lseek() : 파일 포인터 이동할 때 쓰는 함수 include <sys/type.h> include <unistd.h> 위 2 header file을 include해야 함. off_t lseek(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 : 파일 포인터를 맨 끝으로 옮긴다.
lseek (fd, (off_t)+100, SEEK_CUR) LCD에 점 찍기 LCD에 점 찍기(5) lseek (fd, (off_t)+100, SEEK_CUR) 현재의 위치 -100 +100 SEEK_SET SEEK_CUR SEEK_END
LCD에 점 찍기 LCD에 점 찍기(6) #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/type.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에 점 찍기(7) 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("fbdev open"); exit(1); } // 커널로부터 lcd에 관한 정보를 fbvar에 저장한다. ret = ioctl(fbfd, FBIOGET_VSCREENINFO, &fbvar); if(ret < 0){ perror("fbdev ioctl");
LCD에 점 찍기 LCD에 점 찍기(8) if(fbvar.bits_per_pixel!=16){ //bpp가 16bit인지 check fprintf(stderr, "bpp is not 16\n"); exit(1); } //red 점을 (0,0)에 찍는다. if(lseek(fbfd, 0, SEEK_SET) < 0){ //file point를 맨 앞으로 옮김 perror("fbdev lseek"); exit(1); } pixel = makepixel(&fbvar, 255, 0, 0); /*red pixel*/ write(fbfd, &pixel, 2); /*write 2byte(16bit)*/ //green점을 (100,50)에 찍는다. offset = 50*fbvar.xres*(16/8)+100*(16/8); if(lseek(fbfd, offset, SEEK_SET) < 0){ //file point를 맨 앞에서 offset만큼 옮김 exit(1); } pixel = makepixel(&fbvar, 0, 255, 0); /*green pixel */
LCD에 점 찍기 LCD에 점 찍기(9) //blue점을 (50,100)에 찍는다. offset = 100*fbvar.xres*(16/8)+50*(16/8); if(lseek(fbfd, offset, SEEK_SET)<0){ //file point를 맨앞에서 offset만큼 옮김 perror("fbdev lseek"); exit(1); } pixel = makepixel(&fbvar,0,0,255); /*blue pixel */ write(fbfd, &pixel, 2);/*write 2byte(16bit)*/ //white점을 (100,100)에 찍는다. offset = 100*fbvar.xres*(16/8)+100*(16/8); if(lseek(fbfd, offset, SEEK_SET) < 0){ //file point를 맨앞에서 offset만큼 옮김 exit(1); } pixel = makepixel(&fbvar, 255, 255, 255); /*white pixel */ write(fbfd, &pixel, 2); /*write 2byte(16 bit)*/ close(fbfd); exit(0); return 0; }
LCD에 점 찍기 LCD에 점 찍기(10) Host에서 위에서 배운 소스를 fbpixel.c로 저장한 후 아래와 같이 compile한다. minicom이나 NFS 방식을 이용하여 target으로 fbpixel이라는 실행 파일을 download한다. target에서 실행하여 결과를 확인한다. % ./fbpixel