1 LCD显示原理
LCD驱动器:LCD驱动器一般与LCD面板集成在一起,面板需要一定的模拟电信号来控制液晶分子,LCD驱动器芯片负责给面板提供控制液晶分子的模拟电信号,驱动器的控制信号(数字信号)来自于LCD控制器的提供的接口。
LCD控制器:LCD控制器集成在SoC内部,它负责通过数字接口向外部的LCD驱动器提供要显示的像素数字信号。它必须按照一定的时序和LCD驱动器通信,LCD控制器受SoC控制,SoC会从内存中拿出像素数据给LCD控制器并最终传给LCD驱动器。
显存:SoC在内存中选一段内存,用来存放颜色数据,然后通过配置将LCD控制器和这一段内存连接起来,构成一个映射关系,一旦这个关系建立以后,LCD控制器就会自动从显存中读取像素数据传给LCD驱动器,LCD驱动器会自动的控制每个像素点的液晶分子,以形成最终的图像,建立这个映射以后就不需要SoC在来参与任何行为了。
总结一下:SoC控制LCD液晶显示的过程分为两个部分:
(1) SoC的LCD控制器引出一定的引脚与LCD驱动器连接,按照标准设置一定的时序;
(2) 把LCD要显示的像素信息放入内存中,在通过设置LCD控制器中的寄存器,与LCD控制器建立映射;之后过程就是LCD控制器芯片与驱动器芯片自动完成的事情了,整个LCD图像的显示过程就是这样。
1.1调色板介绍
假设某块LCD屏幕的每个像素点所需要的位数为16位(两个字节),此时如果显存让每个像素的位数正好为16位(两个字节),那么正好能够和LCD屏幕硬件要求一致;但如果为了节省内存,显存中使用把8位表示一个像素点,即不能够和LCD屏幕硬件相一致。直接使用会导致错误产生,因此得使用调色板。
调色板可以理解为一块内存,存储颜色,它会根据显存中像素为索引,找到对应的颜色,然后通过LCD控制器发送给屏幕。
比如,对应AT043TN24的4.3寸显示屏:
ARM9核的S3C2440芯片可通过内置的LCD控制器来实现对LCD显示的控制。以TFT LCD为例,S3C2440芯片的LCD控制器可以对TFT LCD提供1位、2位、4位、8位调色板彩色显示和16位、24位真彩色显示,并支持多种不同的屏幕尺寸。
S3C2440的调色板其实是256个16位的存储单元,每个单元中存储有16位的颜色值。根据16位颜色数据中,RGB分量所占位数的不同, 调色板还可以采取5:6:5(R:G:B)和5:5:5:1(R:G:B:1)两种格式。当采用5:6:5(R:G:B)格式时,它的调色板如表1所示。
表1中,第一列为颜色索引,中间三列是R,G,B三个颜色分量对应的数据位,分别是5位、6位和5位,最后一列是对应颜色条目的物理地址。当采用5:5:5:1(R:G:B:1)格式时,R,G,B三个颜色分量的数据位长度都是5位,最低位为1。
2LCD驱动编程框架
 ;由于我们需要使用内核系统的GUI(图形界面接口),因此使用LCD设备驱动程序的frambuffer接口。
frambuffer设备层是对图像设备的一种抽象,它代表了视频硬件的帧缓存,使得应用程序通过定义好的接口就可以访问硬件。所以应用程序不需要考虑底层的(寄存器级)的操作。应用程序对设备文件的访问一般在/dev目录,如 /dev/fb*。
基本编程框架(与输入子系统基本框架类似):
1、分配一个fb_info结构体:framebuff_alloc();
2、设置fb_info;
3、设置硬件相关操作
4、注册
5、注销
2.1需要使用的结构体
fb_info结构体
struct fb_info {
... ...
struct fb_var_screeninfo var; //可变的参数
struct fb_fix_screeninfo fix; //固定的参数
... ...
struct fb_ops *fbops; //操作函数
... ...
char __iomem *screen_base; //显存虚拟起始地址
unsigned long screen_size; //显存虚拟地址长度
void *pseudo_palette;
//假的16色调色板,里面存放了16色的数据,可以通过8bpp数据来找到调色板里面的16色颜色索引值,模拟出16色颜色来,节省内存,不需要的话就指向一个不用的数组即可
... ...
};
需要使用到的操作函数
static struct fb_ops s3c_lcdfb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = my_lcdfb_setcolreg,//设置调色板fb_info-> pseudo_palette,自己构造该函数
.fb_fillrect = cfb_fillrect, //填充矩形,用/drivers/video/ cfbfillrect.c里的函数即可
.fb_copyarea = cfb_copyarea, //复制数据, 用/drivers/video/cfbcopyarea.c里的函数即可
.fb_imageblit = cfb_imageblit, //绘画图形, 用/drivers/video/imageblit.c里的函数即可
};
固定参数
struct fb_fix_screeninfo {
char id[16]; //id名字
unsigned long smem_start; //framebuffer物理起始地址
__u32 smem_len; //framebuffer长度,字节为单位
__u32 type; //lcd类型,默认值0即可
__u32 type_aux; //附加类型,为0
__u32 visual; //画面设置,常用参数如下
// FB_VISUAL_MONO01 0 单色,0:白色,1:黑色
// FB_VISUAL_MONO10 1 单色,1:白色,0:黑色
// FB_VISUAL_TRUECOLOR 2 真彩(TFT:真彩)
// FB_VISUAL_PSEUDOCOLOR 3 伪彩
// FB_VISUAL_DIRECTCOLOR 4 直彩
__u16 xpanstep; /*如果没有硬件panning就赋值为0 */
__u16 ypanstep; /*如果没有硬件panning就赋值为0 */
__u16 ywrapstep; /*如果没有硬件ywrap就赋值为0 */
__u32 line_length; /*一行的字节数 ,例:(RGB565)240*320,那么这里就等于240*16/8 */
/*以下成员都可以不需要*/
unsigned long mmio_start; /*内存映射IO的起始地址,用于应用层直接访问寄存器,可以不需要*/
__u32 mmio_len; /* 内存映射IO的长度,可以不需要*/
__u32 accel;
__u16 reserved[3];
};
可变参数
structfb_var_screeninfo{
__u32xres; /*可见屏幕一行有多少个像素点*/
__u32 yres; /*可见屏幕一列有多少个像素点*/
__u32 xres_virtual; /*虚拟屏幕一行有多少个像素点 */
__u32 yres_virtual; /*虚拟屏幕一列有多少个像素点*/
__u32 xoffset; /*虚拟到可见屏幕之间的行偏移,若可见和虚拟的分辨率一样,就直接设为0*/
__u32 yoffset; /*虚拟到可见屏幕之间的列偏移*/
__u32 bits_per_pixel; /*每个像素的位数即BPP,比如:RGB565则填入16*/
__u32 grayscale;