LCD硬件原理
首先结合LCD接口来简要了解LCD驱动原理(笔者使用的开发板是TQ2440,所用的LCD是天嵌4..3寸屏,以此为例),如下:
首先得知道LCD是由N多个像素点组成,一帧图像在视觉上看到是一体的,但实际上每个像素点的显示的是有时序的。可以想象一下,有好比一个喷光灯,它打到哪个像素点,哪个像素点就被“照亮”。如何让一行像素点一个接一个“点亮”呢?于是有了HSYNC(水平同步信号),对应图中的32号管脚;总不能只“点亮”一行像素点吧,得一行接一行才成啊,如何让喷光灯沿着行方向移动呢?于是有了VSYNC(垂直同步信号),对于图中33号管脚;然后就是喷光灯“喷”什么颜色呢?于是有了数据端口VD0-VD23,对应图中5-28号管脚;
也就是说,HSYNC控制喷光灯水平移动,VSYNC控制喷光灯垂直移动,VD0-VD23控制喷光灯喷光颜色。除此之外,还有VCLK作为像素时钟信号,对应图中的31号管脚;数据使能信号VDEN,对应图中的34号管脚;电源开关信号PWREN,对应图中的31号管脚...
ps:还不清楚1、2号管脚的功能...
关于这些值的意义,结合LCD数据手册,比较容易理解,这里略过,万变不离其宗~
差不多搞清楚了,但是数据显示这个问题比较严重,总不能对每一个像素点的赋值都手动输入吧,那得弄一个很大的for循环。一般来说,会弄一个数据缓冲区,要显示啥东西,往这个缓冲区填充数据,然后进行一系列的处理。帧缓冲
帧缓冲的概念
帧缓冲(framebuffer)是Linux系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。用户不必关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域写入颜色值,对应的颜色会自动在屏幕上显示。
帧缓冲设备为标准字符设备,主设备号为29,对应于/dev/fb%d设备文件。帧缓冲驱动的应用非常广泛,在Linux的桌面系统中,Xwindow服务器就是利用帧缓冲进行窗口的绘制。嵌入式系统中的Qt/Embedded等图形用户界面环境也基于帧缓冲而设计。另外,通过帧缓冲可支持汉字点阵的显示,因此帧缓冲也成为Linux汉化的可行方案。
Linux帧缓冲相关的数据结构与函数
1. 帧缓冲设备最关键的一个数据结构体是fb_info 结构体。定义如下:
struct fb_info
{
int node;
int flags;
struct fb_var_screeninfo var;/*可变参数 */
struct fb_fix_screeninfo fix;/*固定参数 */
struct fb_monspecs monspecs;/*显示器标准 */
struct work_struct queue;/* 帧缓冲事件队列 */
struct fb_pixmap pixmap;/* 图像硬件mapper */
struct fb_pixmap sprite;/* 光标硬件mapper */
struct fb_cmap cmap;/* 目前的颜色表*/
struct list_head modelist;
struct fb_videomode *mode;/* 目前的video模式 */
#ifdef CONFIG_FB_BACKLIGHT
struct mutex bl_mutex;
/* 对应的背光设备 */
struct backlight_device *bl_dev;
/* 背光调整 */
u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
struct fb_ops *fbops;/* fb_ops,帧缓冲操作 */
struct device *device;
struct class_device *class_device;/
int class_flag;/* 私有sysfs标志 */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops;/* 图块Blitting */
#endif
char __iomem *screen_base;/* 虚拟基地址 */
unsigned long screen_size;/* ioremapped的虚拟内存大小 */
void *pseudo_palette;/* 伪16色颜色表 */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state;/* 硬件状态,如挂起 */
void *fbcon_par;
void *par;
};
fb_info结构体记录了帧缓冲设备的全部信息,包括设备的设置参数、状态以及操作函数指针。每一个帧缓冲设备都必须对应一个fb_info结构体~
2. fb_ops结构体
fb_info结构体成员变量fbops为指向底层操作的函数的指针,这些函数是需要驱动程序开发人员编写的,定义如下:
struct fb_ops
{
struct module *owner;
/* 打开/释放 */
int(*fb_open)(struct fb_info *info, int user);
int(*fb_release)(struct fb_info *info, int user);
/* 对于非线性布局的/常规内存映射无法工作的帧缓冲设备需要 */
ssize_t(*fb_read)(struct file *file, char _ _user *buf, size_t count, loff_t*ppos);
ssize_t(*fb_write)(struct file *file, const char _ _user *buf, size_t count, loff_t *ppos);
/* 检测可变参数,并调整到支持的值*/
int(*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
/* 根据info->var设置video模式 */
int(*fb_set_par)(struct fb_info *info);
/* 设置color寄存器 */
int(*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info);
/* 批量设置color寄存器,设置颜色表 */
int(*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
/* 显示空白 */
int(*fb_blank)(int blank, struct fb_info *info);
/* pan显示 */
int(*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
/* 矩形填充 */
void(*fb_fillrect)(struct fb_info *info, const struct fb_fillrect *rect);
/* 数据复制 */
void(*fb_copyarea)(struct fb_info *info, const struct fb_copyarea *region);
/* 图形填充 */
void(*fb_imageblit)(struct fb_info *info, const struct fb_image *image);
/* 绘制光标 */
int(*fb_cursor)(struct fb_info *info, struct fb_cursor *cursor);
/* 旋转显示 */
void(*fb_rotate)(struct fb_info *info, int angle);
/* 等待blit空闲 (可选) */
int(*fb_sync)(struct fb_info *info);
/* fb特定的ioctl (可选) */
int(*fb_ioctl)(struct fb_info *info, unsigned int cmd, unsigned long arg);
/* 处理32位的compat ioctl (可选) */
int(*fb_compat_ioctl)(struct fb_info *info, unsigned cmd, unsigned long arg);
/* fb特定的mmap */
int(*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
/* 保存目前的硬件状态 */
void(*fb_save_state)(struct fb_info *info);
/* 恢复被保存的硬件状态 */
void(*fb_restore_state)(struct fb_info *info);
};
fb_ops的fb_check_var()成员函数用于检查可以修改的屏幕参数并调整到合适的值,而fb_set_par()则使得用户设置的屏幕参数在硬件上有效。
3. fb_var_screeninfo 和fb_fix_screeninfo 结构体fb_info的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结构体的定义分别如下:
struct fb_var_screeninfo
{
/* 可见解析度 */
__u32 xres;
__u32 yres;
/* 虚拟解析度 */
__u32 xres_virtual;
__u32 yres_virtual;
/* 虚拟到可见之间的偏移 */
__u32 xoffset;
__u32 yoffset;
__u32 bits_per_pixel;/* 每像素位数,BPP */
__u32 grayscale;/非0时指灰度 */
/* fb缓存的R\G\B位域 */
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp;/* 透明度 */
__u32 nonstd;/* != 0 非标准像素格式 */
__u32 activate;
__u32 height;/* 高度 */
__u32 width;/* 宽度 */
__u32 accel_flags;/* 看fb_info.flags */
/* 定时: 除了pixclock本身外,其他的都以像素时钟为单位 */
__u32 pixclock;/* 像素时钟(皮秒) */
__u32 left_margin;/* 行切换:从同步到绘图之间的延迟 */
__u32 right_margin;/* 行切换:从绘图到同步之间的延迟 */
__u32 upper_margin;/* 帧切换:从同步到绘图之间的延迟 */
__u32 lower_margin;/* 帧切换:从绘图到同步之间的延迟 */
__u32 hsync_len;/* 水平同步的长度 */
__u32 vsync_len;/* 垂直同步的长度 */
__u32 sync;
__u32 vmode;
__u32 rotate;/* 顺时钟旋转的角度 */
__u32 reserved[5];/* 保留 */
};
struct fb_fix_screeninfo
{
char id[16];/* 字符串形式的标识符 */
unsigned long smem_start;/* fb缓存的开始位置 */
__u32 smem_len;/* fb缓存的长度 */
__u32 type;/* FB_TYPE_* */
__u32 type_aux;/* 分界 */
__u32 visual;/* FB_VISUAL_* */
__u16 xpanstep;/* 如果没有硬件panning ,赋0 */
__u16 ypanstep;
__u16 ywrapstep;/
__u32 line_length;/* 1行的字节数 */
unsigned long mmio_start;/* 内存映射I/O的开始位置 */
__u32 mmio_len;/* 内存映射I/O的长度 */
__u32 accel;
__u16 reserved[3];/* 保留 */
};
fb_fix_screeninfo结构体中的成员变量visual记录屏幕使用的色彩模式,在Linux系统中,支持的色彩模式包括以下几种:
Monochrome(FB_VISUAL_MONO01、FB_VISUAL_MONO10),每个像素是黑或白。
Pseudo color ( FB_VISUAL_PSEUDOCOLOR、FB_VISUAL_STATIC_PSEUDOCOLOR),即伪彩色,采用索引颜色显示。
True color(FB_VISUAL_TRUECOLOR),真彩色,分成红、绿、蓝三基色。
Direct color(FB_VISUAL_DIRECTCOLOR),每个像素颜色也是有红、绿、蓝组成,不过每个颜色值是个索引,需要查表。
Grayscale displays,灰度显示,红、绿、蓝的值都一样。
4. fb_bitfield结构体
fb_var_screen结构体中的fb_bitfield结构的成员变量red、green、blue分别记录R、G、B的位域,fb_bitfield结构体描述每一像素显示缓冲区的组织方式,包含位域偏移、位域长度和MSB指示,如下:
struct fb_bitfield
{
__u32 offset; /* 位域偏移 */
__u32 length; /* 位域长度 */
__u32 msb_right; /* MSB */
};
5. fb_cmap结构体fb_cmap结构体记录设备无关的颜色表信息,用户空间可以通过ioctl()的FBIOGETCMAP 和FBIOPUTCMAP命令读取或设定颜色表。
struct fb_cmap
{
__u32 start; /* 第1个元素入口 */
__u32 len; /* 元素数量 */
/* R、G、B、透明度 */
__u16 *red;
__u16 *green;
__u16 *blue;
__u16 *transp;
};
6. 文件操作结构体作为一种字符设备,帧缓冲设备的文件操作结构体定义于/linux/drivers/vedio/fbmem.c 文件中,如下所示:
static struct file_operations fb_fops =
{
.owner = THIS_MODULE,
.read = fb_read, //读函数
.write = fb_write, //写函数
.ioctl = fb_ioctl, //I/O控制函数
#ifdef CONFIG_COMPAT
.compat_ioctl = fb_compat_ioctl,
#endif
.mmap = fb_mmap, //内存映射函数
.open = fb_open, //打开函数
.release = fb_release, //释放函数
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif
};
帧缓冲设备驱动的文件操作接口函数已经在fbmem.c 中被统一实现,一般不需要由驱动工程师再编写。7. 注册与注销帧缓冲设备
Linux内核提供了register_framebuffer()和unregister_framebuffer()函数分别注册和注销帧缓冲设备,这两个函数都接受FBI指针为参数,原型为:
int register_framebuffer(struct fb_info *fb_info);
int unregister_framebuffer(struct fb_info *fb_info);
对于register_framebuffer()函数而言,如果注册的帧缓冲设备数超过了FB_MAX(目前定义为32),则函数返回-ENXIO,注册成功则返回0。