嵌入式linux之LCD驱动记录

2019-07-12 22:06发布

分类:
1、页对齐内存大小:dma_map_size = PAGE_ALIGN(MY_DATA_SIZE + PAGE_SIZE); MY_DATA_SIZE是你想分配的大小. 2、调用 A = dma_alloc_writecombine(B,C,D,GFP_KERNEL); 含义: A: 内存的虚拟起始地址,在内核要用此地址来操作所分配的内存 B: struct device指针,可以平台初始化里指定,主要是dma_mask之类,可参考framebuffer C: 实际分配大小,传入dma_map_size即可 D: 返回的内存物理地址,dma就可以用。 所以,A和D是一一对应的,只不过,A是虚拟地址,而D是物理地址。对任意一个操作都将改变缓冲区内容。当然要注意操作环境。 参见S3C2410 LCD驱动中的函数s3c2410fb_map_video_memory():
unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,&map_dma, GFP_KERNEL); LCD提供的外部接口信号: VSYNC/VFRAME/STV:垂直同步信号(TFT)/帧同步信号(STN)/SEC TFT信号; HSYNC/VLINE/CPV:水平同步信号(TFT)/行同步脉冲信号(STN)/SEC TFT信号; VCLK/LCD_HCLK:象素时钟信号(TFT/STN)/SEC TFT信号; VD[23:0]:LCD像素数据输出端口(TFT/STN/SEC TFT); VDEN/VM/TP:数据使能信号(TFT)/LCD驱动交流偏置信号(STN)/SEC TFT 信号; LEND/STH:行结束信号(TFT)/SEC TFT信号; LCD_LPCOE:SEC TFT OE信号; LCD_LPCREV:SEC TFT REV信号; LCD_LPCREVB:SEC TFT REVB信号。 所有显示器显示图像的原理都是从上到下,从左到右的。这是什么意思呢?这么说吧,一副图像可以看做是一个矩形,由很多排列整齐的点一行一行组成,这些点称之为像素。那么这幅图在LCD上的显示原理就是: A:显示指针从矩形左上角的第一行第一个点开始,一个点一个点的在LCD上显示,在上面的时序图上用时间线表示就为VCLK,我们称之为像素时钟信号; B:当显示指针一直显示到矩形的右边就结束这一行,那么这一行的动作在上面的时序图中就称之为1 Line; C:接下来显示指针又回到矩形的左边从第二行开始显示,注意,显示指针在从第一行的右边回到第二行的左边是需要一定的时间的,我们称之为行切换; D:如此类推,显示指针就这样一行一行的显示至矩形的右下角才把一副图显示完成。因此,这一行一行的显示在时间线上看,就是时序图上的HSYNC; E:然而,LCD的显示并不是对一副图像快速的显示一下,为了持续和稳定的在LCD上显示,就需要切换到另一幅图上(另一幅图可以和上一副图一样或者不一样,目的只是为了将图像持续的显示在LCD上)。那么这一副一副的图像就称之为帧,在时序图上就表示为1 Frame,因此从时序图上可以看出1 Line只是1 Frame中的一行; F:同样的,在帧与帧切换之间也是需要一定的时间的,我们称之为帧切换,那么LCD整个显示的过程在时间线上看,就可表示为时序图上的VSYNC。 上面时序图上各时钟延时参数的含义如下:(这些参数的值,LCD产生厂商会提供相应的数据手册) VBPD(vertical back porch):表示在一帧图像开始时,垂直同步信号以后的无效的行数,对应驱动中的upper_margin; VFBD(vertical front porch):表示在一帧图像结束后,垂直同步信号以前的无效的行数,对应驱动中的lower_margin; VSPW(vertical sync pulse width):表示垂直同步脉冲的宽度,用行数计算,对应驱动中的vsync_len; HBPD(horizontal back porch):表示从水平同步信号开始到一行的有效数据开始之间的VCLK的个数,对应驱动中的left_margin; HFPD(horizontal front porth):表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK的个数,对应驱动中的right_margin; HSPW(horizontal sync pulse width):表示水平同步信号的宽度,用VCLK计算,对应驱动中的hsync_len; static struct fb_ops s3c2410fb_ops = { .owner = THIS_MODULE, .fb_check_var = s3c2410fb_check_var, //设置可变参数 .fb_set_par = s3c2410fb_set_par, //设置固定参数及lcdcon寄存器 .fb_blank = s3c2410fb_blank, //设置是否使能LCD控制器 .fb_setcolreg = s3c2410fb_setcolreg, //设置RGB颜色,实现伪颜色表 .fb_fillrect = cfb_fillrect, //画一个矩形 .fb_copyarea = cfb_copyarea, //Copy data from area to another .fb_imageblit = cfb_imageblit, //Draws a image to the display }; 而cfb_fillrect、cfb_copyarea、cfb_imageblit是通用的函数,不用驱动工程师去理会,只需要在加载lcd驱动时,将其对应的模块加载,而要加载模块,必须在编译内核后,再执行make modules,这样就可以得到相应的cfb*.ko了。
到这里s3c2410fb.c内核自带的lcd驱动基本剖析完毕,这里总结一下难点:
一、内核自带的lcd驱动是以平台驱动设备模型来编写的,难点不在框架,框架其实很简单, 1、分配一个fb_info结构体; 2、设置 fb_info结构体; 3、注册; 4、硬件相关的设置 二、好啦,难点就是如何设置fb_info结构体,而fb_info结构体成员那么多,是不每个成员都要一一设置呢?当然不是, 主要设置fb_info结构体的固定参数 fb_fix_screeninfo结构体和可变参数fb_var_screeninfo结构体,还有就是硬件相关 的设置,比如lcd时序参数的设置,也就是要设置lcdcon1~lcdcon5,lcdaddr1~lcdaddr3各个寄存器