Linux LCD驅動架構學習(一)

Linux LCD驅動架構學習(一)

LCD 硬件原理 

利用液晶制成的显示器称为 LCD,依据驱动方式可分为静态驱动、简单矩阵驱动以及主动矩阵驱动 3 种。其中,简单矩阵型又可再细分扭转向列型(TN)和超扭
转式向列型(STN)两种,而主动矩阵型则以薄膜式晶体管型(TFT)为主流。表18.1 列出了 TN、STN 和 TFT 显示器的区别。

Linux LCD驅動架構學習(一)_第1张图片

TN 型液晶显示技术是 LCD 中最基本的,其他种类的 LCD 都以 TN 型为基础改进而得。TN 型 LCD 显示质量很差,色彩单一,对比度低,反映速度很慢,故主要用于简单的数字符与文字的显示,如电子表及电子计算器等。 

STN LCD 的显示原理与 TN 类似,区别在于 TN 型的液晶分子将入射光旋转 90°,而 STN 则可将入射光旋转 180°~270°。STN 改善了 TN 视角狭小的缺点,并提高了对比度,显示品质较 TN 高。 STN 搭配彩色滤光片,将单色显示矩阵的任一像素分成 3 个子像素,分别透过彩色滤光片显示红、绿、蓝三原色,再经由三原色按比例调和,显示出逼近全彩模式的色彩。STN 显示的画面色彩对比度仍较小,反应速度也较慢,可以作为一般的操作显示接口。 随后出现的 DSTN 通过双扫描方式来显示,显示效果相对 STN 而言有了较大幅度的提高。DSTN 的反应速度可达到 100ms,但是在电场反复改变电压的过程中,每一像素的恢复过程较慢。因此,当在屏幕画面快速变化时,会产生“拖尾”现象。 

TN 与 STN 型液晶显示器都是使用场电压驱动方式,如果显示尺寸加大,中心部位对电极变化的反应时间就会拉长,显示器的速度跟不上。为了解决这个问题,主动式矩阵驱动被提出,主动式 TFT 型的液晶显示器的结构较为复杂,它包括背光管、导光板、偏光板、滤光板、玻璃基板、配向膜、液晶材料和薄膜式晶体管等。 

在 TFT 型 LCD 中,晶体管矩阵依显示信号开启或关闭液晶分子的电压,使液晶分子轴转向而成“亮”或“暗”的对比,避免了显示器对电场效应的依靠。因此,TFT LCD 的显示质量较 TN/STN 更佳,画面显示对比度可达 150:1以上,反应速度逼近 30ms甚至更快,适用于 PDA、笔记本电脑、数码相机、MP4 等。 

一块 LCD 屏显示图像不但需要 LCD 驱动器,还需要有相应的 LCD 控制器。通常 LCD 驱动器会以 COF/COG 的形式与 LCD 玻璃基板制作在一起,而 LCD 控制器则由外部电路来实现。许多 MCU 内部直接集成了 LCD 控制器,通过 LCD控制器可以方便地控制 STN 和 TFT 屏。 

TFT 屏是目前嵌入式系统应用的主流,图 18.1 给出了 TFT 屏的典型时序。时序图中的 VCLK、HSYNC 和 VSYNC 分别为像素时钟信号(用于锁存图像数据的像素
时钟)、行同步信号和帧同步信号,VDEN 为数据有效标志信号,VD 为图像的数据信号。

Linux LCD驅動架構學習(一)_第2张图片

作为帧同步信号的 VSYNC,每发出一个脉冲,都意味着新的一屏图像数据开始发送。而作为行同步信号的 HSYNC,每发出一个脉冲都表明新的一行图像资料开始发送。在帧同步以及行同步的头尾都必须留有回扫时间。这样的时序安排起源于 CRT显示器电子枪偏转所需要的时间,但后来成为实际上的工业标准,因此 TFT 屏也包含了回扫时间。 

下图给出了 LCD 控制器中应该设置的 TFT 屏的参数,其中的上边界和下边界即为帧切换的回扫时间,左边界和右边界即为行切换的回扫时间,水平同步和垂直同步分别是行和帧同步本身需要的时间。xres 和 yres 则分别是屏幕的水平和垂直分辨率,常见的嵌入式设备的 LCD 分辨率主要为 320*240、640*480 等。 

Linux LCD驅動架構學習(一)_第3张图片

帧缓冲 

帧缓冲的概念 

帧缓冲(framebuffer)是 Linux 系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。用户不必关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域写入颜色值,对应的颜色会自动在屏幕上显示。

