LCD控制器
《嵌入式Linux应用完全开发手册》第2篇第13章总结归纳
本章目标
- 了解LCD显示器的接口及时序
- 掌握S3C2410/S3C2440LCD控制器的使用方法
- 了解帧缓冲区的概念,掌握如何设置帧缓冲区来显示图像
LCD和LCD控制器
LCD显示器
LCD的种类
LCD(Liquid Crystal Display),即液晶显示器,是一种采用了液晶控制透光度技术来实现色彩的显示器。它与传统的CRT显示器相比有很多优点:轻薄、能耗低、辐射小等,市场占有率越来越大。LCD有很多种类,比如STN、TFT、LTPS TFT、OLED等,各有优缺点。
STN(Super Twisted Nematic,超扭曲向列),有CSTN和DSTN之分,是4种LCD屏中最低端的一种,仅有的优点就是功耗低,在色彩鲜艳度和画面亮度上相对于TFT和其他LCD屏存在明显不足,在日光下几乎不能显示,而且响应时间长达200ms左右,播放动画或视频拖影明显不足。
TFT(Thin Film Transistor,薄膜晶体管)可以大大缩短屏幕响应时间,其响应时间已经小于80ms,并改善了STN连续显示时屏幕闪烁模糊,有效提供了动态画面的播放力,呈现画面色彩饱和度、真实效果和对比度都很不错,完全超越STN,只是功耗稍高,是目前最为主流的液晶显示器类型。在MP3、MP4产品上大量应用,在桌面液晶显示器、笔记本电脑、手机等产品上的应用也非常普遍。
LTPS(Low Temperature Polycrystalline Silicon,低温多晶硅)由TFT衍生的新一代的技术产品,可以获得更高的分辨率和更丰富的色彩。LTPS LCD可以提供170°的水平和垂直可视角度,显示响应仅12ms,显示亮度达到500Cd/m²,对比度可达500:1,这就是一些桌面液晶屏性能越来越出色的原因。虽然LTPS LCD已经出现很多年了,但由于LTPS TFT液晶屏的制造需要高于制造传统TFT屏的技术水平,目前仅有少数知名大厂能制造。
OLED(Organic Light Emitted Diode,有机发光二极管)各种物理特性都具备领先优势,色彩明亮、可视角度超大、非常省电,是未来发展的主流,只是目前受技术与成本限制,未能广泛普及。目前,彩色OLED比较广泛的存在中低端产品中。
LCD的接口
CPU或显卡发出的图像是TTL信号,LCD本身接收的也是TTL信号。但是由于TTL信号高速率的长距离传输性能不佳,抗干扰能力也比较差,后来又提出了多种接口,比如LVDS、TDMS、GVIF、P&D、DVI和DFP等。它们实际上只是将CPU或显卡发出的TTL信号编码成各种信号以便传输,在LCD那边将接收到的信号进行解码得到TTL信号。
由于数字接口标准尚未统一,所以使用LCD时需要根据其手册了解具体接口定义。也是基于数字接口标准尚未统一的原因,市场上大多LCD都采用模拟接口信号,LCD先通过ADC将模拟信号转换为数字信号才能显示。
但是不管采用何种数字接口,本质的TTL信号是一样的。
对于STN LCD
STN LCD 的数据传输方式有3种:4位单扫(4-bit single scan)、4位双扫(4-bit dual scan)、8位单扫(8-bit single scan)。所谓“单扫”是指对于一整屏的数据,从上到下、从左到右,一个一个的发送出来;“双扫”是指将一整屏的数据分为上下两部分,同时从上到下、从左到右,一个一个的发送出来。“4位”、“8位”是指发送数据时使用多少个数据线;需要注意的是,4位双扫方式也是用到8根数据线,其中4根用于上半屏数据,另外4根用于下半屏数据。
除数据信号外,还有其他控制信号,所有TTL信号如下表所示:信号名称 描述 VFRAME 帧同步信号 VLINE 行同步信号 VCLK 像素时钟信号 VD[7:0] 数据信号 VM AV偏置信号 PWREN 电源开关信号 对于TFT LCD
TFT LCD的信号与STN类似,只是其数据信号多达24根,对应像素值的每一位。信号名称 描述 VSYNC 垂直同步信号 HSYNC 水平同步信号 HCLK 像素时钟信号 VD[23:0] 数据信号 LEND 行结束信号 PWREN 电源开关信号
S3C2410/S3C2440 LCD控制器介绍
S3C2410/S3C2440 LCD控制器的特性与结构
S3C2410/S3C2440 LCD控制器被用来向LCD传输图像数据,并提供必要的控制信号,比如VFRAME、VLINE、VCLK、VM等。可以支持STN LCD、TFT LCD,其特性如下(BPP 表示bit per pixel,即每个颜色像素点用多少位来表示)。
STN LCD
- 支持3种扫描方式:4位单扫,4位双扫和8位单扫
- 支持单色(1BPP)、4级灰度(2BPP)、16级灰度屏(4BPP)
- 支持256色(8BPP)和4096色(12BPP)彩色STN屏(CSTN)
- 支持分辨率为640x480、320x240、160x160以及其他规格的多种LCD
- 虚拟屏幕最大可达4MB
- 对于256色,分辨率有4094x1024、2048x2048、1024x4096等多种
TFT LCD
- 支持单色(1BPP)、4级灰度(2BPP)、16级灰度(4BPP)、256色(8BPP)的调色板显示模式
- 支持64K(16BPP)和16M(24BPP)色非调色板显示模式
- 支持分辨率为640x480、320x320及其他多种规格的LCD
- 虚拟屏幕最大可达4MB
- 对于64K色,分辨率有2048x1024等多种
S3C2410/S3C2440 LCD控制器提供了驱动STN LCD、TFT LCD所需的所有信号,另外,还特别提供额外的信号以支持SEC公司生产的TFT LCD。这3类信号中很大部分是复用的。
S3C2410/S3C2440 LCD控制器的内部结构如下图所示:
REGBANK是LCD控制器的寄存器组,含17个寄存器及一块256x16的调色板内存,用来设置各项参数。而LCDCDMA则是LCD控制器专用的DMA通道,可以自动地从系统总线(System Bus)上取到图像数据,这使得显示图像时不需要CPU的干涉。VIDPRCS将LCDCDMA中的数据组合成特定的格式,然后从VD[23:0]发送给LCD屏。同时TIMEGEN和LPC3600负责产生LCD屏所需要的控制时序,例如VSYNC、HSYNC、VCLK、VDEN,然后从VIDEO MUX送给LCD屏。其中LPC3600专用于SEC TFT LCD。
LCDCDMA中有2个FIFO:FIFOH容量为16(1个字为4个字节)个字,FIFOL容量为12个字。当使用“双扫”方式时,FIFOH、FIFIL分别用于传输上半屏、下班屏数据;当使用“单扫”方式时,只用到FIFOH。当FIFO为空或者其中的数据已经减少到设定的阈值时,LCDCDMA自动的发起DMA传输从内存中获得图像数据。
显示器上数据的组织格式
一幅图像被称为一帧,每帧由多行组成,每行由多个像素组成,每个像素的颜色用若干位的数据表示。对于单色显示器,每个像素用1位来表示,称为1BPP,对于256色显示器,每个像素使用8位来表示,称为8BPP。
显示器从屏幕的左上方开始,一行一行的取得每个像素的数据并显示出来,当显示当一行的最右边时,跳到下一行的最左边开始显示下一行;当显示完所有行后,跳到左上方开始显示下一帧。显示器沿着“Z”字行的路线进行扫描,使用HSYNC、VSYNC信号来控制扫描路线的跳转。HSYNC表示“是时候跳到最左边了”,VSYNC表示“是时候跳到最上边了”。
在工作中的显示器上,可以在四周看到黑色的边框。上方的黑框是因为显示完所有行的数据时,显示器还没有扫描到最下边(VSYNC信号还未发出),这时数据已经无效。左边的黑框是因为当发出HSYNC信号时,需要经过若干像素之后第一列数据才有效;右边的黑框是因为显示完一行的数据时,显示器还每扫描到最右边(HSYNC信号还没有发出),这时数据已经无效。显示器只会依据VSYNC、HSYNC信号来取得、显示数据,并不理会该数据是否有效,何时发出有效数据由显卡决定。
VSYNC信号出现的频率表示1秒内能显示多少帧的图像,称为垂直频率或者场频率,这就是我们常说的“显示器的频率”;HSYNC信号出现的频率称为水平频率。
显示器上,一帧数据的存放位置与VSYNC、HSYNC信号的关系如下图所示:
有效数据的行数、列数即分辨率,它与VSYNC、HSYNC信号之间的“距离”等,都是可以设置的,这由显卡完成。
TFT LCD的操作
目前市场上主流的LCD为TFT LCD,先了解TFT LCD的时序,这使得我们在设置各个寄存器时有个形象的概念。每个VSYNC信号表示一帧数据的开始;每个HSYNC信号表示一行数据的开始,无论这些数据是否有效;每个VCLK信号表示正在传输一个像素的数据,无论它是否有效。数据是否有效只是对CPU的LCD控制器来说的,LCD根据VSYNC、HSYNC、VCLK不停的读取总线数据、显示。
- VSYNC信号有效时,表示一帧数据的开始。
- VSPW表示VSYNC信号的脉冲宽度为(VSPW + 1)个HSYNC信号周期,即(VSPW + 1)行,这(VSPW + 1)行数据无效。
- VSYNC信号脉冲之后,还要经过(VBPD + 1)个HSYNC信号周期,有效的行数据才出现。所以在VSYNC信号有效之后,总共还要经过(VSPW + 1 + VBPD + 1)个无效的行,它对应图13.2上方的边框,第一个有效的行才出现。
- 随后即连续发出(LINEVAL + 1)行的有效数据。
- 最后是(VFPD + 1)个无效的行,它对应图13.2下方的边框,完整的一帧结束,紧接着就是下一帧的数据了(即下一个VSYNC信号)。
现在深入到一行像素的传输过程。类似于行数据的传输过程。
- HSYNC信号有效时,表示一行数据的开始。
- HSPW表示HSYNC信号的脉冲宽度为(HSPW + 1)个VCLK信号周期,即(HSPW + 1)个像素,这(HSPW + 1)个像素的数据无效。
- HSYNC信号脉冲无效之后,还要经过(HBPD + 1)个VCLK信号周期,有效的像素数据才出现。所以,在HSYNC信号有效之后,总共还要经过(HSPW + 1 + HBPD + 1)个无效的像素,它对应图13.2的左边框,第一个有效像素才出现。
- 随后即连续发出(HOZVAL + 1)个像素的有效数据。
- 最后是(HFPD + 1)个无效的像素,它对应图13.2的右边框,完整的一行结束,紧接着就是下一行的数据了(即下一个HSYNC信号)。
时序图中各信号的时间参数都可以在LCD控制寄存器中设置,VCLK作为时序图的基准信号,它的频率可由此计算:
1 | VCLK(hz) = HCLK / [(CLKVAL + 1 x 2)] |
VSYNC信号的频率又称为帧频率、垂直频率、场频率、显示器的频率,它可以如下计算:
1 | Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LINEVAL+1)+(VFPD+1)} x { (HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1) } x { 2 x ( CLKVAL+1) / (HCLK)}] |
将VSYNC、HSYNC、VCLK等信号的时间参数设置好之后,并将帧内存(frame memory)的地址告诉LCD控制器,它即可自动发起DMA传输从帧内存得到图像数据,最终在上述信号的控制下出现在数据总线VD[23:0]上。用户只需要把要显示的图像数据写入帧内存中。
下面介绍各种图像的格式数据在内存中如何存储。
显示器上的每个像素的颜色都是由3个部分组成:红、绿、蓝。它们被称为三原色,这三者的混合几乎可以表示人眼所能识别到的所有颜色。比如可以根据颜色的浓烈程度将三原色都分为256个级别(0-255)。可以使用255级的红色、255级的绿色、255级的蓝色可以组成白色。0级的红色、0级的绿色、0级的蓝色可以组成黑色。
LCD控制器可以支持单色(1BPP)、4级灰度(2BPP)、16级灰度(8BPP)、256色(8BPP)的调色板显示模式,支持64K(16BPP)和16M(24BPP)非调色板显示模式。下面只介绍256色(8pp)、64K(16BPP)和16M(24BPP)色显示模式下,图像数据的存储格式。
- 16M(24BPP)色
16M(24BPP)色的显示模式就是使用24位的数据来表示一个像素的颜色,每种原色使用8位。LCD控制器从内存中获得某个像素的24位颜色值后,直接通过VD[23:0]数据线发送给LCD。为了方便DMA传输,在内存中使用4个字节(32)位来表示一个像素,其中的3个字节从高到低分别表示红、绿、蓝,剩余的1个字节数据无效。是最低字节还是最高字节无效,这时可以选择的。 - 64K(16BPP)色
64K(16BPP)色的显示模式就是使用16位的数据来表示一个像素的颜色。这16位数据的格式又分为两种:5:6:5、5:5:5:1,前者使用高5位来表示红色,中间的6位来表示绿色,低5位来表示蓝色;后者的高15位从高到低分成3个5位来表示红色、绿色、蓝色,最低位表示透明度。5:5:5:1的格式也被称为RGBA(A表示Alpha,指代透明度)。
一个4字节可以表示两个16BPP的像素,使用高2字节还是低2字节来表示第一个像素,这也是可以选择的。
显示模式为16BPP时,内存数据与像素位置的关系如图所示:
在5:5:5:1的格式下,VD[18]、VD[10]、VD[2]数据线上的值是一样的,都表示透明度。图中的NC表示没有连接(not connect)。 - 256(8BPP)色
256(8BPP)色的显示模式就是使用8位的数据来表示一个像素的颜色,但是对三种原色平均下来,每个原色只能使用不到3位的数据来表示,即每个原色最多不过8个级别,这不足以表示更丰富的颜色。
为了解决8BPP模式显示能力太弱的问题,需要使用调色板。每个像素对应8位数据不再用来表示RGB三原色,而是表示它在调色板中的索引值;要显示这个像素时,使用这个索引值从调色板中取得其RGB颜色值。所谓调色板就是一块内存,可以对每个索引值设置其颜色,可以使用24BPP或16BPP。S3C2410/S3C2440中,调色板是一块256x16的内存,使用16BPP的格式来表示256色(8BPP)显示模式下各个索引值的颜色。这样即使使用256色(8BPP)的显示模式,最终在LCD数据总线上的仍是16BPP的数据。
一个4字节可以表示4个8BPP的像素,字节与像素的对应顺序是可以选择的,如下图所示:
调色板中数据的存放格式与16BPP显示模式类似,也分为两种:5:6:5、5:5:5:1。调色板中数据的格式及与LCD数据线VD[23:0]的对应关系,如下表所示:
5:6:5格式下调色板的数据格式
序号 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 地址 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
00H | R4 | R3 | R2 | R1 | R0 | G5 | G4 | G3 | G2 | G1 | G0 | B4 | B3 | B2 | B1 | B0 | 0X4D000400 |
01H | R4 | R3 | R2 | R1 | R0 | G5 | G4 | G3 | G2 | G1 | G0 | B4 | B3 | B2 | B1 | B0 | 0X4D000404 |
… … | … … | ||||||||||||||||
FFH | R4 | R3 | R2 | R1 | R0 | G5 | G4 | G3 | G2 | G1 | G0 | B4 | B3 | B2 | B1 | B0 | 0X4D0007FC |
VD引脚号 | 23 | 22 | 21 | 20 | 19 | 15 | 14 | 13 | 12 | 11 | 10 | 7 | 6 | 5 | 4 | 3 |
5:5:5:1格式下调色板的数据格式
序号 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 地址 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
00H | R4 | R3 | R2 | R1 | R0 | G4 | G3 | G2 | G1 | G0 | B4 | B3 | B2 | B1 | B0 | – | 0X4D000400 |
01H | R4 | R3 | R2 | R1 | R0 | G4 | G3 | G2 | G1 | G0 | B4 | B3 | B2 | B1 | B0 | – | 0X4D000404 |
… … | … … | ||||||||||||||||
FFH | R4 | R3 | R2 | R1 | R0 | G4 | G3 | G2 | G1 | G0 | B4 | B3 | B2 | B1 | B0 | – | 0X4D0007FC |
VD引脚号 | 23 | 22 | 21 | 20 | 19 | 15 | 14 | 13 | 12 | 11 | 7 | 6 | 5 | 4 | 3 | 2 | |
注: | |||||||||||||||||
①0X4D000400是调色板的起始地址。 | |||||||||||||||||
②5:5:5:1格式下,VD18、VD10和VD2三个数据线中都是亮度值1,即最低位的值。 | |||||||||||||||||
③当LCDCCON5寄存器中的VSTATUS、HSTATUS有效时,不能读写调色板。 |
各模式下用来传输红、绿、蓝三种原色的颜色值VD数据线如下表所示:
24BPP | 16BPP/8BPP 5:6:5格式 | 16BPP/8BPP 5:5:5:1格式 |
---|---|---|
红色 | VD[23:16] | VD[23:19] |
绿色 | VD[15:8] | VD[15:10] |
蓝色 | VD[7:0] | VD[7:3] |
没有用到的数据线其电平为0,从这个观点来看,无论是24BPP模式还是16BPP、8BPP模式,24根数据线VD[23:0]都被用到了。事实上,一个TFT LCD能处理的像素位宽是固定的,即它的数据线的数目是固定的。红、绿、蓝3类信号线总是连接到各字节中的高位;软件设置24BPP、16BPP、8BPP以及调色板等,只会影响到色值的精度。
使用TFT LCD时LCD控制器的寄存器设置
LCD控制器中REGBANK的17个寄存器可以分为6种,如下表所示:
名称 | 说明 |
---|---|
LCDCON1-LCDCON5 | 用于选择LCD类型,设置各类控制信号的时间特性等 |
LCDSADDR1-LCDSADDR3 | 用于设置帧内存的地址 |
TPAL | 临时调色板寄存器,可以快速的输出一帧单色的图像 |
LCDINTPND LCDSRCPND LCDINTMSK |
用于LCD的中断,在一般应用中无需中断 |
REDLUT GREENLUT BLUELUT DITHMODE |
专用于STNLCD |
TCONSEL | 专用于SEC TFT LCD |
对于TFT LCD,一般情况下只需要设置前两种寄存器;在8BPP模式下,如果想快速的输出一帧单色图,可以借助TPAL寄存器。
LCD控制寄存器LCDCON1
用于选择LCD类型、设置像素时钟、使能LCD信号的输出等,格式如下表:功能 位 说明 LINECNT [27:18] 只读,每输出一个有效行其值减一,从LINEVAL减到0 CLKVAL [17:8] 用于设置VCLK(时钟)
对于TFT LCD,VCLK = HCLK / [(CLKVAL + 1) x 2](CLKVAL >= 0)MMODE [7] 设置VM信号的反转效率,用于STN LCD PNRMODE [6:5] 设置LCD的类型,对于TFT LCD 设为0b11 BPPMODE [4:1] 设置BPP,对于TFT LCD:
0b1000 = 1bpp
0b1001 = 2bpp
0b1010 = 4bpp
0b1011 = 8bpp
0b1100 = 16bpp
0b1101 = 24bppENVID [0] LCD信号输出使能位,0:禁止,1:使能 LCD控制寄存器LCDCON2
用于设置垂直方向各信号的时间参数,格式如下表:功能 位 说明 VBPD [31:24] VSYNC信号脉冲之后,还要经过(VBPD + 1)个HSYNC信号周期,有效的行数据才出现 LINEVAL [23:14] LCD的垂直宽度:(LINEVAL + 1)行 VFPD [13:6] 一帧中的有效行数据完结后,到下一个VSYNC信号有效前的无效行数目:VFPD + 1 VSPW [5:0] 表示VSYNC信号的脉冲宽度为(VSPW + 1)个HSYNC信号周期,即(VSPW + 1)行,这(VSPW + 1)行的数据无效 LCD控制器LCDCON3
用于设置水平方向信号的时间参数,格式如下表所示:功能 位 说明 HBPD [25:19] HSYNC信号脉冲之后,还要经过(HBPD + 1)个VCLK信号周期,有效的行数据才出现 HOZVAL [18:8] LCD的水平宽度:(HOZVAL + 1)列(像素点) HFPD [7:0] 一行中的有效数据完结后,到下一个HSYNC信号有效前的无效像素数目:HFPD + 1 LCD控制寄存器LCDCON4
对于TFT LCD,这个寄存器只用来设置HSYNC信号的脉冲宽度,位[7:0]的数值称为HSPW,表示脉冲宽度为(HSPW + 1)个VCLK周期。LCD控制寄存器LCDCON5
用于设置各个控制信号的极性,并可以从中读到一些状态信息。如下表所示:功能 位 说明 VSTATUS [16:15] 只读,垂直状态。
00:正处于VSYNC信号脉冲期间
01:正处于VSYNC信号结束到行有效期间
10:正处于行有效期间
11:正处于行有效结束到下一个VSYNC之间HSTATUS [14:13] 只读,水平状态。
00:正处于HSYNC信号脉冲期间
01:正处于HSYNC信号结束到像素有效期间
10:正处于像素有效期间
11:正处于像素有效结束到下一个HSYNC之间BPP24BL [12] 设置TFT LCD的显示模式为24BPP时,一个4字节中哪3个字节有效。
0:LSB有效(低地址的3字节);1:MSB(高地址的3字节);FRM565 [11] 设置TFT LCD的显示模式为16BPP时,使用的数据格式。
0表示5:5:5:1格式;1表示5:6:5 格式INVVCLK [10] 设置VCLK信号有效沿的极性。
0:在VCLK的下降沿读取数据;1:在VCLK的上升沿读取数据。INVVLINE [9] 设置VLINE/HSYNC脉冲的极性。
0:正常的极性;1:反转的极性INVVFRAME [8] 设置VFRAME/VSYNC脉冲的极性。
0:正常的极性;1:反转的极性INVVD [7] 设置VD数据线表示数据(0/1)的极性。
0:正常的极性;1:反转的极性INVVDEN [6] 设置VDEN信号的极性。
0:正常的极性;1:反转的极性INVPWREN [5] 设置PWREN信号的极性。
0:正常的极性;1:反转的极性INVLEND [4] 设置LEND信号的极性。
0:正常的极性;1:反转的极性PWREN [3] LCD_PWREN信号输出使能。
0:禁止;1:输出ENLEND [2] LEND信号输出使能。
0:禁止;1:输出BSWP [1] 字节交换使能
0:禁止;1:输出HWSWP [1] 半字(2字节)交换使能
0:禁止;1:输出帧内存地址寄存器LCDSADDR1-LCDSADDR3
帧内存可以很大,而真正要显示的区域被称为视口(view point),它处于帧内存之内。这3个寄存器用于确定帧内存的起始地址,定位视口在帧内存的位置。下图给出了帧内存和视口之间的关系:
各寄存器格式如下表所示:
LCDSADDR1 功能 | 位 | 说明 |
---|---|---|
LCDBANK | [29:21] | 用来保存帧内存起始地址A[30:22],帧内存起始地址为4MB对齐。 |
LCDBASEU | [20:0] | 对于TFT LCD,用来保存视口(view point),所对应的内存起始地址A[21:1],这块内存地址也称为LCD的帧缓冲区(frame buffer) |
LCDSADDR2 功能 | 位 | 说明 |
---|---|---|
LCDBASEL | [20:0] | 对于TFT LCD,用来保存LCD的帧缓冲区结束地址A[21:1],其值可如下计算:LCDBASEL = LCDBASEU + (PAGEWIDTH + OFFSICE)x (LINEVAL + 1) |
注:可以修改LCDBASEU、LCDBASEL的值来实现图像的移动,不过不能在一帧图像的结束阶段(LCDCON1寄存器的LINECNT为0时)进行修改,因为此时LCD控制器会优先取得下一帧的数据,之后才会改变这些值,这样的话,这些数据就与新的帧缓冲区不一致。
LCDSADDR3 功能 | 位 | 说明 |
---|---|---|
OFFSIZE | [21:11] | 表示上一行最后一个数据与下一行第一个数据间地址差值的一半,即以半字为单位的地址差(0表示两行数据是紧接着的,1表示它们之间相差2个字节,依次类推) |
PAGEWIDTH | [10:0] | 视口的宽带,以半字为单位 |
注:OFFSIZE、PAGEWIDTH的值只能在ENVID(LCDCON1寄存器的信号输出使能)为0时修改。
- 临时调色板寄存器TPAL
如果要输出一帧单色的图像,可以在TPAL寄存器中设定这个颜色值,然后使能TPAL寄存器,这种方法可以避免修改整个调色板或帧缓冲区。TPAL寄存器格式如下表所示:功能 位 说明 TPALEN [24] 调色板寄存器使能位。
0:禁止 1:使能TPALVAL [23:0] 颜色值。
TPALVAL[23:16]:红色
TPALVAL[15:8]:绿色
TPALVAL[7:0]:蓝色
注:临时调色板寄存器TPAL可以用在任何显示模式下,并非只能用在8BPP模式下。
TFT LCD显示实例
程序设计
本实例的目的是从串口输出一个菜单,从中选择各种方法进行测试,比如画线、画圆、显示单色、使用调色板等。
代码设计
与LCD相关的文件有3个:lcddrv.c、framebuffer.c和lcdlib.c(及相应的头文件)。
- lcddrv.c封装了对LCD控制器、调色板的访问函数,可以设置LCD的显示模式、开启/关闭LCD、设置调色板等。
- framebuffer.c直接操作帧缓冲区(frame buffer),实现了画点、画线、画圆、清屏等操作。
- lcdlib.c调用前两个文件提供的函数在LCD上进行各种操作。
main.c
1 | switch(getc()) |
它根据串口的输入选择是以”240x320、8bpp“、”240x320、16bpp“、”640x480、8bpp“或”640x480、16bpp“的显示模式来操作LCD,所调用的4个函数都在lcdlib.c中实现。
lcdlib.c
8BPP模式将用到调色板,其操作比16BPP模式稍为复杂,但是大部分仍是相似的。下面以Test_Lcd_Tft_8Bit_240320()
为例进行说明:
1 | /* |
第6行所涉及的GPIO引脚用于LCD功能。
第7行调用Tft_Lcd_Init函数初始化LCD控制器,即设置各个控制信号的时间特性、设置LCD的显示模式、设置帧缓冲区的地址等,它是lcddrv.c中最复杂的函数,在后面会详细分析这个函数。
进行第6、7行的初始化之后,只要打开LCD,帧缓冲区中的数据就会被LCD控制器自动地发送到LCD上去显示。打开操作由8、9行来完成。
第8行发出LCD_PWREN信号。对于有电源开关控制引脚的LCD,可以使用LCD_PWREN来打开或关闭LCD。LCD_PWREN信号的极性可以设置。
第9行使能LCD控制器输出信号,这时,帧缓冲区中的数据就开始在LCD上显示出来了。
接下来就是按照设定的流程进行各类操作了,比如画线、清屏等,代码如下:
1 | Lcd_Palette8Bit_Init(); //初始化调色板 |
上述函数分3类:
- 清屏函数ClearScr、画线函数DrawLine,都是通过framebuffer.c中的PutPixel函数来设置帧缓冲区中的数据,以像素为单位修改颜色来实现的。
- Lcd_Palette8Bit_Init函数设置调色板,ChangePalette函数通过设置调色板来实现清屏功能,不涉及帧缓冲区,它在lcddrv.c中实现。
- ClearScrWithTmpPlt函数则是通过临时调色板寄存器来快速的输出单色的图像,也不涉及帧缓冲区,它在lcddrv.c中实现。
lcddrv.c、framebuffer.c文件中的各个函数才是本实例的关键。可以认为lcddrv.c是对操作各寄存器的封装,framebuffer.c则是对操作图像数据的封装。先看lcddrv.c文件。
lcddrv.c
这个文件的重点在于Tft_Lcd_Init、Lcd_Palette8Bit_Init。
Lcd_Port_Init函数
设置所涉及的GPIO引脚用于LCD功能。GPIO功能的设置对读者来说已经很熟悉了,不再赘述。Tft_Lcd_Init函数
用于初始化LCD控制器,即设置各个控制信号的时间特性、设置LCD的显示模式、设置帧缓冲区的地址等。
首先是对5个控制寄存器LCDCON1-LCDCON5的设置,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38/*
初始化LCD控制器
输入参数:
type:显示模式
MODE_TFT_8BIT_240320 : 240*320 8bpp 的TFT LCD
MODE_TFT_16BIT_240320 : 240*320 16bpp 的TFT LCD
MODE_TFT_8BIT_640480 : 640*480 8bpp 的TFT LCD
MODE_TFT_16BIT_640480 : 640*480 16bpp 的TFT LCD
*/
void Tft_Lcd_Init(int type)
{
switch(type)
{
case MODE_TFT_8BIT_240320:
/*
设置LCD控制器的控制寄存器LCDCON1-LCDCON5
1. LCDCON1
设置VCLK的频率:VCLK(Hz)= HCLK/[(CLKVAL+1)x2]
选择LCD类型:TFT LCD
设置显示模式:8BPP
先禁止LCD信号输出
2. LCDCON2/3/4
设置控制信号的时间参数
设置分辨率,即行数及列数
现在,可以根据公式计算出显示器的频率
当HCLK = 100MHz时,
Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LINEVAL+1)+(VFPD+1)} x { (HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1) } x { 2 x ( CLKVAL+1) / (HCLK)}] = 60Hz
3. LCDCON5
设置显示模式为8BPP时,调色板中的数据格式为5:6:5
设置HSYNC、VSYNC脉冲的极性:反转字节交换使能
*/
LCDCON1 = (CLKVAL_TFT_240320 << 8) | (LCDTYPE_TFT << 5) | (BPPMODE_8BPP << 1) | (ENVID_DISABLE << 0);
LCDCON2 = (VBPD_240320 << 24) | (LINEVAL_TFT_240320 << 14) | (VFPD_240320 << 6) | (VSPW_240320);
LCDCON3 = (HBPD_240320 << 19) | (HOZVAL_TFT_240320 << 8) | (HFPD_240320);
LCDCON4 = (HSPW_240320);
LCDCON5 = (FORMAT8BPP_565 << 11) | (HSYNC_INV << 9) | (VSYNC_INV << 8) | (BSWP << 1);
}
}代码中的注释可以帮助读者理解这些代码,比较困难的是时间参数VSPW、VBPD、VFPD、HSPW、HBPD、HFPD、CLKVAL的设置。对于CRT显示器,当它的频率在60Hz时,人眼会感到明显的闪烁;而对于LCD,在60Hz时显示效果就很好。
1
Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LINEVAL+1)+(VFPD+1)} x { (HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1) } x { 2 x ( CLKVAL+1) / (HCLK)}];
接下来是对地址寄存器LCDSADDR1-LCDSADDR3的设置。本程序中,帧内存与视图吻合,即图中的OFFSIZE为0,LCDBANK、LCDBASEU指向同一个地址(同一地址的不同位)。
需要注意的是,8BPP的显示模式要用到调色板,帧缓冲区中的数据不是像素的颜色值,而是调色板中的索引值,真正的颜色值在调色板中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/*
设置LCD控制器的地址寄存器LCDSADDR1-LCDSADDR3
帧内存与视口(view point)完全吻合,
图像数据格式如下(8BPP时,帧缓存区中的数据为调色板中的索引值):
|----width----|
y/x 0 1 2 239
0 idx idx idx idx
1 idx idx idx idx
1. LCDSADDR1
设置LCDBANK、LCDBASEU
2. LCDSADDR2
设置LCDBASEL:帧缓冲区的结束地址A[21:1]
3. LCDSADDR3
OFFSIZE等于0,PAGEWIDTH等于(240/2)
*/
LCDSADDR1 = ((LCDFRAMEBUFFER >> 22) << 21) | LOWER21BITS(LCDFRAMEBUFFER >> 1);
LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER + (LINEVAL_TFT_240320 + 1) x (HOZVAL_TFT_240320+1) x1) >> 1);
LCDSADDR3 = (0 <<11 ) | (LCD_XSIZE_TFT_240320/2);第16行将帧缓冲区的起始地址写入LCDSADDR1寄存器。
第17行先计算帧缓冲区的结束地址,再取其位[21:1]存入LCDSADDR2中。这个地址值在本实例中即是“LCDFRAMEBUFFER + 320 x 240 x 1”,其中的“x1”表示在8BPP中一个像素使用1个字节来表示(对于16BPP,则是“x2”)。
在设置寄存器的最后,禁止临时调色板寄存器,现在还没有用到它。1
2/*禁止临时调色板寄存器*/
TPAL = 0;最后,将显示模式的主要参数记录下来,在framebuffer.c中需要用到。
1
2
3
4fb_base_addr = LCDFRAMEBUFFER;
bpp = 8;
xsize = 240;
ysize = 320;需要说明的是,显示模式为8BPP时,LCDCON5中BSWAP位设为1,表示“字节交换使能”,这时帧缓存区中的数据与屏幕上的像素位置关系如上图13.6所示;显示模式为16BPP时,LCDCON5中HWSWAP位设为1,表示“半字交换使能”,这时帧缓冲区的数据与屏幕上的像素位置关系如图13.5所示。他们都是“低地址的数据”对应“位置靠前”的像素。
Lcd_Palette8Bit_Init函数
设置调色板中的数据:调试板大小为256x16,而8BPP模式中每个像素的索引值占据8位,刚好有256个索引值。代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14/*
设置调色板
*/
void Lcd_Palette8Bit_Init(void)
{
int i;
volatile unsigned int *palette;
LCDCON5 |= (FORMAT8BPP_565 << 11); //设置调色板中数据格式为5:6:5
palette = (volatile unsigned int *)PALETTE;
for(i = 0;i < 256;i++)
*palette++ = DEMO256pal[i];
}调色板中用16BPP的格式来表示颜色,第9行设置调色板中数据的格式为5:6:5。
第12、13行将数组DEMO256pal中的数据写入调色板中。ChangePalette函数
以给定的颜色填充整个调色板。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24/*
改变调色板为一种颜色
输入参数:
color:颜色值,格式为0xRRGGBB
*/
void ChangePalette(UINT32 color)
{
int i;
unsigned char red,green,blue;
UNT32 *palette;
palette = (UINT32 *)PALETTE;
for(i = 0;i < 256;i++)
{
red = (color >> 19) & 0xff;
green = (color >> 10) & 0xff;
blue = (color >> 3) & 0xff;
color = (red << 11) | (greee << 5) | (blue); //格式5:6:5
while((LCDCON5 >> 16) == 2); //等待直到VSTATUS不为“有效”
*palette++ = color;
}
}第15-19行从0xRRGGBB格式的变量中,提取8位红色值的高5位,8位绿色值的高6位,8位蓝色值的高5位组成5:6:5格式的16BPP颜色值。
第21行检测当前VSYNC信号的状态,如果它处于有效的状态,则等待。前面说过,读写调色板时,VSTATUS、HSTATUS不能处于有效状态。这里当VSTATUS不是“有效”状态时,HSTATUS也不能是“有效”状态。
第22行将新数据写入调色板。Lcd_PowerEnable函数
用于是否控制发出LCD_PWREN信号。对于有电源开关控制引脚的LCD,可以使用LCD_PWREN来打开或关闭LCD。LCD_PWREN信号的极性可以设置。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/*
设置是否输出LCD电源开关信号LCD_PWREN
输入参数:
invpwren:
0表示LCD_PWREN有效时为正常极性
1表示LCD_PWREN有效时为反转极性
pwren:
0表示LCD_PWREN输出有效
1表示LCD_PWREN输出无效
*/
void Lcd_PowerEnable(int invpwren,int pwren)
{
GPGCON = (GPGCON & (~ (3 << 8))) | (3 << 8); //GPG4用作LCD_PWREN
GPGUP = (GPGUP & (~ (1 << 4))) | (1 << 4); //禁止内部上拉
LCDCON5 = (LCDCON5 & (~ (1 << 5))) | (invpwrwen << 5); //设置LCD_PWREN的极性:正常/反转
LCDCON5 = (LCDCON5 & (~ (1 << 3))) | (pwren << 3); //设置是否输出LCD_PWREN
}Lcd_EnvidOnOff函数
用于控制是否使能LCD控制器输出各个LCD信号,当设置如控制寄存器、地址寄存器之后,即可调用此函数输出各个LCD信号,这样,帧缓冲区中的数据即发送给LCD。1
2
3
4
5
6
7
8
9
10
11
12
13
14/*
设置LCD控制器是否输出信号
输入参数:
onoff:
0:关闭
1:打开
*/
void Lcd_EnvidOnOff(int onoff)
{
if(onoff == 1)
LCDCON1 |= 1; //ENVID ON
else
LCDCON1 &= 0x3fffe; //ENVID OFF
}ClearScrWithTmpPlt、DisableTmpPlt函数
ClearScrWithTmpPlt函数设置颜色值并使能TPAL寄存器,这使得LCD上显示单一颜色的图像。DisableTmpPlt函数停止TPAL寄存器的功能,继续输出帧缓存区的图像。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19/*
使用临时调色板寄存器输出单色图像
输入参数:
color:颜色值,格式为0xRRGGBB
*/
void ClearScrWithTmpPlt(UINT32 color)
{
TPAL = (1 << 24) | ((color & 0xffffff) << 0);
}
/*
停止使用临时调色板寄存器
*/
void DisableTmpPlt(void)
{
TPAL = 0;
}
framebuffer.c
此文件中有4个函数:画点函数PutPixel、画线函数DrawLine、绘制同心圆函数Mire、清屏函数ClearScr。后3个函数都是基于PutPixel函数实现的。PutPixel函数是framebuffer.c的核心,它在缓冲区中找到给定坐标的像素的内存,然后修改它的值。
1 | extern unsigned int fb_base_addr; |
第1-4行的4个变量在lcddrv.c中的Tft_Lcd_Init函数中设置,PutPixel函数根据它们来确定给定坐标的像素在缓冲区中的地址。
第22、34行分别计算16BPP、8BPP模式下给定坐标的像素在帧缓冲中的地址。对于16BPP模式,每个像素占据2字节;对于8BPP模式,每个像素占据1字节。
对于16BPP的显示模式,第22-25行从0xAARRGGBB中提取8位红色值的高5位,8位绿色值的高6位,8位蓝色值的高5位组成5:6:5格式的16BPP颜色值。
最后,第28、35行将颜色值(8BPP模式下为调色板索引值)写入帧缓冲区中,这样下一次显示的时候,新颜色就可以显示出来了。