您的位置 首页 系统

嵌入式Linux下五颜六色LCD驱动的规划与完成

嵌入式Linux下彩色LCD驱动的设计与实现 PMT 许庆丰 2002年12月 摘 要:本文介绍了如何在嵌入在开发彩色LCD显示驱动的方法,并对Linux中的显示驱动程序结构和框架作一介绍。 关键字:

嵌入式 Linux 下五颜六色 LCD 驱动的规划与完结
嵌入式Linux五颜六色LCD驱动的规划与完结 PMT 许庆丰 2002年12月 摘 要:本文介绍了如安在嵌入在开发五颜六色LCD显现驱动的方法,并对Linux中的显现驱动程序结构和结构作一介绍。 要害字:ARM,帧缓冲(Framebuffer),MC928MX1。 长期以来,在常见的掌上电脑(PDA)等小型手持式设备上,因为硬件条件等的约束,咱们看到的显现器材一般是单色LCD,用户界面也十分简略,简直看不到PC机上漂亮规整的图形界面(GUI)支撑。因为前期嵌入式处理器的速度有限,在处理图形和多媒体数据方面也显得无能为力。 跟着高性能嵌入式处理器的遍及和硬件本钱的不断下降,尤其是Arm系列处理器的推出,嵌入式体系的功用也越来越强。在多媒体运用的推进下,五颜六色LCD也越来越多地运用到了嵌入式体系中,如新一代掌上电脑(PDA)多选用TFT显现器材,支撑五颜六色图形界面,图片显现和视频媒体播映。掌上电脑(PDA)的操作体系有微软Window CE,PalmOS等。而Linux做为开放源代码的操作体系也在商场中占有了一席之地。因为Linux本钱低价,任何人都能够得到其源代码并在其基础上进行开发,成为各家厂商竭力开展的操作体系,加上其间心小,潜力可观。 在运用需求的推进下,Linux下也呈现了许多图形界面软件包,如MiniGUI、Trolletech公司的Embedded QT等,其图形界面及开发工具与Windows CE平起平坐。在图形软件包的开发和移植作业中都牵扯到底层LCD的驱动问题。笔者参加了一个依据ARM9的PDA体系的开发,用的是摩托罗拉公司龙珠系列的MC928MX1。软件选用Linux 2.4.18渠道,编译器为gcc的ARM穿插编译器。 一. 硬件渠道 MC928MX1(以下简称MX1)是摩托罗拉公司依据ARM中心的榜首款MCU,首要面向高端嵌入式运用。内部选用ARM920T内核,并集成了SDRAM/Flash,LCD,USB,蓝牙(bluetooth),多媒体闪存卡(MMC),CMOS摄像头号操控器。 LCD操控器的功用是发生显现驱动信号,驱动LCD显现器。用户只需求经过读写一系列的寄存器,完结制造和显现操控。MX1中的LCD操控器可支撑单色/五颜六色LCD显现器。支撑五颜六色TFT时,可供给4/8/12/16位色彩方法,其间16位色彩方法下能够显现65536种色彩。装备LCD操控器重要的一步是指定显现缓冲区,显现的内容便是从缓冲区中读出的,其巨细由屏幕分辨率和显现色彩数决议。在本例中,笔者选用的是夏普LQ035Q2DD54 TFT 显现模块,在240×320分辨率下可供给16位五颜六色显现。 PMT 版权一切 2002 http://www.pmtsolution.net
Page 1
嵌入式 Linux 下五颜六色 LCD 驱动的规划与完结
二. Linux下的设备驱动 Linux将设备分为最基本的两大类,字符设备和块设备。字符设备是以单个字节为单位进行次序读写操作,一般不运用缓冲技能,如鼠标等,驱动程序完结比较简略;而块设备则是以固定巨细的数据块进行存储和读写的,如硬盘,软盘等。为进步功率,体系关于块设备的读写供给了缓存机制,因为触及缓冲区办理,调度,同步等问题,完结起来比字符设备杂乱的多。 Linux的设备办理是和文件体系解密结合的,各种设备称号都以文件的方法存放在/dev目录下,称为设备文件。运用程序能够翻开,封闭,读写这些设备文件,完结对设备的操作,就象操作一般的数据文件相同。为了办理这些设备,体系为设备编了号,每个设备号又分为主设备号和次设备号。主设备号用来区别不同品种的设备,而次设备号用来区别同一类型的多个设备。关于常用设备,Linux有约定俗成的编号,如硬盘主设备号是3。在Linux的/dev/目录下运用ls -l指令可观察个设备文件的设备号。例如,/dev/hda为块设备,主设备号3,次设备号0,是体系的榜首块硬盘。/dev/hd1主设备号3,次设备号1,为体系的第二块硬盘。咱们即将介绍的显现设备也是一个设备文件/dev/fb,主设备号29。在编写设备驱动程序的时分,也要指明所操作设备的主设备号和次设备号。 Linux的特色之一,是为一切的文件,包含设备文件,供给了一致的操作函数接口,界说如下: struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); }; 结构体中的成员为一系列的接口函数,如用于读/写的read/ write函数,用于操控的ioctl等。翻开一个文件便是调用这个文件file_operations中的open操作。不同类型的文件有不同的file_operations成员函数。如一般的磁盘数据文件,接口函数完结磁盘数据块读写操作;而关于各种设备文件,则终究调用各自驱动程序中的I/O函数进行详细设备的操
PMT 版权一切 2002 http://www.pmtsolution.net
Page 2
嵌入式 Linux 下五颜六色 LCD 驱动的规划与完结
作。这样,运用程序底子不用考虑操作的是设备仍是一般文件,可一概当作文件处理,具有十分明晰一致的I/O接口。所以file_operations是文件层次的I/O接口。 可是,因为外设的品种繁复,操作方法也各不相同。如声响设备驱动要运用DMA通道,显现设备驱动要供给对显存的操作,硬盘驱动要处理杂乱的缓冲区结构,网络设备驱动和socket联络严密。假如file_operations中的函数都让驱动程序的开发人员来写,则就要处理很多的细节,简直是不可能的。为了处理设备多样性的问题,Linux选用了特别情况特别处理的方法,为不同设备界说好了文件层次file_operations结构中的接口函数,其间处理了大多数设备相关的操作,如各种缓冲区的请求和开释等等,而详细操作底层硬件的一小部分则留给开发人员。所以Linux别的供给一个文件层到底层驱动程序的接口,一般为一个结构体,其间包含成员变量和函数指针。不同的设备驱动有不同的结构体。这样,一方面确保了文件层I/O接口file_operations的一致性,另一方面驱动程序的开发人员也不用了解太多细节,只专著于硬件相关的I/O操作就能够了。例如,一个有代表性的特别设备是声响设备,其文件层的file_operations界说如下: struct file_operations oss_sound_fops = { owner: THIS_MODULE, llseek: sound_lseek, read: sound_read, write: sound_write, poll: sound_poll, ioctl: sound_ioctl, mmap: sound_mmap, open: sound_open, release: sound_release, }; 其间的sound_read,sound_write等函数Linux都已供给,处理了与声响设备相关的许多细节,如DMA的请求,开释和操作等。而文件层到驱动程序的接口为audio_driver结构,其间包含底层操作函数。文件层的sound_read,sound_write会在需求时调用audio_driver中的函数。开发人员只需编写audio_driver中的函数就能够了,最大程度地减小了作业量。下面咱们将看到,Linux为显现设备供给的帧缓冲驱动也是这种“文件层-驱动层”的接口方法。 三. Linux的帧缓冲设备 帧缓冲(framebuffer)是Linux为显现设备供给的一个接口,把显存笼统后的一种设备,他答应上层运用程序在图形方法下直接对显现缓冲区进行读写操作。这种操作是笼统的,一致的。用户不用关怀物理显存的方位、换页机制等等详细细节。这些都是由Framebuffer设备驱动来完结的。帧缓冲驱动的运用广泛,在linux的桌面体系中,Xwindow服务器便是运用帧缓冲进行窗口的制作。尤其是经过帧缓冲可显现汉字点阵,成为Linux汉化的仅有可行计划。 帧缓冲设备对应的设备文件为/dev/fb*,假如体系有多个显现卡,Linux下还可支撑多个帧缓冲设备,最多可达32个,别离为/dev/fb0到/dev/fb31,而/dev/fb则为当时缺省的帧缓冲设备,一般指向/dev/fb0。当然在嵌入式体系中支撑一个显现设备就够了。帧缓冲设备为规范字符设备,主设备号为29,次设备号则从0到31。别离对应/dev/fb0-/dev/fb31。 PMT 版权一切 2002 http://www.pmtsolution.net
Page 3
嵌入式 Linux 下五颜六色 LCD 驱动的规划与完结
经过/dev/fb,运用程序的操作首要有这几种: 1. 读/写(read/write)/dev/fb:相当于读/写屏幕缓冲区。例如用 cp /dev/fb0 tmp指令可将当时屏幕的内容拷贝到一个文件中,而指令cp tmp > /dev/fb0 则将图形文件tmp显现在屏幕上。 2. 映射(map)操作:因为Linux作业在保护方法,每个运用程序都有自己的虚拟地址空间,在运用程序中是不能直接拜访物理缓冲区地址的。为此,Linux在文件操作 file_operations结构中供给了mmap函数,可将文件的内容映射到用户空间。关于帧缓冲设备,则可经过映射操作,可将屏幕缓冲区的物理地址映射到用户空间的一段虚拟地址中,之后用户就能够经过读写这段虚拟地址拜访屏幕缓冲区,在屏幕上绘图了。实际上,运用帧缓冲设备的运用程序都是经过映射操作来显现图形的。因为映射操作都是由内核来完结,下面咱们将看到,帧缓冲驱动留给开发人员的作业并不多。 3. I/O操控:关于帧缓冲设备,对设备文件的ioctl操作可读取/设置显现设备及屏幕的参数,如分辨率,显现色彩数,屏幕巨细等等。ioctl的操作是由底层的驱动程序来完结的。 在运用程序中,操作/dev/fb的一般过程如下: 1. 翻开/dev/fb设备文件。 2. 用ioctrl操作获得当时显现屏幕的参数,如屏幕分辨率,每个像素点的比特数。依据屏幕参数可核算屏幕缓冲区的巨细。 3. 将屏幕缓冲区映射到用户空间。 4. 映射后就能够直接读写屏幕缓冲区,进行绘图和图片显现了。 典型程序段如下: #include linux/fb.h> int main() { int fbfd = 0; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; long int screensize = 0; /*翻开设备文件*/ fbfd = open(/dev/fb0, O_RDWR); /*获得屏幕相关参数*/ ioctl(fbfd, FBIOGET_FSCREENINFO, finfo); ioctl(fbfd, FBIOGET_VSCREENINFO, vinfo); /*核算屏幕缓冲区巨细*/ screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; /*映射屏幕缓冲区到用户地址空间*/ fbp=(char*)mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED, fbfd, 0); /*下面可经过fbp指针读写缓冲区*/ ……
PMT 版权一切 2002 http://www.pmtsolution.net
Page 4
}
嵌入式 Linux 下五颜六色 LCD 驱动的规划与完结
四. 帧缓冲驱动的编写 帧缓冲设备归于字符设备,与声响设备相同,也选用“文件层-驱动层”的接口方法。在文件层次上,Linux为其界说了 static struct file_operations fb_fops = { owner: THIS_MODULE, read: fb_read, /* 读操作 */ write: fb_write, /* 写操作 */ ioctl: fb_ioctl, /* 操控操作 */ mmap: fb_mmap, /* 映射操作 */ open: fb_open, /* 翻开操作 */ release: fb_release, /* 封闭操作 */ }; 其间的成员函数都在文件linux/driver/video/fbmem.c中界说。 因为显现设备的特别性,在驱动层的接口中不但要包含底层函数,还要有一些纪录设备状况的数据。Linux为帧缓冲设备界说的驱动层接口为struct fb_info结构,在include/linux/fb.h中界说。这个结构比较长,限于篇幅,文章中就不悉数列出了。走运的是,嵌入式体系要求的显现操作比较简略,只触及到结构中少量几个成员,下面只对编写驱动中要用到的几个要害成员作一阐明。 fb_info中纪录了帧缓冲设备的悉数信息,包含设备的设置参数,状况以及操作函数指针。每一个帧缓冲设备都必须对应一个fb_info结构。其间成员变量Modename为设备称号,fontname为显现字体,fbops为指向底层操作的函数的指针,这些函数是需求驱动程序开发人员编写的。成员fb_var_screeninfo和 fb_fix_screeninfo也是结构体。其间fb_var_screeninfo记载用户可修正的显现操控器参数,包含屏幕分辨率和每个像素点的比特数。fb_var_screeninfo中的xres界说屏幕一行有多少个点, yres界说屏幕一列有多少个点, bits_per_pixel界说每个点用多少个字节表明。而fb_fix_screeninfo中记载用户不能修正的显现操控器的参数,如屏幕缓冲区的物理地址,长度。当对帧缓冲设备进行映射操作的时分,便是从fb_fix_screeninfo中获得缓冲区物理地址的。上面所说的数据成员都是需求在驱动程序中设置的。 在了解了上面所述的概念后,编写帧缓冲驱动的实际作业并不杂乱,需求做的作业是: 1. 编写初始化函数:初始化函数首要初始化LCD操控器,设置显现方法和显现色彩数,然后分配LCD显现缓冲区。在Linux可经过kmalloc函数分配一片接连的空间。笔者选用的LCD显现方法为240×320,16位五颜六色。需求分配的显现缓冲区为240x320x2 = 150k字节,缓冲区一般分配在片外SDRAM中,开始地址保存在LCD操控器寄存器中。 终究是初始化一个fb_info结构,填充其间的成员变量,并调用register_framebuffer(fb_info)将fb_info挂号入内核。 2. 编写结构fb_info中函数指针fb_ops对应的成员函数:关于嵌入式体系的简略完结,只需求下列三个函数就能够了: struct fb_ops {
PMT 版权一切 2002 http://www.pmtsolution.net
Page 5
嵌入式 Linux 下五颜六色 LCD 驱动的规划与完结
…….. int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); int (*fb_get_var)(struct fb_var_screeninfo *var, int con, struct fb_info *info); int (*fb_set_var)(struct fb_var_screeninfo *var, int con,struct fb_info *info); ……. }; struct fb_ops在include/linux/fb.h中界说。这些函数都是用来设置/获取fb_info结构中的成员变量的。当运用程序对设备文件进行Ioctl操作时分会调用它们,读者可参阅前文中的运用程序比如。例如,关于fb_get_fix(),运用程序传入的是fb_fix_screeninfo结构,在函数中对其成员变量赋值,首要是smem_start(缓冲区开始地址)和smem_len(缓冲区长度),终究回来给运用程序。而fb_set_var()函数的传入参数是fb_var_screeninfo,函数中需求对xres,yres,和bits_per_pixel赋值。 驱动程序编写完结后,开发者可选择将其编译为动态加载模块,或静态地编译入内核中。因为篇幅所限,有关这方面的内容请读者参阅相关驱动程序文档。 五. 结束语 因为篇幅所限,本文中仅对帧缓冲设备驱动的基本原理和结构做了简略介绍。走运的是,在Linux的发布版别中,包含了很多的设备驱动程序源代码,其间drvers/video下供给了多种显现卡的帧缓冲设备驱动程序程序,用户自己的驱动程序可参阅老练的代码编写或直接修正得到。 参阅资料 《MC928MX1 User Manual》 《Linux frame buffer driver howto》 作者简介 许庆丰 Libo小组发起人。现任职于摩托罗拉半导体部,首要研讨方向是嵌入式操作体系和运用。 Libo小组面向一切对嵌入式体系开发感兴趣的人士,旨在促进和推行嵌入式体系的运用、相关的开源技能及行业界的沟通。Libo在线讨论组: http://www.smiling.com.cn/group/homepage.ecgi?group_id=36725 PMT 版权一切 2002 http://www.pmtsolution.net

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/xitong/198995.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部