帧缓冲设备为标准字符设备,主设备号为 29,对应于/dev/fb%d 设备文件。帧缓冲驱动的应用非常广泛,在 Linux 的桌面系统中,Xwindow 服务器就是利用帧缓冲进行窗口的绘制。嵌入式系统中的 Qt/Embedded 等图形用户界面环境也基于帧缓冲而设计。另外,通过帧缓冲可支持汉字点阵的显示,因此帧缓冲也成为 Linux 汉化的可行方案。 

显示缓冲区与显示点 

在帧缓冲设备中,对屏幕显示点的操作通过读写显示缓冲区来完成,在不同的色彩模式下,显示缓冲区和屏幕上的显示点有不同的对应关系,表 18.2~表 18.4 分别给出了 16 级灰度、8 位色和 16 位情况下显示缓冲区与显示点的对应关系。

Linux LCD驅動架構學習(一)_第4张图片

Linux LCD驅動架構學習(一)_第5张图片

Linux LCD驅動架構學習(一)_第6张图片

Linux 帧缓冲相关数据结构与函数 

1.fb_info 结构体 

帧缓冲设备最关键的一个数据结构体是 fb_info 结构体(为了便于记忆,我们把它简称为“FBI”),FBI 中包括了关于帧缓冲设备属性和操作的完整描述,这个结构体的定义如代码清单所示。

1  struct fb_info 
2  { 
3     int node; 
4     int flags; 
5     struct fb_var_screeninfo var; /*可变参数 */ 
6     struct fb_fix_screeninfo fix; /*固定参数 */ 
7     struct fb_monspecs monspecs; /*显示器标准 */ 
8     struct work_struct queue; /* 帧缓冲事件队列 */ 
9     struct fb_pixmap pixmap; /* 图像硬件 mapper */ 
10    struct fb_pixmap sprite; /* 光标硬件 mapper */ 
11    struct fb_cmap cmap; /* 目前的颜色表*/ 
12    struct list_head modelist;  
13    struct fb_videomode *mode; /* 目前的 video 模式 */ 
14 
15    #ifdef CONFIG_FB_BACKLIGHT 
16       struct mutex bl_mutex; 
17       /*  对应的背光设备  */ 
18       struct backlight_device *bl_dev; 
19       /* 背光调整 */ 
20       u8 bl_curve[FB_BACKLIGHT_LEVELS]; 
21     #endif 
22  
23     struct fb_ops *fbops; /* fb_ops,帧缓冲操作 */ 
24     struct device *device; 
25     struct class_device *class_device; / 
26     int class_flag; /* 私有 sysfs 标志 */ 
27     #ifdef CONFIG_FB_TILEBLITTING 
28         struct fb_tile_ops *tileops; /* 图块 Blitting */ 
29     #endif 
30     char _ _iomem *screen_base; /* 虚拟基地址 */ 
31     unsigned long screen_size; /* ioremapped 的虚拟内存大小 */ 
32     void *pseudo_palette; /* 伪 16 色颜色表 */ 
33     #define FBINFO_STATE_RUNNING 0 
34     #define FBINFO_STATE_SUSPENDED         1 
35     u32 state; /* 硬件状态,如挂起 */ 
36     void *fbcon_par; 
37     void *par; 
38 };
FBI 中记录了帧缓冲设备的全部信息,包括设备的设置参数、状态以及操作函数指针。每一个帧缓冲设备都必须对应一个 FBI。 

2.fb_ops 结构体 

FBI 的成员变量 fbops 为指向底层操作的函数的指针,这些函数是需要驱动程序开发人员编写的,其定义如代码清单所示。

