framebuffer机制

 

s3c2440-lcd驱动与帧缓冲

注意:本文是主要参考《S3C2440LCD驱动详解》,《S3c2410_LCD驱动学习心得》,《嵌入式linux_Framebuffer驱动开发》部分直接搬过来。

一、帧缓冲机制

         在谈到lcd驱动时,先谈谈,帧缓冲机制,为什么呢?因为Linux系统是工作在保护模式下,所以用户态进程无法像DOS那要使用显卡BIOS里提供的中断调用来实现直接写屏蔽,Framebuffer是出现在linux 2.2及以后的一种驱动程序接口,它是一项重要技术,基本上都是用它来实现图形界面的。

下面是LCD驱动程序与应用程序以及帧缓冲机制的关系

应用程序要操作LCD,就操作设备节点(/dev/fb0由帧缓冲创建),fbmem.c是提供应用程序的操作接口,fbmem.c本身并不实现这些功能,这就需要下一层接口实现,就是XXXfb.c要实现的与lcd底层硬件相关的操作接口。具体可以参考s3c2410fb.c

帧缓冲技术是与LCD驱动混在一起从而形成帧缓冲LCD设备驱动程序,主要是由下面几个重要数据结构起关联。

 

1Struct fb_info

Struct fb_info这结构记录了帧缓冲设备的全部信息,包括设备的设置参数、状态、以及对底层硬件操作的函数指针。下面具体分析一下。

 其中比较重要的就是struct fb_var_screeninfo var;              struct fb_fix_screeninfo fix;

struct fb_ops *fbops;

下面各自分析一下

 

2struct fb_var_screeninfo

 

struct fb_var_screeninfo 主要是记录用户可以修改的控制器可变参数

 

3struct fb_fix_screeninfo

 

struct fb_fix_screeninfo fix;就是固定的控制器配置,比如屏幕缓冲区的物理地址和长度,定义如下:

 

4struct fb_ops

 

struct fb_ops,帧缓冲操作,关联硬件跟应用程序。

5、帧缓冲设备以及设备资源

LCD帧缓冲设备在Linux里是作为一个平台设备,在内核arch/arm/plat-s3c24xx/devs.c中定义LCD相关平台设备如下:

这里导出s3c_device_lcd是为了在arch/asm/mach-s3c2410/mach-smdk2410.c里的smdk2410_devices[](或者其它smdk2440_devices[])中添加到平台设备列表中。

下面准备分析具体实例,但分析前还要了解LCD的特性以及读写时序。

实在不如别人做得漂亮,做得详细,大家还是去看原文吧,我这里就不接了。

二、LCD的硬件知识

1. LCD工作的硬件需求:

   要使一块 LCD正常的显示文字或图像,不仅需要 LCD驱动器,而且还需要

相应的 LCD控制器。在通常情况下,生产厂商把LCD驱动器会以 COF/COG

的形式与 LCD玻璃基板制作在一起,而 LCD控制器则是由外部的电路来实现,

现在很多的 MCU内部都集成了 LCD控制器, S3C2410/2440 等。 通过LCD

控制器就可以产生LCD驱动器所需要的控制信号来控制STN/TFT 屏了。

 

2. S3C2440内部 LCD 控制器结构图:

 

我们根据数据手册来描述一下这个集成在 S3C2440 内部的 LCD控制器:

aLCD控制器由REGBANKLCDCDMATIMEGENVIDPRCS寄存器组

成;

bREGBANK 17个可编程的寄存器组和一块 256*16 的调色板内存组成,

它们用来配置 LCD控制器的;

cLCDCDMA是一个专用的 DMA,它能自动地把在侦内存中的视频数据传送

LCD驱动器,通过使用这个 DMA通道,视频数据在不需要 CPU的干预的情

况下显示在 LCD屏上;

dVIDPRCS接收来自 LCDCDMA的数据,将数据转换为合适的数据格式,比

如说 4/8 位单扫,4 位双扫显示模式,然后通过数据端口 VD[23:0]传送视频数

据到 LCD驱动器;

……

在这里我加上《S3c2410 LCD驱动学习心得》因为这里面分析如何确定驱动里的lcd配置参数写得很明白

S3C2410实验箱上的LCD是一款3.5TFT真彩LCD屏,分辩率为240*320,下图为该屏的时序要求。

1.3
通过对比图1.2和图1.3,我们不难看出:
VSPW+1=2 -> VSPW=1

