Backlight 에서 나온 백색광이 액정 셀을 통과하면 서 투과율이 조절되고 red, green, blue 의 color filter 를 투과해 나오는 빛의 혼합을 통해 색이 구 성됨 Color filter 는 셀사이의 빛을 차단하는 black matrix, 색상을 구현하는 RGB pattern, 전압을 인 가하기 위한 공통전극으로 구성
Graphics power control ◦ 0x (ARM9) 0: Enable Flag for both LCDs (0=Disable (Prohibited)) 1: 2D Graphics Engine A (0=Disable) (Ports 008h-05Fh, Pal h) 2: 3D Rendering Engine (0=Disable) (Ports 320h-3FFh) 3: 3D Geometry Engine (0=Disable) (Ports 400h-6FFh) 4-8: Not used 9: 2D Graphics Engine B (0=Disable) (Ports 1008h- 105Fh, Pal h) 10-14: Not used 15: Display Swap (0=Send Display A to Lower Screen, 1=To Upper Screen)
2D memory layout
ek.htm#lcdiodisplaycontrol 참조 ek.htm#lcdiodisplaycontrol
Address ◦ Main display: 0x ◦ Sub display: 0x Bit control ◦ 0-2: BG Mode ◦ 3: (Engine A) BG0 2D/3D Selection (instead CGB Mode) (0=2D, 1=3D) ◦ 8: Screen Display BG0 (0=Off, 1=On) ◦ 9: Screen Display BG1 (0=Off, 1=On) ◦ 10: Screen Display BG2 (0=Off, 1=On) ◦ 11: Screen Display BG3 (0=Off, 1=On) ◦ 16-17: Display Mode (Engine A: 0..6, Engine B: 0..5) ◦ 18-19: (Engine A) VRAM block (0..3=VRAM A..D) (For Capture & above Display Mode=2) ◦ 24-26: (Engine A) Character Base (in 64K steps) (merged with 16K step in BGxCNT) ◦ 27-29: (Engine A) Screen Base (in 64K steps) (merged with 2K step in BGxCNT) ◦ 30: BG Extended Palettes (0=Disable, 1=Enable)
Main 2D Engine ModeBG0BG1BG2BG3 Mode 0Text/3DText Mode 1Text/3DText Rotation Mode 2Text/3DTextRotation Mode 3Text/3DText Extended Mode 4Text/3DTextRotationExtended Mode 5Text/3DTextExtended Mode 63D-Large Bitmap- Frame BufferDirect VRAM display as a bitmap Sub 2D Engine ModeBG0BG1BG2BG3 Mode 0Text Mode 1Text Rotation Mode 2Text Rotation Mode 3Text Extended Mode 4Text RotationExtended Mode 5Text Extended
Background mode 사용시 Layout
BGx 의 control register (16 bits) ◦ Engine A: h~ Eh ◦ Engine B: h~400100Eh Bit7 Bit2 Mode Selection 0 CharBaseLsb rot/scal with 16bit bgmap entries 1 0 rot/scal 256 color bitmap 1 1 rot/scal direct color bitmap ◦ Direct color bitmap 모드를 사용하면 frame buffer
Frame Buffer 란 ◦ Linux system 에서 그래픽을 표현할 수 있는 hardware ◦ PC 라면 그래픽카드, NDS 의 경우 LCD controller ◦ frame buffer 를 user level application 이 제어할 수 있도록 만들어진 device driver 를 frame buffer driver 라고 함
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 정보얻어오기 (1) ◦ TFT-LCD 의 해상도와 할당된 메모리의 크기 등 LCD 에 관한 정보 를 얻어보자. ◦ 위의 정보들은 에 정의되어 있는 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 정보얻어오기 (2) #include #include /*for exit*/ #include /*for open/close..*/ #include /*for O_RDWR*/ #include /*for ioctl*/ #include /*for fb_var_screeninfo, FBIOGET_VSCREENINFO*/ #define FBDEVFILE “/dev/fb0” int main(){ int fbfd; int ret; struct fb_var_screeninfo fbvar; struct fb_fix_screeninfo fbfix ; 17
LCD 정보 얻어오기 (3) ◦ fb_var_screeninfo 구조체
LCD 정보얻어오기 (4) ◦ fb_fix_screeninfo
LCD 정보 얻어오기 (5) fbfd= open(FBDEVFILE, O_RDWR); //frame buffer 의 node 인 /dev/fb0 를 open if(fbfd<0){ perror("fbdevopen"); exit(1); } ret = ioctl(fbfd, FBIOGET_VSCREENINFO, &fbvar); if(ret< 0){ perror("fbdevioctl(FSCREENINFO)"); exit(1); } ret = ioctl(fbfd, FBIOGET_FSCREENINFO, &fbfix); if(ret< 0){ perror("fbdevioctl(FSCREENINFO)"); exit(1); }
LCD 정보 얻어오기 (6) printf("x-resolutionnn: %d\n", fbvar.xres); // x-resolution printf("y-resolution: %d\n", fbvar.yres); //y-resolution //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; }
display 디바이스 ◦ /dev/fb0 : Main LCD ◦ /dev/fb1 : Sub LCD mmap 함수 ◦ 열린 파일 기술자 (file descriptor) 를 통해 access 되는 파일의 내용과 관 련된 memory 의 구역에 대한 pointer 를 생성 ◦ file 이나 device driver 메모리에 mapping 시키는 함수
mmap 함수의 원형 Arguments − start: 특정 memory address 를 요청하기 위해, 일반적으로 0 으 로 설정 − length: memory segment 의 길이 설정 − prot: memory segment 를 위한 액세스 허용 권한 설정 − flags: page 에 가해지는 변경이 다른 곳에 반영되는 방법 설정 − fd: 파일 기술자 − offset: − 파일 데이터의 시작을 변경 − mapping 대상의 시작 위치를 제시하며, mapping 대상의 내용 가운 데 이 지점부터 memory 를 mapping void *mmap (void *start, size_t length, int prot, int flags, int fd, off_t offset);
Protection mode - PROT_EXEC: page execution - PROT_READ: page read 허락 - PROT_WRITE: page write 허락 - PROT_NONE: page access 불가 Flag parameters - MAP_FIXED: 특정한 mapping 위치로 고정 - MAP_SHARED: 다른 프로세스와 mapping 영역의 공유가 가능 - MAP_PRIVATE: mapping 을 설정한 자신만의 mapping 영역의 사용이 가 능
Program example fd = open( “ /dev/fb0 ”,O_RDWR|O_SYNC); addr = mmap(NULL,x_res*y_res,PROT_WRITE,MAP_SHARED,fd,0); *addr = 0xff; munmap(addr,1); close(fd) Header files #include “ start ” argument ◦ mapping 영역이 시작되길 원하는 위치를 의미하며, 통산 null 혹은 0 값으로 대입을 권고 ◦ 0 값이 아닌 경우 flag 인자가 MAP_FIXED 일 때 mapping 영역의 시작 위치가 이 값이 되도록 커널에서 강제적으로 요청할 경우에 사용 ◦ 일반적으로 mapping 의 시작 위치는 자동적으로 비어 있는 영역을 커널로 선택하도록 하는 것이 안전하므로 null 혹은 0 값으로 대입
mmap 함수와 함께 쓰며, mmap 으로 메핑된 메모리를 반 환 mumap 함수 원형 mmap 함수를 사용하는 방법 − open() 함수를 사용하여 열린 file descriptor 를 획득한다. − mmap() 함수를 사용하여 제어할 I/O 의 pointer 획득한다. − pointer 에서 값을 읽거나 원하는 값을 쓴다. − munmap() 함수를 사용하여 memory 공간 해제한다. − close() 함수를 이용하여 열린 descriptor 를 반환한다. int munmap (void *start, size_t length);
munmap() ◦ mmap() 과 pair 함수 ◦ Memory mapping 을 해제하는 기능 형식 ◦ #include ◦ int munmap (void *start, size_t length); Argument ◦ Start: mmap() 에서 반환했던 가상주소를 대입 함으로서, 해제할 mapping 영역을 공지 ◦ Length: 해제할 때 영역의 길이를 byte 단위로 계산하여 대입 munmap() Return value ◦ Success: return (0) ◦ Fail: return (-1)
사실, NDS 는 MMU 가 없어 직접 메모리를 access 한다. drivers/video/ndsfb.c 설정 ◦ ndsfb_probe(struct device *device) … info->screen_base = (dev->id==0 )? (void*)0x :(void*)0x ; ◦ /dev/fb0 를 mmap 하면 main VRAM (0x ) ◦ /dev/fb1 을 mmap 하면 sub VRAM (0x )
ndsfb.c ◦ ndsfb_set_par 512 의 경우는 BG2&BG3 256 은 BG2
RGB555 ◦ 5-bit Red+5-bit Green + 5-bit Blue ◦ NDS: 1555 (T: Transparency) unsigned short RGB(unsigned char r, unsigned char g, unsigned char b, unsigned char t) { return (unsigned short)( (r&0x1F) | (g&0x1F)<<5 | (b&0x1F)<<10) | (t&0x01)<<15) ); } TBBBBBGGGGGRRRRR
X Y (0,0) (a,b) (0,0) 은 fb0 라면 0x (a,b)=0x a*( )+b*( ) yres xres 1
lcddot.c #include #include /* for exit */ #include /* for open/close.. */ #include /* for O_RDWR */ #include /* for ioctl */ #include /* for mmap */ #include /* for fb_var_screeninfo, FBIOGET_VSCREENINFO */ #define FBDEVFILE "/dev/fb0" typedef unsigned char ubyte; unsigned short makepixel(ubyte r, ubyte g, ubyte b) {return (unsigned short) ( (r&0x1F) | ((g&0x1F)<<5) | ((b&0x1F)<<10) | ( 1<<15) );}
int main() { int fbfd; int ret; struct fb_var_screeninfo fbvar; unsigned short pixel; int offset; unsigned short *pfbdata; fbfd = open(FBDEVFILE, O_RDWR); if(fbfd < 0) { perror("fbdev open"); exit(1); } ret = ioctl(fbfd, FBIOGET_VSCREENINFO, &fbvar); if(ret < 0) { perror("fbdev ioctl"); exit(1); }
if(fbvar.bits_per_pixel != 16) { fbvar.bits_per_pixel=16; ioctl(fbfd, FBIOPUT_VSCREENINFO, &fbvar); } pfbdata = (unsigned short *) mmap(0, fbvar.xres * fbvar.yres * 16/8, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd, 0); if((unsigned)pfbdata == (unsigned)-1) { perror("fbdev mmap"); exit(1); } /*draw screen black*/ pixel = makepixel(0,0,0); for(offset = 0; offset < fbvar.yres * fbvar.xres; offset++) { *(pfbdata+offset) = pixel; }
/* red (50,50) */ offset = 50*fbvar.xres+50; pixel = makepixel(255,0,0); /* red pixel */ *(pfbdata+offset) = pixel; /* draw pixel */ //*pfbdata = pixel; /* green (100,50) */ offset = 50*fbvar.xres+100; pixel = makepixel(0,255,0); /* green pixel */ *(pfbdata+offset) = pixel; /* draw pixel */ /* blue (50,100) */ offset = 100*fbvar.xres+50; pixel = makepixel(0,0,255); /* blue pixel */ *(pfbdata+offset) = pixel; /* draw pixel */ /* white (100,100) */ offset = 100*fbvar.xres+100; pixel = makepixel(255,255,255); /* white pixel */ *(pfbdata+offset) = pixel; /* draw pixel */ close(fbfd); exit(0); return 0; }
앞의 예제를 변경, (50,50), (50,100), (100,50), (100,100) 을 꼭지점으로 하는 네모를 그리자. ◦ 색깔은 마음대로 코드 변경 pixel=makepixel(255,0,0); for(y=50;y<=100;y++) { for(x=50;x<=100;x++) { offset=y*fbvar.xres+x; *(pfbdata+offset) = pixel; }
Random size & color 의 사각형을 출력함 코드 참조
#include #include /* for exit */ #include /* for open/close.. */ #include /* for O_RDWR */ #include /* for ioctl */ #include /* for mmap */ #include /* for fb_var_screeninfo, FBIOGET_VSCREENINFO */ #define FBDEVFILE "/dev/fb0" typedef unsigned char ubyte; unsigned short makepixel(ubyte r, ubyte g, ubyte b) { return (unsigned short) ( (r&0x1F) | ((g&0x1F)<<5) | ((b&0x1F)<<10) | ( 1<<15) ); } 앞 부분은 이전 예제와 동일하다.
int main() { int fbfd; int ret; struct fb_var_screeninfo fbvar; unsigned short pixel; int offset; unsigned short pixel; int offset; unsigned short *pfbdata; fbfd = open(FBDEVFILE, O_RDWR); if(fbfd < 0) { perror("fbdev open"); exit(1); } ret = ioctl(fbfd, FBIOGET_VSCREENINFO, &fbvar); if(ret < 0) { perror("fbdev ioctl"); exit(1); } 앞 부분은 이전 예제와 동일하다.
if(fbvar.bits_per_pixel != 16) { fbvar.bits_per_pixel=16; ioctl(fbfd, FBIOPUT_VSCREENINFO, &fbvar); } pfbdata = (unsigned short *) mmap(0, fbvar.xres * fbvar.yres * 16/8, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd, 0); if((unsigned)pfbdata == (unsigned)-1) { perror("fbdev mmap"); exit(1); } /*draw screen black*/ pixel = makepixel(0,0,0); for(offset = 0; offset < fbvar.yres * fbvar.xres; offset++) { *(pfbdata+offset) = pixel; } 앞 부분은 이전 예제와 동일하다.
while(1) { int xpos1, ypos1; int xpos2, ypos2; int offset; int rpixel; int t, tt; /* random number between 0 and xres */ xpos1 = (int)((fbvar.xres*1.0*rand())/RAND_MAX); xpos2 = (int)((fbvar.xres*1.0*rand())/RAND_MAX); /* random number between 0 and yres */ ypos1 = (int)((fbvar.yres*1.0*rand())/RAND_MAX); ypos2 = (int)((fbvar.yres*1.0*rand())/RAND_MAX); if(xpos1 > xpos2) { t = xpos1; xpos1 = xpos2; xpos2 = t; } if(ypos1 > ypos2) { t = ypos1; ypos1 = ypos2; ypos2 = t; } 네모 그리기 !
/* random number between 0 and 65535(2^16-1) */ rpixel = (int)( *rand()/(RAND_MAX+1.0)); for(t = ypos1; t <= ypos2; t++) { for(tt = xpos1; tt <= xpos2; tt++) { offset = ( 여기를 채워 넣으시오 ); *(pfbdata+offset) = rpixel; } return 0; } 네모 그리기 !