1  struct fb_ops 
2  { 
3      struct module *owner; 
4       /* 打开/释放 */ 
5      int(*fb_open)(struct fb_info *info, int user); 
6      int(*fb_release)(struct fb_info *info, int user); 
7   
8      /* 对于非线性布局的/常规内存映射无法工作的帧缓冲设备需要 */ 
9      ssize_t(*fb_read)(struct file *file, char _ _user *buf, size_t count, 
10        loff_t*ppos); 
11     ssize_t(*fb_write)(struct file *file, const char _ _user *buf, size_t count, 
12        loff_t *ppos); 
13  
14     /* 检测可变参数,并调整到支持的值*/ 
15          int(*fb_check_var)(struct  fb_var_screeninfo  *var,  struct fb_info *info); 
16  
17    /* 根据 info->var 设置 video 模式 */
18    int(*fb_set_par)(struct fb_info *info); 
19  
20    /* 设置 color 寄存器 */ 
21    int(*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, unsigned 
22        blue, unsigned transp, struct fb_info *info); 
23  
24     /* 批量设置 color 寄存器,设置颜色表 */ 
25     int(*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info); 
26  
27     /*显示空白 */ 
28     int(*fb_blank)(int blank, struct fb_info *info); 
29  
30     /* pan 显示 */ 
31        int(*fb_pan_display)(struct  fb_var_screeninfo  *var,  struct fb_info *info); 
32  
33     /* 矩形填充 */ 
34          void(*fb_fillrect)(struct  fb_info  *info,  const  struct fb_fillrect *rect); 
35     /* 数据复制 */ 
36          void(*fb_copyarea)(struct  fb_info  *info,  const  struct fb_copyarea *region); 
37     /* 图形填充 */ 
38     void(*fb_imageblit)(struct fb_info *info, const struct fb_image *image); 
39  
40     /* 绘制光标 */ 
41     int(*fb_cursor)(struct fb_info *info, struct fb_cursor *cursor); 
42  
43     /* 旋转显示 */ 
44     void(*fb_rotate)(struct fb_info *info, int angle); 
45  
46     /* 等待 blit 空闲 (可选) */ 
47     int(*fb_sync)(struct fb_info *info); 
48  
49     /* fb 特定的 ioctl (可选) */ 
50   int(*fb_ioctl)(struct fb_info *info, unsigned int cmd, unsigned long arg); 
51  
52   /* 处理 32 位的 compat ioctl (可选) */ 
53      int(*fb_compat_ioctl)(struct  fb_info  *info,  unsigned  cmd, unsigned long arg); 
54  
55   /* fb 特定的 mmap */ 
56   int(*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma); 
57  
58   /* 保存目前的硬件状态 */ 
59   void(*fb_save_state)(struct fb_info *info); 
60  
61   /* 恢复被保存的硬件状态 */ 
62   void(*fb_restore_state)(struct fb_info *info); 
63 }; 

fb_ops 的 fb_check_var()成员函数用于检查可以修改的屏幕参数并调整到合适的值,而 fb_set_par()则使得用户设置的屏幕参数在硬件上有效。

3.fb_var_screeninfo 和 fb_fix_screeninfo 结构体 

FBI 的 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 结构体的定义如代码清单所示。

1  struct fb_var_screeninfo 
2  { 
3     /* 可见解析度   */ 
4     _ _u32 xres; 
5     _ _u32 yres; 
6     /* 虚拟解析度    */ 
7     _ _u32 xres_virtual; 
8     _ _u32 yres_virtual; 
9     /* 虚拟到可见之间的偏移 */ 
10    _ _u32 xoffset; 
11    _ _u32 yoffset; 
12  
13    _ _u32 bits_per_pixel; /* 每像素位数,BPP */ 
14    _ _u32 grayscale; /非 0 时指灰度 */ 
15  
16    /* fb 缓存的 R\G\B 位域 */ 
17    struct fb_bitfield red; 
18    struct fb_bitfield green; 
19    struct fb_bitfield blue; 
20    struct fb_bitfield transp; /* 透明度 */ 
21  
22    _ _u32 nonstd; /* != 0 非标准像素格式 */ 
23  
24    _ _u32 activate; 
25  
26    _ _u32 height; /*高度 */ 
27    _ _u32 width; /*宽度 */ 
28  
29    _ _u32 accel_flags; /* 看 fb_info.flags */ 
30  
31    /* 定时: 除了 pixclock 本身外,其他的都以像素时钟为单位 */ 
32    _ _u32 pixclock; /* 像素时钟(皮秒) */ 
33    _ _u32 left_margin; /* 行切换:从同步到绘图之间的延迟    */ 
34    _ _u32 right_margin; /* 行切换:从绘图到同步之间的延迟   */ 
35    _ _u32 upper_margin; /* 帧切换:从同步到绘图之间的延迟  */ 
36    _ _u32 lower_margin; /* 帧切换:从绘图到同步之间的延迟  */ 
37    _ _u32 hsync_len; /* 水平同步的长度     */ 
38    _ _u32 vsync_len; /* 垂直同步的长度     */ 
39    _ _u32 sync; 
40    _ _u32 vmode; 
41    _ _u32 rotate; /* 顺时钟旋转的角度 */ 
42    _ _u32 reserved[5]; /* 保留 */ 
43 }; 
1  struct fb_fix_screeninfo 
2  { 
3      char id[16]; /* 字符串形式的标识符 */ 
4      unsigned long smem_start; /* fb 缓存的开始位置 */ 
5      _ _u32 smem_len; /* fb 缓存的长度 */ 
6      _ _u32 type; /* FB_TYPE_*        */ 
7      _ _u32 type_aux; /* 分界 */ 
8      _ _u32 visual; /* FB_VISUAL_* */ 
9      _ _u16 xpanstep; /* 如果没有硬件 panning ,赋 0 */ 
10     _ _u16 ypanstep;  
11     _ _u16 ywrapstep;/ 
12     _ _u32 line_length; /* 1 行的字节数 */ 
13     unsigned long mmio_start; /* 内存映射 I/O 的开始位置 */ 
14     _ _u32 mmio_len; /* 内存映射 I/O 的长度  */ 
15     _ _u32 accel; 
16     _ _u16 reserved[3]; /* 保留*/ 
17 }; 