VBPD+1=2 -> VBPD=1
LINVAL+1=320-> LINVAL=319
VFPD+1=3 -> VFPD=2
HSPW+1=4 -> HSPW=3
HBPD+1=7 -> HBPW=6
HOZVAL+1=240-> HOZVAL=239
HFPD+1=31 -> HFPD=30
以上各参数,除了LINVALHOZVAL直接和屏的分辩率有关,其它的参数在实际操作过程中应以上面的为参考,不应偏差太多。

1.3  LCD
控制器主要寄存器功能详解

1.4
LINECNT
:当前行扫描计数器值,标明当前扫描到了多少行。
CLKVAL
:决定VCLK的分频比。LCD控制器输出的VCLK是直接由系统总线(AHB)的工作频率HCLK直接分频得到的。做为240*320TFT屏,应保证得出的VCLK5~10MHz之间。
MMODE
VM信号的触发模式(仅对STN屏有效,对TFT屏无意义)。
PNRMODE
:选择当前的显示模式,对于TFT屏而言,应选择[11],即TFT LCD panel
BPPMODE
:选择色彩模式,对于真彩显示而言,选择16bpp64K色)即可满足要求。
ENVID
:使能LCD信号输出。

1.5
VBPD
LINEVAL VFPD VSPW 的各项含义已经在前面的时序图中得到体现。

1.6
HBPD
HOZVAL HFPD 的各项含义已经在前面的时序图中得到体现。

1.7
HSPW
的含义已经在前面的时序图中得到体现。
MVAL
只对 STN屏有效,对TFT屏无意义。
HSPW
的含义已经在前面的时序图中得到体现,这里不再赘述。
MVAL
只对 STN屏有效,对TFT屏无意义。 




1.8
VSTATUS
:当前VSYNC信号扫描状态,指明当前VSYNC同步信号处于何种扫描阶段。
HSTATUS
:当前HSYNC信号扫描状态,指明当前HSYNC同步信号处于何种扫描阶段。
BPP24BL
:设定24bpp显示模式时,视频资料在显示缓冲区中的排列顺序(即低位有效还是高位有效)。对于16bpp64K色显示模式,该设置位无意义。
FRM565
:对于16bpp显示模式,有2中形式,一种是RGB5:5:5:1,另一种是5:6:5。后一种模式最为常用,它的含义是表示64K种色彩的16bit RGB资料中,红色(R)占了5bit,绿色(G)占了6bit,蓝色(B)占了5bit
INVVCLK
INVLINE INVFRAME INVVD :通过前面的时序图,我们知道,CPULCD控制器输出的时序默认是正脉冲,而LCD需要VSYNCVFRAME)、VLINEHSYNC)均为负脉冲,因此 INVLINE INVFRAME 必须设为“1 ”,即选择反相输出。
INVVDEN
INVPWREN INVLEND 的功能同前面的类似。
PWREN
LCD电源使能控制。在CPU LCD控制器的输出信号中,有一个电源使能管脚LCD_PWREN,用来做为LCD屏电源的开关信号。
ENLEND
对普通的TFT屏无效,可以不考虑。
BSWP
HWSWP 为字节(Byte)或半字(Half-Word)交换使能。由于不同的GUIFrameBuffer(显示缓冲区)的管理不同,必要时需要通过调整 BSWP HWSWP 来适应GUI

 

分析之后,我们能否把这LCD弄成模块?如果可以,又怎么弄?(这跟平台设备驱动有很大关系)

1、修改
linux-2.6.24/arch/arm/mach-s3c2410/mach-smdk2410.c

先加头文件
#include <asm/arch/fb.h>

再加入如下

然后找到
static void __init smdk2410_init(void)
函数
加入
s3c24xx_fb_set_platdata(&qt2410_fb_info);

OK,
文件修改完毕
make menuconfig
Device Drivers --->
Graphics support --->
Display device support --->
勾上     S3C2410 LCD framebuffer support
想看开机的小企鹅就勾上
           Bootup logo
想换一个启动图案的话,如下

1)进入linuxkde图形界面,使用The GIMP 图像编辑器打开你想要的图像文件,依次选择图像->模式->索引颜色,将颜色改为224色;至于图片大小,不要大于你的显示器分辨率就好(我只试过8080320240的大小),最后将文件保存为ppm格式(ASCii码),文件名为:logo_linux_clut224.ppm
2)将logo_linux_clut224.ppm拷贝到/drivers/video/logo文件夹下,替换原有的文件(记得备份啊,以防万一)。
3)重新编译内核,tftp到开发板启动。

直接分析源码

Drivers/video/s3c2410fb.c

前面就是注册LCD平台驱动层,看到结构体static struct platform_driver s3c2410fb_driver,

