本文转载至高手CLK:http://blog.csdn.net/xubin341719/article/details/9125583,谢谢!!!
关键词:android LCD TFT 液晶 偏光片 彩色滤光片 背光
平台信息:
内核:linux2.6/linux3.0
系统:android/android4.0
平台:samsung exynos 4210、exynos 4412 、exynos 5250
作者:xubin341719(欢迎转载,请注明作者)
下载链接:LCD规格书(404份),之前工作用用到的 、 LCD规格书00 、 LCD规格书01 、 LCD测试图片,彩条灰阶等
第一份工作、第一家公司,是做电视方案的,那段时间整天和LCD屏打交道,从7”到42”的都有调试过。那时没毕业,学校学习的东西跟工作差别比较大,不是太懂。不过那个公司的同事都很好,感谢他们细心的指导,也感谢第一家公司的工作机会和优厚的待遇(对学生来说很多)、很好的工作机会。 之后转行做平板,离开第一家公司,如果有机会、或者有足够的能力,一定会回报那些帮助过我的热心人,“滴水之恩,涌泉相报”。扯些闲话,认真工作、认真记录总结每一里程。
下面我们说一下TFT-LCD的构造和显示原理,和以前写的博客一样,我会写一下器件的组成、和简单工作原理,这些跟程序、android的关系并不是太大,不过要去调试一个模块,对它的构造有一个系统的了解,对模块的认识和工作的思路还是有比较大的帮助的(仅代表个人观点)。
LCD的种类分类标准比多,按驱动方式可以分为:被动矩阵式、主动矩阵式两种
被动矩阵式:被动矩阵式LCD又可分为TN-LCD(TwistedNematic-LCD,扭曲向列LCD)、STN—LCD(SuperTN-LCD,超扭曲向列LCD)和DSTN-LCD(Doublelayer STN-LCD,双层超扭曲向列LCD)。这部分内容就不详细解释, 我们重点讲TFT-LCD。
主动矩阵式
目前应用比较广泛的主动矩阵式LCD,也称TFT-LCD。TFT-LCD 即是Thin-FilmTransistor Liquid-Crystal Display的缩写(薄膜电晶体液晶显示器)TFT-LCD如何点亮?TFT-LCD现在比较广泛的应用,我们从TFT-LCD说起。
TFT-Thin Film Transistor 薄膜电晶体
LCD-Liquid Crystal Display液晶显示器
TFT-LCD Transistor Liquid-CrystalDisplay的缩写(薄膜电晶体液晶显示器)
由于TFT-LCD具有体积小,重量轻,低辐射,低耗电量,全彩化等优点,因此在各类显示器材上得到了广泛的应用。
一、TFT-lCD 的结构
1、TFT-LCD 的结构如下图所示
Reflector:反光板 CCF lamps:冷光灯管 Ligh pipe:导光片 Extraction pattern: Diffuser:散光板,起散光作用,使光线散布较为均匀 | 这部分主要是光源部分,CCFL或者LED背光光源,其他反光板、散光板,作用是这些光分布的更均匀 |
Rear polarizer:后部偏光片 Front Polarizer:前端偏光片 | 偏光片的作用把自然光变成偏极光 |
Selected Subpixels:子像素 TFT: Liquid crystal:液晶 Color filters:彩色滤色片 | 这部分是LCD的核心部分,选择光源的导通、阻断,彩色在这部分控制。 |
Back glass:背部玻璃基板 Front glass:前部玻璃基板 | 起保护作用 |
TFT-LCD各结构的功能
(1)、背光板模组:提供光的来源;
(2)、上下偏光板,TFT Glass Substrate,液晶:形成偏振光,控制光线的通过与否;
(3)、彩色滤光片:提供TFT LCD红、绿、蓝(光的三原色)的来源;
(4)、ITO透明导电层:提供透明的导电通路;
(5)、Photo Spacer:提供一固定高度給彩色滤光片和TFT Glass Substrate。作为灌入液晶时的空间.及作为上下两层Glass的支撑。
2、TFT-LCD 结构侧视图
一、TFT-LCD显示原理
1、 液晶的背光
背光也就是显示器的光源,LCD的背光常用有两种:CCFL背光、LED背光
(1)、CCFL
Cold Cathode Fluorescent Lamp简称CCFL,中文译名为冷阴极光灯管,具有高功率、高亮度、低能耗等优点,广泛应用于显示器、照明等领域。
(2)、LED背光
相对于CCFL,LED有功耗低、光源均匀、寿命长、体积小的优势,价格方面会贵点,不过现在平板上用的TFT-lCD好像都是LED背光的,上次搞破了一片顺便拆开看了下。
(3)、LED与LED背光
市面上所谓LED显示器,其实是“LED背光液晶显示器”;现在流行的液晶显示器,属于“CCFL背光液晶显示器”。所以此二者仍是液晶显示器,只是背光源不一样而已。不要看到LED显示器就误以为是下一代技术显示器,其实技术最新的是叫OLED。所以在买电视的时候不要被忽悠了。
2、液晶简介
(1)、液晶晶体的形状
TFT-LCD使用的液晶为TN(Twist Nematic)型液晶,液晶分子呈椭圆状。
(2)、液晶的特性
TN型液晶一般是顺着长轴方向串接,长轴间彼此平行方式排列。当接触到槽装表面时,液晶分子就会顺着槽的方向排列于槽中。
(3)、液晶垂直分布
当液晶被包含在两个槽状表面中间,且槽的方向互相垂直,则液晶分子的排列为:
上表面分子:沿着a方向
下表面分子:沿着b方向
介于上下表面中间的分子:产生旋转的效应。因此液晶分子在两槽状表面间产生90度的旋转。
(4)光与液晶分子产生偏转效果
(5)、液晶在电压做用下均匀分布
当在上下表面之间加电压时,液晶分子会顺着电场方向排列,形成直立排列的现象。此时入射光线不受液晶分子影响,直线射出下表面。
3、偏光板的特性
作用:将非偏极光(一般光线)过滤成偏极光。当非偏极光通过a方向的偏光片时,光线被过滤成与a方向平行的线性偏极光。
上图:线性偏极光继续前进,通过第二片偏光片时,光线通过。
下图:通过第二片时,光线被完全阻挡。
偏光板、槽状表面、液晶组合后产生的光学效果,如下图所示
(1)、当上下偏光片相互垂直时,若未施加电压,光线可通过
(2)、当施加电压时,光线被完全阻挡
当电流通过电晶体产生电场变化,造成液晶分子偏转,借以改变光线的偏极性,再利用偏光片决定画素(Pixel)的明暗状态。这样就可以实现对光线亮暗的控制,如果要显示彩色,我们后面在讲彩色滤光片。
4、彩色滤光片原理 color fliters
(1)、C/F 的结构
像之前像素低的显示器仔细都能看得到这些方格。比较简单的方法,在显示器上放一个水滴,你就可以看到红、绿、蓝、三色的点。
(2)、C/F Pixel Array的常见排列方式
如下图所示分别是马赛克、直条式、三角形式、四画素。
(3)、不同颜色的显示
我们再看下我们要显示相应颜色时,控制相应的pixel electrode就可以。如下图所示:
C/F彩色单元,对应到TFT的控制单元,就可以完成我们像素点颜色的控制。TFT Array 等效电路如下图所示:
三、TFT-LCD显像原理
我们前面解释了液晶透光原理、偏光片透光原理、彩色滤光片工作原理,这些把他理解成一个像素控制单元,然后我们来整理下TFT-LCD整体的显示原理。
(1)、SCAN IC传输信号;
完成图像信号输入;
(2)、DRIVER IC传输显像控制信号;
完成TFT单元控制;
(3)、当某一Sub-Pixel导通时,该Sub-Pixel因无法透光呈现黑色;
这部分完成像素点是亮还是暗。
(4)、若该Sub-Pixel未导通,则因光通过CF而显示颜色。经过光的合成效果,显示器即可产生彩色效果。如下图所示:
现在回头看我们开始那张结构图是不是清晰一点了:光源部分先把自然光通过偏光片转成偏极光-->TFT subpixels单元控制液晶单元是否导光、色彩-->通过前置偏光片把色彩图像显示。其实图像也就是不同色彩的光,我们看到的光其实也是偏极光。
这张图好像跟清晰的描述:
四、LCD常用到的知识点
1、残影
残影是指画面切换之后前一个画面不会立刻消失而是慢慢不见的现象,残影与反应时间不算同一件事,残影可能要两三秒后才会完全消失,而液晶的反应时间是十几到几十毫秒。一个设计得好的液晶显示器,就算反应时间是 15+35ms,也不可能让使用者看到残影。
残影发生机制有些复杂,通常是同一画面显示太久的情况下液晶内的带电离子吸附在上下玻璃两端形成内建电场,画面切换之后这些离子没有立刻释放出来,使得液晶分子没有立刻转到应转的角度所造成。另外一种可能情况则是因为画素电极设计不良,使得液晶分子在状态切换时排列错乱,这种情况之下也有可能看到残影。
2、坏点(dot defect)
所谓坏点, 是指液晶显示器上无法控制的恒亮或恒暗的点,坏点的造成是液晶面板生产时因各种因素造成的瑕疵可能是颗粒物落在面板里面,可能是静电伤害破坏面板,可能是制程控制不良等等等。坏点分为两种:亮点与暗点。一般来说,亮点会比暗点更令人无法接受,所以很多厂商会保证无亮点,但好象比较少保证无暗点的,有些面板厂商会在出货前把亮点修成暗点。
面板厂商会把有坏点的面板降价卖出,通常是无坏点算A grade,三点以内算B grade,六点以内算C grade。
市场上现在好多公司做平板,用IPAD2、IPAD3、MINIPAD的屏,然后在宣传产品时拿苹果说事,跟苹果比较,国内这些公司真实搞笑。其实他们用的屏就是生产过程中苹果检验通不过的屏,比如苹果只用A+的屏,A-包括A-以下等级的屏,都流入市场,国内的平板都是垃圾,虽然我也一直做这些东西,环境不好。
3、mura
mura本来是一个日本字,意思不均匀,有斑点,随着日本的液晶显示器在世界各地发扬光大。mura是指显示器亮度不均匀造成各种痕迹的现象,最简单的判断方法就是在暗室中切换到黑色画面以及其它低灰阶画面,然后从各种不同的角度用力去看,有问题的显示器比较容易看出。
4、色饱和度 (color gamut)
色饱和度是指显示器色彩鲜艳的程度,显示器是由红色绿色蓝色三种颜色光来组合成任意颜色光,如果RGB三原色越鲜艳, 则该显示器可以表示的颜色范围就更广。
5、亮度
亮度是指显示器在白色画面之下明亮的程度,单位是cd/m^2, 或是nit。亮度是直接影响画面品质的重要因素。在实验室里面我们常讲一句话:“一亮遮三丑”。一个明亮的显示器即使色饱和度比较差或颜色偏黄等其它不利因素,还是有可能看起来画面会比较漂亮。
亮度跟灯光有关了,灯管有寿命的,尤其是比较早的CCFL背光的,时间久了会发黄,这个如果家里有比较老的显示器就能明显的感受到。
6、视角
液晶显示器由于天生的物理特性, 使得使用者从不同角度去看时画面品质会
有所变化. 与正看时相比, 斜看的时候, 转到当画面品质已经变化到无法接
受的临界角度时, 称之为该显示器之视角.
7、色温(color temperature):
色温是用来形容显示器的白色的颜色,不限于LCD, 所有的显示器都通用,当显示器的颜色与黑体的温度高到某一绝对温度时所发出来的光一样时,称为该显示器的色温等于该温度。比如说,当显示器的白色设计成接近,黑体在温度6500K的时候所发出来的光颜色(接近晴天时上午的太阳光),称为该显示器的色温为6500K。
色温越低颜色会越偏黄色,色温越高颜色会越偏蓝色,一个色温偏高的显示器在秀图片的时候整个画面看起来色调就会偏蓝。
8、Gamma Curve:
Gamma curve是指不同灰阶与亮度的关系曲线。把零到二五五灰阶当x轴, 亮度当y轴, 画出来的曲线就叫做gamma curve. Gamma curve通常不会是一条直线,
因为人眼对不同亮度有不同辨识的效果, 比如说低亮度的辨识能力较高(一点点亮度变化就有感觉)。
下载链接:LCD常用测试图片,这里面有色阶、彩条之类的图片。调试效果时用到的。
http://blog.csdn.net/xubin341719/article/details/9125799
关键词:android LCD TFT TTL(RGB) LVDS EDP MIPI TTL-LVDS TTL-EDP
平台信息:
内核:linux2.6/linux3.0
系统:android/android4.0
平台:samsung exynos 4210、exynos 4412 、exynos 5250
作者:xubin341719(欢迎转载,请注明作者)
下载链接:LCD规格书(404份),之前工作用用到的 、 LCD规格书00 、 LCD规格书01 、 LCD测试图片,彩条灰阶等
TFT-lCD常用的接口,TTL(RGB)、LVDS、EDP、MIPI,这篇我们大致说一下这些接口的信号组成已经基本原理。
一、TTL
1、TTL接口概述
TTL(Transistor Transistor Logic)即晶体管-晶体管逻辑,TTL电平信号由TTL器件产生。TTL器件是数字集成电路的一大门类,它采用双极型工艺制造,具有高速度、低功耗和品种多等特点。
TTL接口属于并行方式传输数据的接口,采用这种接口时,不必在液晶显示器的驱动板端和液晶面板端使用专用的接口电路,而是由驱动板主控芯片输出的TTL数据信号经电缆线直接传送到液晶面板的输人接口。由于TTL接口信号电压高、连线多、传输电缆长,因此,电路的抗干扰能力比较差,而且容易产生电磁干扰(EMI)。在实际应用中,TTL接口电路多用来驱动小尺寸(15in以下)或低分辨率的液晶面板。TTL最高像素时钟只有28MHz。
TTL是信号时TFT-LCD唯一能识别的信号,早期的数字处理芯片都是TTL的,也就是RGB直接输出到TFT-LCD。
2、TTL接口的信号类型
驱动板TTL输出接口中一般包含RGB数据信号、时钟信号和控制信号这三大类信号。如下图所示:
(1)RGB数据信号
a、单通道TTL
单通道6bit TTL输出接口
对于6bit单路TTL输出接口,共有18条RGB数据线,分别是R0~R5红基色数据6条,G0~G5绿基色数据6条,B0~B5蓝基色数据6条,共3*6=18条。由于基色RGB数据为18bit,因此,也称18位或18bitTTL接口。
单通道8bit TTL输出接口
对于8bit单路TTI,输出接口,共有24条RGB数据线,分别是R0~R7红基色数据8条,B0~B7绿基色数据8条,BO~B7蓝基色数据8条,共3*8=24条。由于基色RGB数据为24bit,因此,也称24位或24bitTTL接口。
b、双通道TTL
双通道,也就是两组RGB数据,分为奇通道、偶通道,时钟有的也分为OCLK/ECLK,有的公用一个,我们示意图上画了两个,如下所示:
双通道6bit TTL输出接口
对于6bit双路TTL,输出接口,共有36条RGB数据线,分别是奇路RGB数据线18条,偶路RGB数据线18条,3*6*2=36条。由于基色ROB数据为36bit,因此,也称36位或36bitTTL接口。
双通道8bit TTL输出接口
对于8bit双路TTL输出接口,共有48条RGB数据线,分别是奇路RGB数据线24条,偶路RGB数据线24条,3*8*2=48条。由于基色RGB数据为48bit,因此,也称48位或48bitTTL接口。
(2)时钟信号
是指像素时钟信号,是传输数据和对数据信号进行读取的基准。在使用奇/偶像素双路方式传输RGB数据时,不同的输出接口使用像素时钟的方法有所不同。有的输出接口奇/偶像素双路数据共用一个像素时钟信号,有的输出接口奇/偶两路分别设置奇数像素数据时钟和偶数像素两个时钟信号,以适应不同液晶面板的需要。
(3)控制信号
控制信号包括数据使能信号(或有效显示数据选通信号)DE、行同步信号HS、场同步信号VS。
二、LVDS
1、LVDS接口概述
LVDS,即Low Voltage Differential Signaling,是一种低压差分信号技术接口。克服以TTL电平方式传输宽带高码率数据时功耗大、EMI电磁干扰大等缺点而研制的一种数字视频信号传输方式。LVDS输出接口利用非常低的电压摆幅(约350mV)在两条PCB走线或一对平衡电缆上通过差分进行数据的传输,即低压差分信号传输。采用LVDS输出接口,可以使得信号在差分PCB线或平衡电缆上以几百Mbit/s的速率传输,由于采用低压和低电流驱动方式,因此,实现了低噪声和低功耗。
2、LVDS接口电路的组成
在液晶显示器中,LVDS接口电路包括两部分,即主板侧的LVDS输出接口电路(LVDS发送端)和液晶面板侧的LVDS输入接口电路(LVDS接收器)。LVDS发送端将TTL信号转换成LVDS信号,然后通过驱动板与液晶面板之间的柔性电缆(排线)将信号传送到液晶面板侧的LVDS接收端的LVDS解码IC中,LVDS接收器再将串行信号转换为TTL电平的并行信号,送往液晶屏时序控制与行列驱动电路。也就是其实TFT只识别TTL(RGB)信号。这部分我们做samsung的方案中用的比较多,因为samsung芯片没有LVDS输出,所以我们用LVDS接口的TFT-LCD的时候就要加一个(RGB-LVDS)转换芯片,这个后面我们重点说。
3、LVDS接口的信号类型
LVDS信号有数据差分和时钟差分信号组成。如下图所示:
(1)、单通道LVDS
单通道6位数据(如果是6位的Y3M/P这组红色的线没有)
有4组差分线,3组信号线,一组时钟线。Y0M、Y0P、Y1M、Y1P、Y2M、Y2P、CLKOUT_M、CLKOUT_P。
单通道8位数据
有5组差分线,4组信号线,一组时钟线。分别是Y0M、Y0P、Y1M、Y1P、Y2M、Y2P、CLKOUT_M、CLKOUT_P。
(2)、双通道
LVDS在传输分辨率较高的数据时,抗干扰能力比较强,可是1920X1080以上分辨率时,单路不堪重负,所以有双路接口出现。目的很简单,加快速度,增强抗干扰能力。
双通道6位数据
刚好是单通道的两倍,时钟也是两路,红色部分:Y3M、Y3P、Y3M1、Y3M1这两组信号不接。
双通道8位数据
和前面的比较类似。
三、EDP
这个接口比较陌生,我接触到一个屏IPAD3的,用于高清屏,比如2048*1536,goole n10的分辨率2536* 也是用这个接口。
(整理中…………)
四、MIPI接口
这个我们公司有产品用,不过是其他平台的,不是我们调试 ,我也没接触过。只是过一下。感觉这类接口非常类似:比如LVDS、EDP、HDMI、MIPI,都是差分信息+差分时钟。
(整理中…………)
五、TTL(RGB)转换成LVDS
我们在项目中用到过两颗芯片:SN75LVDS83B 、THC63LVD827(可输出双路LVDS),以SN75LVDS83B来说明。
1、SN75LVDS83B、主控、LVDS接口的LCD关系
如下图所示SN75LVDS83B的应用:
其实就是:把三星芯片输出的TTL(RGB)信号转换成LVDS差分信号输出的LCD接收端。
硬件的接口如下所示:
2、SN75LVDS83B的参考电路
其实这部分要注意的是LCD的位数,你的屏是16bit、18bit、还是24bit的,不同位数的LCD有不同的硬件接线方法。如下图是samsung exynos4412提到的AP端,在不同位数输出时的接线图。
(1)、24bitRGB 24bit lcd
注意到用到五组差分信号线,四组信号一组时钟。
(2)、24bitRGB 18bit lcd
注意到用到四组差分信号线,三组信号一组时钟,Y3M、Y3P是NC的。AP端RGB的接线方式也不一样,6、7两个bit接地。
如果按(1)中的接线方法(24bit输出),接上18bit的屏。18bit 屏RGB(纯色)信号显示正常,可是有画面、渐变的就不正常。为此跟硬件争论了好久,不过问题解决了就好。做技术实践是非常重要的一个环节,有些事认识上的误区,就会导致工作的失误。
六、RGB转换成EDP
这个我们点过一个屏,不过分辨率太大,我们的系统非常卡,最后就停掉了。
线路图如下所示:
示意图:
edp 的信号和和lvds比较类似,不过多了一个HPD的信号。
http://blog.csdn.net/xubin341719/article/details/9177085
关键词:android LCD控制器 Framebuffer PWM
平台信息:
内核:linux2.6/linux3.0
系统:android/android4.0
平台:samsung exynos 4210、exynos 4412 、exynos 5250
作者:xubin341719(欢迎转载,请注明作者)
下载链接:LCD规格书(404份),之前工作用用到的 、 LCD规格书00 、 LCD规格书01 、 LCD测试图片,彩条灰阶等
参考:S5PV210显示驱动分析与移植(android)
这篇文章中转载的成分比较多,不过大部分内容是从芯片手册上翻译过来。Framebuffer部分是黄冈老师--《嵌入式Linux之我行》这一系列博客中的,嵌入式Linux之我行这系列博客写的非常精,我刚学习Linux时经常拜读他的博客。这部分内容比较固定,三星的芯片跟新了好多代,不过这部分变化不大,技术是一个积累的过程,感谢那些前辈给我们整理比较好的学习资料,有比较好的技术继承。
这篇从LCD控制器、接口信号硬件接口 寄存器、Framebuffer 、接口函数的实现及寄存器的操作来讲解,同事补充两个知点:如何阅读LCD、PWM概述;
一、 LCD控制器
功能模块的实现其实是芯片里面集成了一个相应的控制器,比如IIC有IIC控制器,UART有UART控制器等,像其他功能模块一样LCD也有一个控制器,来实现图形信息的处理。LCD控制器可以通过编程支持不同LCD屏的要求,例如行和列像素数,数据总线宽度,接口时序和刷新频率等。LCD控制器的主要作用,是将定位在系统存储器中的显示缓冲区中的LCD图像数据传送到外部LCD驱动器,并产生必要的控制信号,例如RGB_VSYNC,RGB_HSYNC, RGB_VCLK等。
如下图所示,在Exynos4412规格书中截图,LCD控制器的构成。
(下面这部分来自网络翻译,规格书中的描述)
主要由VSFR,VDMA, VPRCS , VTIME和视频时钟产生器几个模块组成:
(1)、VSFR由121个可编程控制器组,一套gamma LUT寄存器组(包括64个寄存器),一套i80命令寄存器组(包括12个寄存器)和5块256*32调色板存储器组成,主要用于对lcd控制器进行配置。
(2)、VDMA是LCD专用的DMA传输通道,可以自动从系统总线上获取视频数据传送到VPRCS,无需CPU干涉。
(3)、VPRCS收到数据后组成特定的格式(如16bpp或24bpp),然后通过数据接口(RGB_VD, VEN_VD, V656_VD or SYS_VD)传送到外部LCD屏上。
(4)、VTIME模块由可编程逻辑组成,负责不同lcd驱动器的接口时序控制需求。VTIME模块产生 RGB_VSYNC, RGB_HSYNC, RGB_VCLK, RGB_VDEN,VEN_VSYNC等信号。
主要特性:
(1)、支持4种接口类型:RGB/i80/ITU 601(656)/YTU444
(2)、支持单色、4级灰度、16级灰度、256色的调色板显示模式
(3)、支持64K和16M色非调色板显示模式
(4)、支持多种规格和分辨率的LCD
(5)、虚拟屏幕最大可达16MB
(6)、5个256*32位调色板内存
(7)、支持透明叠加
二、接口信号
FIMD显示控制器全部信号定义如下所示
Signal | I/O | Description | LCD Type |
LCD_HSYNC | O | 水平同步信号 |
RGB I/F |
LCD_VSYNC | O | 垂直同步信号 | |
LCD_VDEN | O | 数据使能 | |
LCD_VCLK | O | 视频时钟 | |
LCD_VD[23:0] | O | LCD像素数据输出 | |
SYS_OE | O | 输出使能 | |
VSYNC_LDI | O | Indirect i80接口,垂直同步信号 |
i80 I/F |
SYS_CS0 | O | Indirect i80接口,片选LCD0 | |
SYS_CS1 | O | Indirect i80接口,片选LCD1 | |
SYS_RS | O | Indirect i80接口,寄存器选择信号 | |
SYS_WE | O | Indirect i80接口,写使能信号 | |
SYS_VD[23:0] | IO | Indirect i80接口,视频数据输入输出 | |
SYS_OE | O | Indirect i80接口,输出使能信号 | |
VEN_HSYNC | O | 601接口水平同步信号 |
ITU 601/656 I/F |
VEN_VSYNC | O | 601接口垂直同步信号 | |
VEN_HREF | O | 601接口数据使能 | |
V601_CLK | O | 601接口数据时钟 | |
VEN_DATA[7:0] | O | 601接口YUV422格式数据输出 | |
V656_DATA[7:0] | O | 656接口YUV422格式数据输出 | |
V656_CLK | O | 656接口数据时钟 | |
VEN_FIELD | O | 601接口域信号 |
1、其中主要的RGB接口信号:
(1)、LCD_HSYNC:行同步信号,表示一行数据的开始,LCD控制器在整个水平线(整行)数据移入LCD驱动器后,插入一个LCD_HSYNC信号;
(2)、LCD_VSYNC: 帧同步信号,表示一帧数据的开始,LCD控制器在一个完整帧显示完成后立即插入一个LCD_VSYNC信号,开始新一帧的显示;VSYNC信号出现的频率表示一秒钟内能显示多少帧图像,称为“显示器的频率”
(3)、LCD_VCLK:像素时钟信号,表示正在传输一个像素的数据;
(4)、LCD_VDEN:数据使能信号;
(5)、 LCD_VD[23:0]: LCD像素数据输出端口
2、RGB信号的时序
下图是LCDRGB接口工作时序图:
(1)、上面时序图上各时钟延时参数的含义如下:这些配置可以在LCD规格书中查取
VBPD(vertical back porch):表示在一帧图像开始时,垂直同步信号以后的无效的行数
VFBD(vertical front porch):表示在一帧图像结束后,垂直同步信号以前的无效的行数VSPW(vertical sync pulse width):表示垂直同步脉冲的宽度,用行数计算
HBPD(horizontal back porch):表示从水平同步信号开始到一行的有效数据开始之间的VCLK的个数HFPD(horizontal front porth):表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK的个数
HSPW(horizontal sync pulse width):表示水平同步信号的宽度,用VCLK计算
(2)、帧的传输过程
VSYNC信号有效时,表示一帧数据的开始, 信号宽度为(VSPW +1)个HSYNC信号周期,即(VSPW +1)个无效行;
VSYNC信号脉冲之后,总共还要经过(VBPD+ 1)个HSYNC信号周期,有效的行数据才出现; 所以,在VSYNC信号有效之后,还要经过(VSPW +1 + VBPD + 1)个无效的行;
随即发出(LINEVAL + 1)行的有效数据;
最后是(VFPD + 1)个无效的行;
(3)、行中像素数据的传输过程
HSYNC信号有效时,表示一行数据的开始,信号宽度为(HSPW+ 1)个VCLK信号周期,即(HSPW +1)个无效像素;
HSYNC信号脉冲之后,还要经过(HBPD +1)个VCLK信号周期,有效的像素数据才出现;
随后发出(HOZVAL+ 1)个像素的有效数据;
最后是(HFPD +1)个无效的像素;
(4)、将VSYNC、HSYNC、VCLK等信号的时间参数设置好之后,并将帧内存的地址告诉LCD控制器,它即可自动地发起DMA传输从帧内存中得到图像数据,最终在上述信号的控制下出现在数据总线VD[23:0]上。用户只需要把要显示的图像数据写入帧内存中。
其实现实的图像有像素点主城行、行组成场、场组成动画、动画叠加也就是3D的出现,也就是我们所说的“点动成线、线动成面、面动成体”。
三、LCD的硬件接口
1、16M(24BPP)色的显示模式
用24位的数据来表示一个像素的颜色,每种颜色使用8位。 LCD控制器从内存中获得某个像素的24为颜色值后,直接通过VD[23:0]数据线发送给LCD;在内存中,使用4个字节(32位)来表示一个像素,其中的3个字节从高到低分别表示红、绿、蓝,剩余的1个字节无效;
2、64K(16BPP)色的显示模式
用16位的数据来表示一个像素的颜色;格式又分为两种: 5:6:5 ——使用5位来表示红色,6位表示绿色,5位表示蓝色 ; 5:5:5:1——分别使用5位来表示红、绿、蓝,最后一位表示透明度;
3、16BPP
4、serialRGB
不同的BPP接线方式如下所示:
四、寄存器
主要寄存器如下:
VIDCON0:配置视频输出格式,显示使能
VIDCON1:RGB 接口控制信号
VIDCON2: 输出数据格式控制
VIDCON3: 图像增强控制
I80IFCONx:i80接口控制信号
ITUIFCON: ITU接口控制信号
VIDTCONx:配置视频输出时序及显示大小
WINCONx:每个窗口特性设置
VIDOSDxA,B: 窗口位置设置
VIDOSDxC,D:OSD大小设置
五、Framebuffer驱动部分
这部分是:分析的比较好,我刚学linux的时候就拿个mini2440的板子对着他的博客练习)。其实这部分也是博主从S3c2440上分析的,三星芯片更新了这么多代,这块的原理还是不变的。就像一些协议一样,这么多年基本上不会变化,唯一出现的结果就是出来新的接口替代。LCD这块就是:TTL、LVDS、EDP、MIPI、HDMI等等…………速度更快,接线、PCB走线更简单,这就是集成化的好处。
1、简介
帧缓冲是Linux为显示设备提供的一个接口,它把一些显示设备描述成一个缓冲区,允许应用程序通过FrameBuffer定义好的接口访问这些图形设备,从而不用去关心具体的硬件细节。对于帧缓冲设备而言,只要在显示缓冲区与显示点对应的区域写入颜色值,对应的颜色就会自动的在屏幕上显示。下面来看一下在不同色位模式下缓冲区与显示点的对应关系:
2、驱动结构
帧缓冲设备为标准的字符型设备,在Linux中主设备号29,定义在/linux/major.h中的FB_MAJOR,次设备号定义帧缓冲的个数,最大允许有32个FrameBuffer,定义在/include/linux/fb.h中的FB_MAX,对应于文件系统下/dev/fb%d设备文件。
帧缓冲设备驱动在Linux子系统中的结构如下:
我们从上面这幅图看,帧缓冲设备在Linux中也可以看做是一个完整的子系统,大体由fbmem.c和xxxfb.c(对应我们的s3cfb.c)组成。向上给应用程序提供完善的设备文件操作接口(即对FrameBuffer设备进行read、write、ioctl等操作),接口在Linux提供的fbmem.c文件中实现;向下提供了硬件操作的接口,只是这些接口Linux并没有提供实现,因为这要根据具体的LCD控制器硬件进行设置,所以这就是我们要做的事情了(即s3cfb.c部分的实现)。
3、数据结构及接口函数
从帧缓冲设备驱动程序结构看,该驱动主要跟fb_info结构体有关,该结构体记录了帧缓冲设备的全部信息,包括设备的设置参数、状态以及对底层硬件操作的函数指针。在Linux中,每一个帧缓冲设备都必须对应一个fb_info,fb_info在/linux/fb.h中的定义如下:(只列出重要的一些)
- struct fb_info {
- int node;
- int flags;
- struct fb_var_screeninfo var;/*LCD可变参数结构体*/
- struct fb_fix_screeninfo fix;/*LCD固定参数结构体*/
- struct fb_monspecs monspecs; /*LCD显示器标准*/
- struct work_struct queue; /*帧缓冲事件队列*/
- struct fb_pixmap pixmap; /*图像硬件mapper*/
- struct fb_pixmap sprite; /*光标硬件mapper*/
- struct fb_cmap cmap; /*当前的颜色表*/
- struct fb_videomode *mode; /*当前的显示模式*/
- #ifdef CONFIG_FB_BACKLIGHT
- struct backlight_device *bl_dev;/*对应的背光设备*/
- struct mutex bl_curve_mutex;
- u8 bl_curve[FB_BACKLIGHT_LEVELS];/*背光调整*/
- #endif
- #ifdef CONFIG_FB_DEFERRED_IO
- struct delayed_work deferred_work;
- struct fb_deferred_io *fbdefio;
- #endif
- struct fb_ops *fbops; /*对底层硬件操作的函数指针*/
- struct device *device;
- struct device *dev; /*fb设备*/
- int class_flag;
- #ifdef CONFIG_FB_TILEBLITTING
- struct fb_tile_ops *tileops; /*图块Blitting*/
- #endif
- char __iomem *screen_base; /*虚拟基地址*/
- unsigned long screen_size; /*LCD IO映射的虚拟内存大小*/
- void *pseudo_palette; /*伪16色颜色表*/
- #define FBINFO_STATE_RUNNING 0
- #define FBINFO_STATE_SUSPENDED 1
- u32 state; /*LCD的挂起或恢复状态*/
- void *fbcon_par;
- void *par;
- };
其中,比较重要的成员有struct fb_var_screeninfo var、structfb_fix_screeninfo fix和struct fb_ops *fbops,他们也都是结构体。
fb_var_screeninfo结构体主要记录用户可以修改的控制器的参数,比如屏幕的分辨率和每个像素的比特数等,该结构体定义如下:
- struct fb_var_screeninfo {
- __u32 xres; /*可见屏幕一行有多少个像素点*/
- __u32 yres; /*可见屏幕一列有多少个像素点*/
- __u32 xres_virtual; /*虚拟屏幕一行有多少个像素点*/
- __u32 yres_virtual; /*虚拟屏幕一列有多少个像素点*/
- __u32 xoffset; /*虚拟到可见屏幕之间的行偏移*/
- __u32 yoffset; /*虚拟到可见屏幕之间的列偏移*/
- __u32 bits_per_pixel; /*每个像素的位数即BPP*/
- __u32 grayscale; /*非0时,指的是灰度*/
- struct fb_bitfield red; /*fb缓存的R位域*/
- struct fb_bitfield green; /*fb缓存的G位域*/
- struct fb_bitfield blue; /*fb缓存的B位域*/
- struct fb_bitfield transp; /*透明度*/
- __u32 nonstd; /* != 0 非标准像素格式*/
- __u32 activate;
- __u32 height; /*高度*/
- __u32 width; /*宽度*/
- __u32 accel_flags;
- /*定时:除了pixclock本身外,其他的都以像素时钟为单位*/
- __u32 pixclock; /*像素时钟(皮秒)*/
- __u32 left_margin; /*行切换,从同步到绘图之间的延迟*/
- __u32 right_margin; /*行切换,从绘图到同步之间的延迟*/
- __u32 upper_margin; /*帧切换,从同步到绘图之间的延迟*/
- __u32 lower_margin; /*帧切换,从绘图到同步之间的延迟*/
- __u32 hsync_len; /*水平同步的长度*/
- __u32 vsync_len; /*垂直同步的长度*/
- __u32 sync;
- __u32 vmode;
- __u32 rotate;
- __u32 reserved[5]; /*保留*/
- };
而fb_fix_screeninfo结构体又主要记录用户不可以修改的控制器的参数,比如屏幕缓冲区的物理地址和长度等,该结构体的定义如下:
- struct fb_fix_screeninfo {
- char id[16]; /*字符串形式的标示符 */
- unsigned long smem_start; /*fb缓存的开始位置 */
- __u32 smem_len; /*fb缓存的长度 */
- __u32 type; /*看FB_TYPE_* */
- __u32 type_aux; /*分界*/
- __u32 visual; /*看FB_VISUAL_* */
- __u16 xpanstep; /*如果没有硬件panning就赋值为0 */
- __u16 ypanstep; /*如果没有硬件panning就赋值为0 */
- __u16 ywrapstep; /*如果没有硬件ywrap就赋值为0 */
- __u32 line_length; /*一行的字节数 */
- unsigned long mmio_start; /*内存映射IO的开始位置*/
- __u32 mmio_len; /*内存映射IO的长度*/
- __u32 accel;
- __u16 reserved[3]; /*保留*/
- };
fb_ops结构体是对底层硬件操作的函数指针,该结构体中定义了对硬件的操作有:(这里只列出了常用的操作)
- struct fb_ops {
- struct module *owner;
- //检查可变参数并进行设置
- int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
- //根据设置的值进行更新,使之有效
- int (*fb_set_par)(struct fb_info *info);
- //设置颜色寄存器
- int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp, struct fb_info *info);
- //显示空白
- int (*fb_blank)(int blank, struct fb_info *info);
- //矩形填充
- void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
- //复制数据
- void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
- //图形填充
- void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
- };
六、Framebuffer设备注册
S3cfb.c中的s3cfb_probe设备探测,是驱动注册的主要函数,
/*定义一个结构体用来维护驱动程序中各函数中用到的变量
先别看结构体要定义这些成员,到各函数使用的地方就明白了*/
- static int __devinit s3cfb_probe(struct platform_device *pdev)
- {
- struct s3c_platform_fb *pdata;/*LCD屏配置信息结构体*/
- struct s3cfb_global *fbdev;/*驱动程序全局变量结构体*/
- struct resource *res; /*用来保存从LCD平台设备中获取的LCD资源*/
- int i, j, ret = 0;
- printk("%s\n",__func__);
- fbdev = kzalloc(sizeof(struct s3cfb_global), GFP_KERNEL);
- if (!fbdev) {
- dev_err(&pdev->dev, "failed to allocate for "
- "global fb structure\n");
- ret = -ENOMEM;
- goto err_global;
- }
- fbdev->dev = &pdev->dev;
- fbdev->regulator = regulator_get(&pdev->dev, "pd");
- if (!fbdev->regulator) {
- dev_err(fbdev->dev, "failed to get regulator\n");
- ret = -EINVAL;
- goto err_regulator;
- }
- ret = regulator_enable(fbdev->regulator);
- if (ret < 0) {
- dev_err(fbdev->dev, "failed to enable regulator\n");
- ret = -EINVAL;
- goto err_regulator;
- }
- /*获取LCD参数信息*/
- pdata = to_fb_plat(&pdev->dev);
- if (!pdata) {
- dev_err(fbdev->dev, "failed to get platform data\n");
- ret = -EINVAL;
- goto err_pdata;
- }
- fbdev->lcd = (struct s3cfb_lcd *)pdata->lcd;
- /*配置GPIO端口*/
- if (pdata->cfg_gpio)
- pdata->cfg_gpio(pdev);
- /*设置时钟参数*/
- if (pdata->clk_on)
- pdata->clk_on(pdev, &fbdev->clock);
- /*获取LCD平台设备所使用的IO端口资源,注意这个IORESOURCE_MEM标志和LCD平台设备定义中的一致*/
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(fbdev->dev, "failed to get io memory region\n");
- ret = -EINVAL;
- goto err_io;
- }
- /*申请LCD IO端口所占用的IO空间(注意理解IO空间和内存空间的区别),request_mem_region定义在ioport.h中*/
- res = request_mem_region(res->start,
- res->end - res->start + 1, pdev->name);
- if (!res) {
- dev_err(fbdev->dev, "failed to request io memory region\n");
- ret = -EINVAL;
- goto err_io;
- }
- /*将LCD的IO端口占用的这段IO空间映射到内存的虚拟地址,ioremap定义在io.h中
- 注意:IO空间要映射后才能使用,以后对虚拟地址的操作就是对IO空间的操作*/
- fbdev->regs = ioremap(res->start, res->end - res->start + 1);
- if (!fbdev->regs) {
- dev_err(fbdev->dev, "failed to remap io region\n");
- ret = -EINVAL;
- goto err_mem;
- }
- #ifdef CONFIG_FB_S3C_LTE480WV
- /*设置寄存器初始状态*/
- s3cfb_pre_init_para(fbdev);
- #endif
- /*设置gamma 值*/
- s3cfb_set_gamma(fbdev);
- /*设置VSYNC中断*/
- s3cfb_set_vsync_interrupt(fbdev, 1);
- /*设置全局中断*/
- s3cfb_set_global_interrupt(fbdev, 1);
- /*fb设备参数信息初始化*/
- s3cfb_init_global(fbdev);
- /*为framebuffer分配空间,进行内存映射,填充fb_info*/
- if (s3cfb_alloc_framebuffer(fbdev)) {
- ret = -ENOMEM;
- goto err_alloc;
- }
- /*注册fb设备到系统中*/
- if (s3cfb_register_framebuffer(fbdev)) {
- ret = -EINVAL;
- goto err_register;
- }
- s3cfb_set_clock(fbdev);
- s3cfb_set_window(fbdev, pdata->default_win, 1);
- s3cfb_display_on(fbdev);
- fbdev->irq = platform_get_irq(pdev, 0);
- if (request_irq(fbdev->irq, s3cfb_irq_frame, IRQF_SHARED,
- pdev->name, fbdev)) {
- dev_err(fbdev->dev, "request_irq failed\n");
- ret = -EINVAL;
- goto err_irq;
- }
- #ifdef CONFIG_FB_S3C_LCD_INIT
- if (pdata->backlight_on)
- pdata->backlight_on(pdev);
- if (!bootloaderfb && pdata->reset_lcd)
- pdata->reset_lcd(pdev);
- if (pdata->lcd_on)
- pdata->lcd_on(pdev);
- #endif
- #ifdef CONFIG_HAS_EARLYSUSPEND
- fbdev->early_suspend.suspend = s3cfb_early_suspend;
- fbdev->early_suspend.resume = s3cfb_late_resume;
- fbdev->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
- register_early_suspend(&fbdev->early_suspend);
- #endif
- /*对设备文件系统的支持,创建fb设备文件*/
- ret = device_create_file(&(pdev->dev), &dev_attr_win_power);
- if (ret < 0)
- dev_err(fbdev->dev, "failed to add sysfs entries\n");
- dev_info(fbdev->dev, "registered successfully\n");
- /*显示开机logo*/
- #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
- if (fb_prepare_logo( fbdev->fb[pdata->default_win], FB_ROTATE_UR)) {
- printk("Start display and show logo\n");
- /* Start display and show logo on boot */
- fb_set_cmap(&fbdev->fb[pdata->default_win]->cmap, fbdev->fb[pdata->default_win]);
- fb_show_logo(fbdev->fb[pdata->default_win], FB_ROTATE_UR);
- }
- #endif
- return 0;
- }
七、如何阅读LCD规格书
首先我们调试LCD的时候要获得的一些参数,没必要把整个规格书通读一遍,我刚开始调试屏的时候拿到一个规格书不知道从何入手,也不知那些参数有用,比较模糊,其实只提取一些有用的信息就可以,下面这些对初学者也许有点用处。
1、GeneralSpecification
尺寸、分辨率、位数、色彩、像素时钟频率、接口类型
(1)、尺寸:
(2)、分辨率:1920 1200;
(3)、接口:双通道LVDS;
(4)、色彩:16.7M,这里可以确认数据位数8bitRGB三色:3*8=24,2的24次方=16.7M
6bitRGB 三色:3*6=18,2的18次方=262 144;
所以当看到色彩是1.7M是,说明LCD是24bit的,如果是262 144说明LCD是18bit的。
2、Timing Characteristics
(1)、Frame rate :是60HZ,也就是帧率;
(2)、clock frequency:像素时钟,这里面有最大值、中间值和最小值,这个屏默认值为:76.36MHz;
(3)、Vertical Seciton:VSWidth +Back Porc+Front Porch,前间距、后间距。这个我们再RGB信号哪里详细解释,这个我们前面有说过;
(4)、Horizontal Section:HS Width +Back Porc+Front Porch,这个跟VS的Porch相同。
3、LCD Timing diagram信号时序图,如下所示
有些读者会问,为什么没有行、场、数据等信号。其实这个是 LVDS 信号的时序,这个根据屏厂的习惯,有的画的是 LVDS 输入的信号时序,有的是 TTL ( RGB )的时序。
上面我们以一个例子说明,做驱动的(软件方面)要知道的一些参数,如果是硬件方面的问题,可以再对一下接口。其实一个LCD规格书要了解的也就这么多,调试软件就够用:
(1)、General Specification中可得到,尺寸、分辨率、位数、色彩、像素时钟频率、接口类型;
(2)、Timing Characteristics中可以得到一些具体的参数;
(3)、LCD Timing diagram信号时序图,可以看到一些信号的时序、极性等;
八、PWM概述
1、先解释两个名词:
PWM:脉冲宽度调制(PWM),是英文“Pulse WidthModulation”的缩写,简称脉宽调制。
占空比:占空比(DutyRation)在电信领域中有如下含义:
在一串理想的脉冲周期序列中(如方波),正脉冲的持续时间与脉冲总周期的比值。例如:(假设脉冲为3V)
脉冲宽度 1μs,信号周期4μs的脉冲序列占空比为0.25,平均电压为:3*0.25=0.75V;
脉冲宽度 0μs,信号周期4μs的脉冲序列占空比为0,平均电压为:0V;
脉冲宽度 4μs,信号周期4μs的脉冲序列占空比为1,平均电压为:3V;
平均电压的变化成阶梯型变化,如果T足够小,成线性。
看下芯片片规格书中的描述:寄存器填不同值是,脉冲宽度不一样。
2、samusng 中的PWM控制器
PWM时钟分频。跟单片机里面的有点像。
死区控制器:这个是根据晶体管的特性,设置这个功能的,不过我工作中还没有用到死区控制这块。了解有这个概念。
看这些寄存器,记得用MINI2440写裸机程序的时候,直接写这些寄存器,记得上学时把s3c2440当单片机玩,有点浪费。学生时代,已经逝去的青春??
http://blog.csdn.net/xubin341719/article/details/9179203
关键词:android LCD TFTSN75LVDS83B TTL-LVDS LCD电压背光电压
平台信息:
内核:linux2.6/linux3.0
系统:android/android4.0
平台:samsung exynos 4210、exynos 4412 、exynos 5250
作者:xubin341719(欢迎转载,请注明作者)
下载链接:LCD规格书(404份),之前工作用用到的 、 LCD规格书00 、 LCD规格书01 、 LCD测试图片,彩条灰阶等
这篇我们以一个实例来说明,Samsung Exynos4412搭配TTL转LVDS芯片SN75LVDS83B、LVDS接口LCD为例说明。从硬件接口、驱动配置、背光PWM调节三部分说明。
一、LCD接口原理以及硬件电路
Samsung Exynos4412、SN75LVDS83B、LVDS接口LCD(24bit)为例说明,三者的关系如下:
如上图所示,我们在应用中我,主控(Exynos4412)输出RGB信号到TFT-LCD大体经过三部分:
(1)、标号1部分,主控(Exynos4412)输出TTL信号;
(2)、标号2部分,TTL(RGB)-LVDS转换芯片SN75LVDS83B,把TTL信号转换成LVDS信号,传输到显示器的LVDS接收端;这部分有SN75LVDS83B编码芯片自动完成,所以我们不需要程序控制;
(3)、标号3部分,分两个小部分,LVDS转换成TTL,TFT-LCD显示部分;我们前面说过,TFT-LCD其实只识别TTL信号,所以要有一个转换的过程,先把LVDS信号转换、解码成TTL信号,在TFT-LCD上显示。
有上面的过程,其实我们关心调试的部分只有标号1部分到标号2部分,后面标号2到标号3的部分是自动完成的,不需要我们程序上控制,把标号2部分、标号3部分合并:
标号二部分可以理解为一个TTL(RGB)接口的LCD,如下图所示,标号一部分就是主控信号输出端,简化图如下所示:
其实最简单的做法就是找个TTL接口的TFT-LCD,这样直接接上就可以。下面我们看下硬件上的电路连接:这个和我们上篇用的相同。
有上面图可以看出:硬件连接
网络标号 | 说明 | 管脚 |
XvVD[0:23] XvVDEN XvVSYNC XvHSYNC XvVCLK | RGB数据、使能、行场同步、时钟信号 | 这是TTL信号输出 |
LCD_PWM | 调节背光 | XpwmTOUT1/LCD_PWM/GPD0_1 |
LCD_LED_EN | LCD电压(TFT电压)使能 | GPC1_2 |
LED_BL_EN | LED背光使能 | GPL2_4 |
上面可分为几部分,电路连接部分分析:
(1)、TTL数据部分
这张图有木有烂掉呀,哈哈,就是这些数据了。还有有木有想起来摄像头的数据(ITU接口)也是这样的??其实视频这种信号的原理是通用的,所以LCD通了,摄像头也就知道怎么回事了。
(2)、PWM背光调节
PWM其实也是芯片的一个功能模块,看到他的管脚就是一个复用脚XpwmTOUT1/LCD_PWM/GPD0_1。上一篇我们粗略的了解了PWM,就是用到这里。但是有一个疑问,PWM是调节背光电压的,背光电压一般都是12V以上的,我们PWM只有0-3V的样子,Exynos4412的IO只有1.8V。怎么调节电压???
其实这个PWM只是给LCD上PWM控制部分,真正的电压还是通过LCD控制板上的电路实现。
(3)、LED背光、LCD电压控制
a、背光:LED+
我们可以看到这个升压电路,通过SY7208把VBATT升压到18V,供给LED背光。SY7208最大升压26V。这个电压是提供给我们前面讲的背光的,也就是CCFL灯管或者LED背光组的电压。
b、LCD电压
这个电压也就是给你我们TFT阵列组用的,控制LCD液晶元素。
这部分电路分析完成,我们就有比较清晰的思路出,要一个LCD工作,要完成两部分内容:LCD上电控制,背光、LCD电压;信号输出。
二、LCD 驱动部分调试
LCD这部分,像上篇我们说的frambuffer这些部分一般平台都是可以用的,除非你是芯片厂的要写这部分。一般公司拿到的demo板子这部分都是通的,只是针对自己的lCD换一些参数。
下面我们针对三星平台我们调试LCD的时时候程序方面的改动:
1、屏参数的配置
/kernel/drivers/video/Samsung/s3cfb_wa101s.c
- static struct s3cfb_lcd wa101 = {
- .width = 1280,//LCD 分辨率宽1280
- .height = 800, //LCD 分辨率高 800
- .bpp = 24,//CLD 数据位 24bit
- .freq = 60,//LCD 像素时钟 60MHz
- .timing = {//LCD porch无效值
- .h_fp = 70,
- .h_bp = 70,
- .h_sw = 20,
- .v_fp = 10,
- .v_fpe = 0,
- .v_bp = 10,
- .v_bpe = 0,
- .v_sw = 3,
- },
- .polarity = {//时钟、行场的极性;
- .rise_vclk = 1,
- .inv_hsync = 1,
- .inv_vsync = 1,
- .inv_vden = 0,
- },
- };
- /* name should be fixed as 's3cfb_set_lcd_info' */
- void s3cfb_set_lcd_info(struct s3cfb_global *ctrl)//初始化结构体
- {
- wa101.init_ldi = NULL;
- ctrl->lcd = &wa101;
- #endif
- }
2、数据管脚初始化
kernel/arch/arm/mach-exynos/setup-fb-s5p.c
- void s3cfb_cfg_gpio(struct platform_device *pdev)
- {
- s3cfb_gpio_setup_24bpp(EXYNOS4_GPF0(0), 8, S3C_GPIO_SFN(2), S5P_GPIO_DRVSTR_LV4);
- s3cfb_gpio_setup_24bpp(EXYNOS4_GPF1(0), 8, S3C_GPIO_SFN(2), S5P_GPIO_DRVSTR_LV4);
- s3cfb_gpio_setup_24bpp(EXYNOS4_GPF2(0), 8, S3C_GPIO_SFN(2), S5P_GPIO_DRVSTR_LV4);
- s3cfb_gpio_setup_24bpp(EXYNOS4_GPF3(0), 4, S3C_GPIO_SFN(2), S5P_GPIO_DRVSTR_LV4);
- }
LCD 数据脚初始化,驱动能力设为最高S5P_GPIO_DRVSTR_LV4;管脚驱动能力,S5P_GPIO_DRVSTR_LV1-4四个等级选择。
3、时钟控制部分
kernel/arch/arm/mach-exynos/setup-fb-s5p.c
- int s3cfb_clk_on(struct platform_device *pdev, struct clk **s3cfb_clk)
- {
- struct clk *sclk = NULL;
- struct clk *mout_mpll = NULL;
- struct clk *lcd_clk = NULL;
- u32 rate = 0;
- int ret = 0;
- lcd_clk = clk_get(&pdev->dev, "lcd");
- if (IS_ERR(lcd_clk)) {
- dev_err(&pdev->dev, "failed to get operation clk for fimd\n");
- goto err_clk0;
- }
- ret = clk_enable(lcd_clk);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to clk_enable of lcd clk for fimd\n");
- goto err_clk0;
- }
- clk_put(lcd_clk);
- sclk = clk_get(&pdev->dev, "sclk_fimd");
- if (IS_ERR(sclk)) {
- dev_err(&pdev->dev, "failed to get sclk for fimd\n");
- goto err_clk1;
- }
- if (soc_is_exynos4210())
- mout_mpll = clk_get(&pdev->dev, "mout_mpll");
- else
- mout_mpll = clk_get(&pdev->dev, "mout_mpll_user");
- if (IS_ERR(mout_mpll)) {
- dev_err(&pdev->dev, "failed to get mout_mpll for fimd\n");
- goto err_clk2;
- }
- ret = clk_set_parent(sclk, mout_mpll);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to clk_set_parent for fimd\n");
- goto err_clk2;
- }
- if ((soc_is_exynos4412()) && (samsung_rev() >= EXYNOS4412_REV_2_0))
- ret = clk_set_rate(sclk, 880000000);
- else
- ret = clk_set_rate(sclk, 800000000);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to clk_set_rate of sclk for fimd\n");
- goto err_clk2;
- }
- dev_dbg(&pdev->dev, "set fimd sclk rate to %d\n", rate);
- clk_put(mout_mpll);
- ret = clk_enable(sclk);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to clk_enable of sclk for fimd\n");
- goto err_clk2;
- }
- *s3cfb_clk = sclk;
- return 0;
- err_clk2:
- clk_put(mout_mpll);
- err_clk1:
- clk_put(sclk);
- err_clk0:
- clk_put(lcd_clk);
- return -EINVAL;
- }
- int s3cfb_clk_off(struct platform_device *pdev, struct clk **clk)
- {
- struct clk *lcd_clk = NULL;
- lcd_clk = clk_get(&pdev->dev, "lcd");
- if (IS_ERR(lcd_clk)) {
- printk(KERN_ERR "failed to get ip clk for fimd0\n");
- goto err_clk0;
- }
- clk_disable(lcd_clk);
- clk_put(lcd_clk);
- clk_disable(*clk);
- clk_put(*clk);
- *clk = NULL;
- return 0;
- err_clk0:
- clk_put(lcd_clk);
- return -EINVAL;
- }
- void s3cfb_get_clk_name(char *clk_name)
- {
- strcpy(clk_name, "sclk_fimd");
- }
LCD_LED_EN | LCD电压(TFT电压)使能 | GPC1_2 |
LED_BL_EN | LED背光使能 | GPL2_4 |
- int s3cfb_backlight_on(struct platform_device *pdev)
- {
- int err;
- pwm_set();
- err = gpio_request_one(EXYNOS4_GPL2(4), GPIOF_OUT_INIT_HIGH, "GPL2_4");
- if (err) {
- printk(KERN_ERR "failed to request GPL2 for "
- "lcd backlight control\n");
- return err;
- }
- s3c_gpio_setpull(EXYNOS4_GPL2(4),S3C_GPIO_PULL_NONE);
- gpio_direction_output(EXYNOS4_GPL2(4), 1);
- gpio_free(EXYNOS4_GPL2(4));
- mdelay(20);
- err = gpio_request_one(EXYNOS4_GPC1(2), GPIOF_OUT_INIT_HIGH, "GPC1_2");
- if (err) {
- printk(KERN_ERR "failed to request GPC1 for "
- "lcd backlight control\n");
- return err;
- }
- s3c_gpio_setpull(EXYNOS4_GPC1(2),S3C_GPIO_PULL_NONE);
- gpio_direction_output(EXYNOS4_GPC1(2), 0);
- gpio_free(EXYNOS4_GPC1(2));
- mdelay(20);
- err = gpio_request(EXYNOS4_GPD0(1), "GPD0_1");
- if (err) {
- printk(KERN_ERR "failed to request GPD0_1 for "
- "lcd pwm control\n");
- return err;
- }
- s3c_gpio_setpull(EXYNOS4_GPD0(1),S3C_GPIO_PULL_NONE);
- s5p_gpio_set_drvstr(EXYNOS4_GPD0(1), S5P_GPIO_DRVSTR_LV4);
- gpio_direction_output(EXYNOS4_GPD0(1), 1);
- s3c_gpio_cfgpin(EXYNOS4_GPD0(1), EXYNOS4_GPD_0_1_TOUT_1);
- gpio_free(EXYNOS4_GPD0(1));
- mdelay(20);
- return 0;
- return 0;
- }
- int s3cfb_backlight_off(struct platform_device *pdev)
- {
- int err;
- err = gpio_request_one(EXYNOS4_GPL2(4), GPIOF_OUT_INIT_LOW, "GPL2_4");
- if (err) {
- printk(KERN_ERR "failed to request GPL2 for "
- "lcd backlight control\n");
- return err;
- }
- s3c_gpio_setpull(EXYNOS4_GPL2(4),S3C_GPIO_PULL_NONE);
- gpio_direction_output(EXYNOS4_GPL2(4), 0);
- gpio_free(EXYNOS4_GPL2(4));
- err = gpio_request_one(EXYNOS4_GPC1(2), GPIOF_OUT_INIT_HIGH, "GPC1_2");
- if (err) {
- printk(KERN_ERR "failed to request GPC1 for "
- "lcd backlight control\n");
- return err;
- }
- gpio_free(EXYNOS4_GPC1(2));
- return 0;
- }
5、PWM的设置
arch/arm/mach-exynos/mach-smdk4x12.c
- Arch/arm/mach-exynos/mach-smdk4x12.c
- /* LCD Backlight data */
- static struct samsung_bl_gpio_info smdk4x12_bl_gpio_info = {
- .no = EXYNOS4_GPD0(1),//PWM管脚XpwmTOUT1/LCD_PWM/GPD0_1
- .func = S3C_GPIO_SFN(2),
- };
- static struct platform_pwm_backlight_data smdk4x12_bl_data = {
- .pwm_id = 1,//PWM ID PWM编号为1号;
- .pwm_period_ns = 90000, //22k
- };
- static void __init smdk4x12_machine_init(void)
- {
- ………………
- samsung_bl_set(&smdk4x12_bl_gpio_info, &smdk4x12_bl_data);//在初始化的时候把对应的结构体初始化
- ………………
- }
samsung_bl_set看下这个函数的实现:
kernel/arch/arm/palt-samsung/dev-backlight.c
- void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
- struct platform_pwm_backlight_data *bl_data)
- {
- int ret = 0;
- struct platform_device *samsung_bl_device;
- struct platform_pwm_backlight_data *samsung_bl_data;
- samsung_bl_device = kmemdup(&samsung_dfl_bl_device,
- sizeof(struct platform_device), GFP_KERNEL);//(1)、分配内存空间;
- if (!samsung_bl_device) {
- printk(KERN_ERR "%s: no memory for platform dev\n", __func__);
- return;
- }
- samsung_bl_data = s3c_set_platdata(&samsung_dfl_bl_data,
- sizeof(struct platform_pwm_backlight_data), samsung_bl_device);//(2)、
- if (!samsung_bl_data) {
- printk(KERN_ERR "%s: no memory for platform dev\n", __func__);
- goto err_data;
- }
- /* Copy board specific data provided by user */
- samsung_bl_data->pwm_id = bl_data->pwm_id;//(3)、把具体配置的数据给samsung_bl_data
- samsung_bl_device->dev.parent =
- &s3c_device_timer[samsung_bl_data->pwm_id].dev;
- if (bl_data->max_brightness)//(4)、对bl_data的结构体检查,如果没有复制则用default的值
- samsung_bl_data->max_brightness = bl_data->max_brightness;
- if (bl_data->dft_brightness)
- samsung_bl_data->dft_brightness = bl_data->dft_brightness;
- if (bl_data->lth_brightness)
- samsung_bl_data->lth_brightness = bl_data->lth_brightness;
- if (bl_data->pwm_period_ns)
- samsung_bl_data->pwm_period_ns = bl_data->pwm_period_ns;
- if (bl_data->init)
- samsung_bl_data->init = bl_data->init;
- if (bl_data->notify)
- samsung_bl_data->notify = bl_data->notify;
- if (bl_data->exit)
- samsung_bl_data->exit = bl_data->exit;
- if (bl_data->check_fb)
- samsung_bl_data->check_fb = bl_data->check_fb;
- /* Keep the GPIO info for future use */
- s3c_device_timer[samsung_bl_data->pwm_id].dev.platform_data = gpio_info;
- /* Register the specific PWM timer dev for Backlight control */
- ret = platform_device_register(//(5)、注册PWM设备驱动;
- &s3c_device_timer[samsung_bl_data->pwm_id]);
- if (ret) {
- printk(KERN_ERR "failed to register pwm timer for backlight: %d\n", ret);
- goto err_plat_reg1;
- }
- /* Register the Backlight dev */
- ret = platform_device_register(samsung_bl_device);//(6)、注册背光设备驱动;
- if (ret) {
- printk(KERN_ERR "failed to register backlight device: %d\n", ret);
- goto err_plat_reg2;
- }
- return;
- err_plat_reg2://(7)、如果有异常的情况下退出;
- platform_device_unregister(&s3c_device_timer[samsung_bl_data->pwm_id]);
- err_plat_reg1:
- kfree(samsung_bl_data);
- err_data:
- kfree(samsung_bl_device);
- return;
- }
(1)、分配内存空间
- samsung_bl_device = kmemdup(&samsung_dfl_bl_device,
- sizeof(struct platform_device), GFP_KERNEL);
- 其中:
- static struct platform_pwm_backlight_data samsung_dfl_bl_data = {
- .max_brightness = 255,
- .dft_brightness = 140,
- .pwm_period_ns = 78770,
- .init = samsung_bl_init,
- .exit = samsung_bl_exit,
- };
- static struct platform_device samsung_dfl_bl_device = {
- .name = "pwm-backlight",
- };
(2)、
(3)、把具体配置的数据给samsung_bl_data
- arch/arm/mach-exynos/mach-smdk4x12.c
- static struct samsung_bl_gpio_info smdk4x12_bl_gpio_info = {
- .no = EXYNOS4_GPD0(1),//PWM管脚XpwmTOUT1/LCD_PWM/GPD0_1
- .func = S3C_GPIO_SFN(2),
- };
- static struct platform_pwm_backlight_data smdk4x12_bl_data = {
- .pwm_id = 1,//PWM ID PWM编号为1号;
- .pwm_period_ns = 90000, //22k
- };
(4)、对bl_data的结构体检查,如果没有复制则用default的值
参考(1)中的那些值。
(5)、注册PWM设备驱动;
- ret = platform_device_register(
- &s3c_device_timer[samsung_bl_data->pwm_id]);
- struct platform_device s3c_device_timer[] = {
- [0] = { DEFINE_S3C_TIMER(0, IRQ_TIMER0) },
- [1] = { DEFINE_S3C_TIMER(1, IRQ_TIMER1) },
- [2] = { DEFINE_S3C_TIMER(2, IRQ_TIMER2) },
- [3] = { DEFINE_S3C_TIMER(3, IRQ_TIMER3) },
- [4] = { DEFINE_S3C_TIMER(4, IRQ_TIMER4) },
(6)、注册背光设备驱动;
- ret =platform_device_register(samsung_bl_device);
- samsung_bl_data = s3c_set_platdata(&samsung_dfl_bl_data,
- sizeof(struct platform_pwm_backlight_data), samsung_bl_device);
(7)、如果有异常的情况下退出;
6、PWM_BL背光驱动分析:
Kernel/drivers/video/backlight/pwm_bl.c
(1)、驱动注册:
- static struct platform_driver pwm_backlight_driver = {
- .driver = {
- .name = "pwm-backlight",
- .owner = THIS_MODULE,
- },
- .probe = pwm_backlight_probe,
- .remove = pwm_backlight_remove,
- .suspend = pwm_backlight_suspend,
- .resume = pwm_backlight_resume,
- };
- static int __init pwm_backlight_init(void)
- {
- return platform_driver_register(&pwm_backlight_driver);
- }
(2)、probe函数分析
- static int pwm_backlight_probe(struct platform_device *pdev)
- {
- struct backlight_properties props;
- struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
- struct backlight_device *bl;
- struct pwm_bl_data *pb;
- int ret;
- if (!data) {
- dev_err(&pdev->dev, "failed to find platform data\n");
- return -EINVAL;
- }
- if (data->init) {
- ret = data->init(&pdev->dev);
- if (ret < 0)
- return ret;
- }
- pb = kzalloc(sizeof(*pb), GFP_KERNEL);
- if (!pb) {
- dev_err(&pdev->dev, "no memory for state\n");
- ret = -ENOMEM;
- goto err_alloc;
- }
- global_pb=pb;
- INIT_DELAYED_WORK_DEFERRABLE(&key_event, key_event_work);//1)、任务队列初始化;
- pb->period = data->pwm_period_ns;//2)、pb结构体初始化;
- pb->notify = data->notify;
- pb->check_fb = data->check_fb;
- pb->lth_brightness = data->lth_brightness *
- (data->pwm_period_ns / data->max_brightness);
- pb->dev = &pdev->dev;
- pb->pwm = pwm_request(data->pwm_id, "backlight");
- if (IS_ERR(pb->pwm)) {
- dev_err(&pdev->dev, "unable to request PWM for backlight\n");
- ret = PTR_ERR(pb->pwm);
- goto err_pwm;
- } else
- dev_dbg(&pdev->dev, "got pwm for backlight\n");
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_RAW;
- props.max_brightness = data->max_brightness;
- bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
- &pwm_backlight_ops, &props);
- if (IS_ERR(bl)) {
- dev_err(&pdev->dev, "failed to register backlight\n");
- ret = PTR_ERR(bl);
- goto err_bl;
- }
- global_bl=bl;
- bl->props.brightness = data->dft_brightness;
- backlight_update_status(bl);//3)、更新背光状态;
- platform_set_drvdata(pdev, bl);
- return 0;
- err_bl:
- pwm_free(pb->pwm);
- err_pwm:
- kfree(pb);
- err_alloc:
- if (data->exit)
- data->exit(&pdev->dev);
- return ret;
- }
1)、任务队列初始化;
把key_event_work加入key_event队列,
- INIT_DELAYED_WORK_DEFERRABLE(&key_event, key_event_work);
队列调度函数:
- static void key_event_work(struct work_struct *work)
- {
- global_pb->period=90000;
- global_bl->props.brightness=global_brightness;
- backlight_update_status(global_bl);
- return ;
- }
- static inline void backlight_update_status(struct backlight_device *bd)
- {
- mutex_lock(&bd->update_lock);
- if (bd->ops && bd->ops->update_status)
- bd->ops->update_status(bd);
- mutex_unlock(&bd->update_lock);
- }
update_status在pwm_backlight_ops结构体重指定:
- static const struct backlight_ops pwm_backlight_ops = {
- .update_status = pwm_backlight_update_status,
- …………}
pwm_backlight_update_status我们后面分析,这个其实就是我们PWM设定实现的具体实施过程。
2)、pb结构体初始化;
- pb->period = data->pwm_period_ns; pb->notify = data->notify;
- pb->check_fb = data->check_fb;
- pb->lth_brightness = data->lth_brightness *
- (data->pwm_period_ns / data->max_brightness);
- pb->dev = &pdev->dev;
- pb->pwm = pwm_request(data->pwm_id, "backlight");
3)、更新背光状态
- backlight_update_status(bl);
(4)、PWM_SET
当UI设置PWM时,会调用到驱动中的pwm_set(void)这个函数。这个函数主要在开机时使用。
- int pwm_set(void)
- {
- int error;
- struct backlight_device *bl = global_bl;
- struct pwm_bl_data *pb = global_pb;
- printk("%s__%d\n",__func__,pb->period);
- pb->period=410000;
- backlight_update_status(bl);
- schedule_delayed_work(&key_event, 600); //调用队列,跟新亮度信息;
- return 0;
- }
(5)、pwm_backlight_update_status这个就是PWM变化的具体实现,当应用层调节时,会调用到这个函数,把改变的值填入寄存器。
- static int pwm_backlight_update_status(struct backlight_device *bl)
- {
- struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
- int brightness = bl->props.brightness;
- int max = bl->props.max_brightness;
- //if(brightness==0)
- // return 0;
- //printk("#####%s#%d__%d\n",__func__,pb->period,brightness);
- global_brightness=brightness;
- if (bl->props.power != FB_BLANK_UNBLANK)
- brightness = 0;
- if (bl->props.fb_blank != FB_BLANK_UNBLANK)
- brightness = 0;
- if (pb->notify)
- brightness = pb->notify(pb->dev, brightness);
- if (brightness == 0) {
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
- } else {
- #if 1
- brightness = pb->lth_brightness +
- (brightness * (pb->period - pb->lth_brightness) / max);
- #else
- brightness = pb->lth_brightness +
- (((pb->period - pb->lth_brightness) / max) * brightness );
- #endif
- pwm_config(pb->pwm, brightness, pb->period);//这里对PWM寄存器的具体操作;
- pwm_enable(pb->pwm);
- }
- return 0;
- }
三、LCD UBOOT下的控制(待整理…………)
LCD 在UBOOT下的控制,这部分我们没做过,后面有机会做了再把这部分完善,或者找个机会把代码详细看看。