4.fb_bitfield 结构体 

fb_var_screeninfo 代码清单第 17、18、19 行分别记录 R、G、B 的位域,fb_bitfield 结构体描述每一像素显示缓冲区的组织方式,包含位域偏移、位域长度和 MSB 指示,如代码清单所示。

1  struct fb_bitfield 
2  { 
3      _ _u32 offset; /* 位域偏移    */ 
4      _ _u32 length; /* 位域长度    */
5      _ _u32 msb_right; /* MSB */ 
6  }; 
5.fb_cmap 结构体 

fb_cmap 结构体记录设备无关的颜色表信息,用户空间可以通过 ioctl()的FBIOGETCMAP 和 FBIOPUTCMAP 命令读取或设定颜色表。

1  struct fb_cmap 
2  { 
3      _ _u32 start; /* 第 1 个元素入口    */ 
4      _ _u32 len; /* 元素数量 */ 
5      /* R、G、B、透明度*/ 
6      _ _u16 *red; 
7      _ _u16 *green; 
8      _ _u16 *blue; 
9      _ _u16 *transp; 
10 };

下面代码清单所示为用户空间获取颜色表的例程,若 BPP 为 8 位,则颜色表长度为 256;若 BPP 为 4 位,则颜色表长度为 16;否则,颜色表长度为 0,这是因为,对于 BPP 大于等于 16 的情况,使用颜色表是不划算的。

1  // 读入颜色表 
2  if ((vinfo.bits_per_pixel == 8) || (vinfo.bits_per_pixel == 4)) 
3  { 
4       screencols = (vinfo.bits_per_pixel == 8) ? 256 : 16;//颜色表大小 
5       int loopc; 
6       startcmap = new fb_cmap; 
7       startcmap->start = 0; 
8       startcmap->len = screencols; 
9      //分配颜色表的内存 
10     startcmap->red = (unsigned short int*)malloc(sizeof(unsigned short int) 
11         *screencols); 
12     startcmap->green = (unsigned short int*)malloc(sizeof(unsigned short int) 
13         *screencols); 
14     startcmap->blue = (unsigned short int*)malloc(sizeof(unsigned short int) 
15         *screencols); 
16     startcmap->transp = (unsigned short int*)malloc(sizeof(unsigned short int) 
17         *screencols); 
18     //获取颜色表 
19     ioctl(fd, FBIOGETCMAP, startcmap); 
20     for (loopc = 0; loopc < screencols; loopc++) 
21     { 
22           screenclut[loopc]  =  qRgb(startcmap->red[loopc]  >>  8, startcmap 
23               ->green[loopc] >> 8, startcmap->blue[loopc] >> 8);
24   } 
25 } 
26 else 
27 { 
28      screencols = 0; 
29 } 
对于一个 256 色(BPP=8)的 800*600 分辨率的图像而言,若红、绿、蓝分别用一个字节描述,则需要 800*600*3=1440000Byte 的空间,而若使用颜色表,则只需要 800*600*1+256*3= 480768Byte 的空间。 

6.文件操作结构体 

作为一种字符设备,帧缓冲设备的文件操作结构体定义于/linux/drivers/vedio/fbmem.c 文件中,如代码清单所示。

1  static struct file_operations fb_fops = 
2  { 
3      .owner = THIS_MODULE, 
4      .read = fb_read, //读函数 
5      .write = fb_write, //写函数 
6      .ioctl = fb_ioctl, //I/O 控制函数 
7      #ifdef CONFIG_COMPAT 
8         .compat_ioctl = fb_compat_ioctl, 
9      #endif 
10     .mmap = fb_mmap, //内存映射函数 
11     .open = fb_open,  //打开函数 
12     .release = fb_release, //释放函数 
13     #ifdef HAVE_ARCH_FB_UNMAPPED_AREA 
14        .get_unmapped_area = get_fb_unmapped_area, 
15     #endif 
16 }; 
帧缓冲设备驱动的文件操作接口函数已经在 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。

你可能感兴趣的:(Linux,LCD,driver)