一、LCD显示原理
利用液晶制成的显示器称为LCD,根据驱动方式可分为静态驱动、简单矩阵驱动以及主动矩阵驱动3种。当中,简单矩阵型又可再细分扭转向列型(TN)和超扭转式向列型(STN)两种,而主动矩阵型则以薄膜式晶体管型(TFT)为主流。
一块LCD 屏显示图像不但须要LCD驱动器,还须要有对应的LCD控制器。通常 LCD 驱动器会以 COF/COG的形式与LCD 玻璃基板制作在一起,而 LCD 控制器则由外部电路来实现。很多MCU 内部直接集成了LCD 控制器,通过LCD控制器能够方便地控制 STN 和 TFT 屏。
TFT屏是眼下入式系统应用的主流,下图给出了TFT屏的典型时序。时序图中的VCLK、HSYNC 和 VSYNC 分别为像素时钟信号(用于锁存图像数据的像素时钟)、行同步信号和帧同步信号,VDEN 为数据有效标志信号,VD 为图像的数据信号。
作为帧同步信号的 VSYNC,每发出一个脉冲,都意味着新的一屏图像数据開始发送。而作为行同步信号的 HSYNC,每发出一个脉冲都表明新的一行图像资料開始发送。在帧同步以及行同步的头尾都必须留有回扫时间。
下图给出了 LCD 控制器中应该设置的 TFT屏的參数,当中的上边界和下边界即为帧切换的回扫时间,左边界和右边界即为行切换的回扫时间,水平同步和垂直同步各自是行和帧同步本身须要的时间。 xres 和 yres 则各自是屏幕的水平和垂直分辨率,常见的嵌入式设备的 LCD 分辨率主要为 320*240、640*480 等。
二、帧缓冲
1、基本概念
帧缓冲(framebuffer)是 Linux 系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,同意上层应用程序在图形模式下直接对显示缓冲区进行读写操作。用户不必关心物理显示缓冲区的详细位置及存放方式,这些都由帧缓冲设备驱动本身来完毕。对于帧缓冲设备而言,仅仅要在显示缓冲区中与显示点相应的区域写入颜色值,相应的颜色会自己主动在屏幕上显示。
帧缓冲设备为标准字符设备,主设备号为29,相应于/dev/fb%d 设备文件。帧缓冲驱动的应用很广泛,在Linux的桌面系统中,X windowserver就是利用帧缓冲进行窗体的绘制。嵌入式系统中的Qt/Embedded等图形用户界面环境也基于帧缓冲而设计。另外,通过帧缓冲可支持汉字点阵的显示,因此帧缓冲也成为Linux汉化的可行方案。
2、显示缓冲区与显示点
在帧缓冲设备中,对屏幕显示点的操作通过读写显示缓冲区来完毕,在不同的色彩模式下,显示缓冲区和屏幕上的显示点有不同的相应关系。下表各自是8位色和16 位色时显示缓冲区与显示点的相应关系:
3、Linux 帧缓冲相关数据结构与函数
1)fb_info 结构体
帧缓冲设备最关键的一个数据结构体是fb_info 结构体,它包含了关于帧缓冲设备属性和操作的完整描写叙述,这个结构体定义在/include/linux/fb.h中,代码例如以下所看到的:
该结构体记录了帧缓冲设备的所有信息,包含设备的设置參数、状态以及操作函数指针。每个帧缓冲设备都必须相应一个fb_info。
2)fb_ops结构体
fb_ops 的fb_check_var()成员函数用于检查能够改动的屏幕參数并调整到合适的值,而 fb_set_par()则使得用户设置的屏幕參数在硬件上有效。
3)fb_var_screeninfo和 fb_fix_screeninfo 结构体
fb_var_screeninfo记录用户可改动的显示控制器參数,包含屏幕分辨率和每一个像素点的比特数。fb_var_screeninfo 中的 xres 定义屏幕一行有多少个点, yres 定义屏幕一列有多少个点,bits_per_pixel 定义每一个点用多少个字节表示。而 fb_fix_screeninfo 中记录用户不能改动的显示控制器的參数,如屏幕缓冲区的物理地址、长度。当对帧缓冲设备进行映射操作的时候,就是从 fb_fix_screeninfo 中取得缓冲区物理地址的。上述数据成员都须要在驱动程序中初始化和设置。
fb_var_screeninfo和 fb_fix_screeninfo 结构体的定义在/include/linux/fb.h中,代码分别例如以下:
fb_fix_screeninfo结构体定义中第8 行的 visual 记录屏幕使用的色彩模式,在 Linux 系统中,支持的色彩模式包含例如以下几种。
● Monochrome(FB_VISUAL_MONO01、FB_VISUAL_MONO10),每一个像素是黑或白。
● Pseudo color ( FB_VISUAL_PSEUDOCOLOR 、FB_VISUAL_ST ATIC_PSEUDOCOLOR),即伪彩色,採用索引颜色显示。
● T rue color(FB_VISUAL_TRUECOLOR),真彩色,分成红、绿、蓝三基色。
● Direct color(FB_VISUAL_DIRECTCOLOR),每一个像素颜色也是有红、绿、
蓝组成,只是每一个颜色值是个索引,须要查表。
● Grayscale displays,灰度显示,红、绿、蓝的值都一样。
4)文件操作结构体
作为一种字符设备,帧缓冲设备的文件结构体定义在/linux/drivers/vedio/fbmem.c文件里,代码例如以下:
帧缓冲设备驱动的文件操作接口函数已经在fbmem.c 中被统一实现,一般不须要由驱动project师再编写。
5)注冊与注销帧缓冲设备
Linux 内核提供了register_framebuf fer()和 unregister_framebu销帧缓冲设备,这两个函数都接受fb_info指针为參数,原型为:
对于register_framebuffer()函数而言,假设注冊的帧缓冲设备数超过了 FB_MAX(眼下定义为 32),则函数返回-ENXIO,注冊成功则返回 0。
三、Linux 帧缓冲设备驱动结构
Linux 帧缓冲设备驱动的主要结构例如以下图所看到的,帧缓冲设备提供给用户空间的file_operations 结构体由fbmem.c 中的file_operations 提供,而特定帧缓冲设备fb_info结构体的注冊、注销以及当中成员的维护,尤其是fb_ops中成员函数的实现则由相应的 xxxfb.c 文件实现,fb_ops 中的成员函数终于会操作 LCD 控制器硬件寄存器。
四、帧缓冲设备的用户空间訪问
通过/dev/fbns,应用程序可进行的针对帧缓冲设备的操作主要有例如以下几种。
● 读/写 dev/fbn:相当于读/写屏幕缓冲区。比如用cp /dev/fb0 tmp 命令可将当前屏幕的内容拷贝到一个文件里,而命令cp tmp > /dev/fb0 则将图形文件tmp 显示在屏幕上。
● 映射操作:对于帧缓冲设备,可通过mmap()映射操作将屏幕缓冲区的物理地址映射到用户空间的一段虚拟地址中,之后用户就能够通过读/写这段虚拟地址訪问屏幕缓冲区,在屏幕上画图。并且若干个进程能够映射到同一个显示缓冲区。实际上,使用帧缓冲设备的应用程序都是通过映射操作来显示图形的。
● I/O 控制:对于帧缓冲设备,对设备文件的ioctl()操作可读取/设置显示设备及屏幕的參数,如分辨率、显示颜色数、屏幕大小等。
在应用程序中,操作/dev/fbn 的一般过程例如以下。
(1)打开/dev/fbn 设备文件;
(2)用 ioctl()操作取得当前显示屏幕的參数,如屏幕分辨率、每一个像素点的比特数和偏移;依据屏幕參数可计算屏幕缓冲区的大小;
(3)将屏幕缓冲区映射到用户空间;
(4)映射后就能够直接读/写屏幕缓冲区,进行画图和图片显示了。
样例:
功能:在LCD屏幕上显示红色汉字“赵”。
源代码例如以下:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
int main()
{
int fbfd=0;
struct fb_var_screeninfo vinfo;
unsigned long screensize=0;
char *fbp=0;
int x=0,y=0;
fbfd=open("/dev/fb0",O_RDWR); //打开帧缓冲设备
if(!fbfd){
printf("error\n");
exit(1);
}
if(ioctl(fbfd,FBIOGET_VSCREENINFO,&vinfo)){ //获取屏幕可变參数
printf("error\n");
exit(1);
}
//打印屏幕可变參数
printf("%dx%d,%dbpp\n",vinfo.xres,vinfo.yres,vinfo.bits_per_pixel);
screensize=vinfo.xres*vinfo.yres* vinfo.bits_per_pixel/2; //缓冲区字节大小
fbp=(char *)mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd,0);//映射
if((int)fbp==-1){
printf("error\n");
exit(4);
}
memset(fbp,0,screensize); //清屏
char hz[16][2]={
0x08, 0x00, 0x08, 0x00, 0x08, 0x04, 0x7E, 0x84, 0x08, 0x48, 0x08, 0x28, 0xFF, 0x10, 0x08, 0x10,
0x28, 0x28, 0x2F, 0x28, 0x28, 0x44, 0x28, 0x84, 0x58, 0x00, 0x48, 0x00, 0x87, 0xFE, 0x00, 0x00,
}; //16*16字模库中提取的“赵”字相应的字符数组
int i,j,k;
for(j=0;j<16;j++){
for(i=0;i<2;i++){
for(k=0;k<8;k++){
if(hz[j][i]&(0x80>>k))
*((unsigned short *)(fbp + j*vinfo.xres*2 + i*16 + k*2))=0xf100;
}
}
}
munmap(fbp,screensize);
close(fbfd);
return 0;
}
ps:0xf100即相应16位:1111 1000 0000 0000,查看16位色时显示缓冲区与显示点的相应关系表,能够得出此像素点相应红色。
參考资料:《Linux设备驱动开发具体解释》
2014年6月23日星期一22时54分