里面就是这个平台设备的函数指针,通过调用platform_driver_register,如果系统里有LCD设备已经注册了(如果直接移植,就是在mach-smdk2410.c里加的内容注册的),就会调用s3c24xxfb_probe

分析s3c24xxfb_probe(假设是采用移植直接编译在内核里,而不是写成模块)

在注册framebuffer,即register_framebuffer里注册完后,假如你将这编译成模块,会发现最终程序死在fb_notifier_call_chain一直等待,最后出现Segmentation fault具体做法是将这语句注释掉,但如果你是把这驱动编译进内核,注释掉这步不能显示开机logo,原因在于,模块编译缺少依赖的内核模块,主要为cfbcopyarea.ko cfbfillrect.ko cfbimgblt.ko,这几个主要是给下面s3c2410fb_ops里的后三个,因为要 显示logoint fb_show_logo(struct fb_info *info)函数中,需要应用fb_ops结构体中的fb_imageblit域来在屏幕上画一幅图象,且是必须的,所以,fb_ops结构中fb_imageblit域不能为NULL,如果为NULL,那么这个函数就没有办法完成功能,也就是一个无用的函数,Fb_ops里面的内容就是完成应用程序系统调用。那register_framebuffer>>fb_notifier_call_chain》》》blocking_notifier_call_chain里的fb_notifier_list,这个内核链表又是哪里定义的?static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);慢慢看就知道定义成什么样子,那接上面的函数深入,到__blocking_notifier_call_chain》》notifier_call_chain,最终会调用nb->notifier_call(nb, val, v);,那什么时候加入到这内核链表?

加的地方有两个,一个是fbcon.c一个是backlight.cfbcon.c里的是fb_register_client(&fbcon_event_notifier);backlight.c里的是info->fb_notif

其中

fbcon_event_notify,这函数就根据不同的标志做不同的处理,再跟踪到较里面就发现,原来根据 是不是编译成内核模块来执行不同的东西,如果是编译进内核,就会显示logo了。大概完了。

现在更专业的方法是什么?当然是把那三个内核模块都加载进来

这里有一个关于pixclock像素时钟计算问题,它是怎么计算得来的?

其实它就是VCLK的另一种表述,VCLK是每秒多少像素,耐pixclock是每像素多少微微秒,1Hz = 10^12picoseconds,举个例子,当pixclock = 80000(pic) VCLK=1/80000*10^12/10^6 = 12.5MHz

由于LCD时钟是使用AHB分频得到的HCLK时钟再分频得来的,pixclock确定之后,怎么确定分频值呢?在函数s3c2410fb_set_par》》》》s3c2410fb_activate_var》》》》》s3c2410fb_calc_pixclk就是计算分频值也就是CLKAL的。还有一个提一下,就是在s3c2410fb_calc_pixclk里有一个unsigned long clk = clk_get_rate(fbi->clk);,其实它是得到HCLK的,具体是在clk_get(NULL,”lcd”)时得到的。

应用层操作lcd

采用fb_open(),fb_mmap(),fb_write()

以华清的例子为例分析

具体参考《嵌入式linux_Framebuffer驱动开发》,复制不过来,这里我在网上找了一个例子。

 

1.    显存大小计算:xres * yres * bits_per_pixel/8 (BYTES)

2.编程流程:

1 打开设备 open("/dev/fb0",O_RDWR);调用fb_open()

(2)   获取framebuffer设备信息.ioctl(int fb,FBIOGET_FSCREENINFO,&finfo);调用fb_ioctl

       ioctl函数是实现对设备的信息获取和设定,第一个参数为文件描述符,第二个参数为具体设备的参数,对于framebuffer,参数在linux/fb.h中定义的。

      #define FBIOGET_VSCREENINFO 0x4600   //获取设备无关的数据信息fb_var_screeninfo
      #define FBIOPUT_VSCREENINFO 0x4601   //
设定设备无关的数据信息

      #define FBIOGET_FSCREENINFO 0x4602   //
获取设备无关的常值信息fb_fix_screeninfo
      #define FBIOGETCMAP   0x4604        //
获取设备无关颜色表信息

      #define FBIOPUTCMAP   0x4605       //
设定设备无关颜色表信息
      #define FBIOPAN_DISPLAY   0x4606
      #define FBIO_CURSOR            _IOWR('F', 0x08, struct fb_cursor)

      第三个参数是存放信息的结构体或者缓冲区

(3)内存映射 mmap函数。头文件:sys/mman.h .常用用法:mmap(0,screensize,PROT_RD |PROT_WR,MAP_SHARED,int fb,0)返回映射的首地址。

3。实例

程序实现在lcd 上全屏写 blue

  

 

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值