欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

LCD

程序员文章站 2022-03-04 18:23:04
...

注意:本资料来源于朱友鹏老师的课程的视频,只用于学习使用,如用于其他用途,请联系朱老师本人,不然后果自负,不允许转载!!!

LCD的接口技术

从电平角度来讲本质上都是TTL信号

(1)什么是TTL接口。+5V表示逻辑1,0V表示逻辑0.这种就叫TTL电平,和CMOS电平相对比。
(2)SoC的LCD控制器硬件接口是TTL电平的,LCD这边硬件接口也是TTL电平的。所以他们俩本来是可以直接对接的,手机、平板、开发板都是这样直接对接的(一般用软排线连接)。
(3)TTL电平的缺陷就是不能传递太远,如果LCD屏幕和主板控制器太远(1米甚至更远)就不能直接TTL连接了,要进行转换。转换方式:主机So(TTL) ->VGA-> LCD屏幕(TTL)

RGB接口详解(参考数据手册P1207页时序图)

(1)VD[23:0]:24根数据线,用来传输图像信息。可见LCD是并行接口,速率才够快。
(2)HSYNC(水平同步信号)
(3)VSYNC(垂直同步信号):时序信号线,为了让LCD能够正常显示给的控制信号
(4)VCLK(像素时钟):LCD工作时需要主板控制器给LCD模组一个工作时钟信号,就是VCLK。
(5)VDEN(数据有效标志):时序信号,和HSYNC、VSYNC结合使用。
(6)LEND(行结束标志,不是必须的):时序信号,非必须,譬如X210接口就没有。

图像是由像素组成的,每个像素由三种组成,红-绿-蓝

显存的概念

1.显存就是图像的信息存储的那块内存,这个是由程序员来制定的,通过配置LCD控制器和内存的映射,从而使改变内存就可以改变图像的,一旦这个关系建立之后,LCD控制器就会自动从显存中读取像素数据传输给LCD驱动器。这个显示的过程不需要CPU的参与。
2显示体系建立起来后,CPU就不用再管LCD控制器、驱动器、面板这些东西了;以后CPU就只关心显存了,因为我只要把要显示的图像的像素数据丢到显存中,硬件就会自动响应(屏幕上就能自动看到显示的图像了)。

LCD的六个主要时序参数

LCD显示单位:帧(frame)

(1)显示器上一整个画面的内容成为一个帧(frame),整个显示器工作时是一帧一帧的在显示。
(2)电影实际就是以每秒种24帧的速度在播放图片。
(3)帧内数据:一帧分为多行,一行分为多像素,因此一帧图像其实就是多个像素组成的矩阵。
(4)帧外数据:整个视频由很多个帧构成,最终播放视频时逐个播放各个图像帧即可。

LCD显示一帧图像的过程

(1)首先把帧分为行,然后再把行分为像素,然后逐个像素去显示。(显示像素:其实就是LCD驱动器按照接收到的LCD控制器给的显示数据,驱动一个像素的液晶分子旋转,让这个像素显示出相应的颜色值的过程)
(2)关键点:LCD控制器和驱动器之间一次只能传一个像素点的显示数据。所以一帧图像在屏幕上其实是串行的依次被显示上去的,不是同一时间显示出来的。

为了向前兼容出现的六个时序参数

HSPW 水平同步信号脉宽

HBPD 水平同步信号前肩

HFPD 水平同步信号后肩

VSPW 垂直同步信号脉宽

VBPD 垂直同步信号前肩

VFPD 垂直同步信号后肩

时序过程

(1)一行的通信过程是这样的:LCD控制器先发送一个HSYNC高电平脉冲(脉冲宽度是HSPW),脉冲告诉驱动器下面的信息是一行信息。然后开始这一行信息,这一行信息包括3部分:HBPD+有效行信息+HFPD。其中前肩和后肩都属于时序信息(和LCD屏幕具体有关),有效行信息就是横向分辨率。所以你可以认为一行总共包含4部分:HSPW+HBPD+有效行信息+HFPD。
(2)一帧图像其实就是一列,一列图像由多个行组成,每行都是上面讲的这个时序。
(3)一帧图像的通信过程是这样的:整个帧图像信号分为4部分:VSPW+VBPD+帧有效信号+VFPD。VSPW是帧同步信号宽度,用来告诉驱动器一帧图像要开始了;VBPD和VFPD分别是垂直同步信号前后肩。
(4)必须说明:这6个参数对于LCD显示器其实本来是没用的,这些信号其实是老式的CRT显示器才需要的,LCD本身不需要,但是出于历史兼容性要求,LCD选择了兼容CRT显示器的这些时序要求,所以理解LCD显示器时序和编程时,用CRT的方式来理解不会错。
(5)要注意,这几个时序参数本身是LCD屏幕本身的参数,与LCD控制器无关。所以同一个主板如果接的屏幕不一样则时序参数设置也会不同。这些参数的来源一般是:第一,厂家会直接给出,一般以实例代码的形式给出;第二,来自于LCD的数据手册。
第一种方式,查看九鼎的210裸机教程(x210v3裸机开发教程\src\template-framebuffer-font\source\hardware\s5pv210-fb.c的第774行)

像素深度(bits per pixel,简称bpp)

(1)一个像素在计算机中由多少个字节数据来描述。
(2)计算机中用二进制位来表示一个像素的数据,用来表示一个像素的数据位越多,则这个像素的颜色值更加丰富、分的更细,颜色深度就更深。
(3)一般来说像素深度有这么几种:1位、8位、16位、24位、32位。

常见像素深度:1位、8位、16位、24位、32位
1位:用1个二进制位来表示颜色,这种就叫单色显示。示例就是小饭店、理发店门口的LED屏。
8位:用8个二进制位来表示颜色,此时能表示256种颜色。这种叫灰度显示。这时候是黑白的,没有彩色,我们把纯白到纯黑分别对应255到0,中间的数值对应不同的灰。示例就是以前的黑白电视机。
16位:用16个二进制位表示颜色,此时能表示65536种颜色。这时候就可以彩色显示了,一般是RGB565的颜色分布(用5位二进制表示红色、用6位二进制表示绿色、用5位二进制表示蓝色)。这种红绿蓝都有的颜色表示法就是一种模拟自然界中所有颜色的表示方式。但是因为RGB的颜色表达本身二进制位数不够多(导致红绿蓝三种颜色本身分的都不够细致),所以这样显示的彩色失真比较重,人眼能明显看到显示的不真实。
24位:用24个二进制位来表示颜色,此时能表示16777216种颜色。这种表示方式和16位色原理是一样的,只是RGB三种颜色各自的精度都更高了(RGB各8位),叫RGB888。此时颜色比RGB565更加真实细腻,虽然说比自然界无数种颜色还是少了很多,不过由于人眼的不理想性所以人眼几乎不能区分1677万种颜色和无数种颜色的差别了。于是乎就把这种RGB888的表示方法叫做真彩色。(RGB565就是假彩色)
32位:总共用32位二进制来表示颜色,其中24位表示红绿蓝三元色(还是RGB888分布),剩下8位表示透明度。这种显色方式就叫ARGB(A是阿尔法,表示透明度),现在PC机中一般都用ARGB表示颜色。

补充:颜色的组成,三元色(三基色)是RGB,也就是说所有的颜色都可以由红绿蓝三种颜色组成。

虚拟屏幕的叠加问题

210 由5个虚拟屏幕 ,每中可以叠加,可以设置显示的前后

使用虚拟屏幕优势:不污染原图像,不占内存

虚拟显示(数据手册P1206)

(1)如何实现在小分辨率的屏幕上(真实)显示大分辨率的图像
(2)细节上,我们需要屏幕上看到不同图像时,需要对显存区域进行刷新。即使我们只需要屏幕显示移动一点点,整个屏幕对应的显存空间也需要整个重新刷新,工作量和完全重新显示一幅图像是一样的。这个显然不好,这样CPU刷新屏幕的工作量太大了,效率很低。
(3)如何能够在显示一个大图片的不同区域时让CPU刷新屏幕工作量减少?有,方法就是虚拟显示。具体做法就是在内存中建立显示缓存的时候实际建立一个很大的区域,然后让LCD去对应其中的一部分区域作为有效的显示区域。将来要显示大图像时,直接将大图像全部一次性加载入显示缓存区,然后通过移动有效显示区域就可以显示大图像的不同区域了。

程序lcd_init

基本流程:1.配置LCD引脚的模式

LCD

2.设置背光:找到引脚位置,配置为输出模式,给其低电平

LCD

3.最容易忘的点:RGB=FIMD I80=FIMD ITU=FIMD

LCD

4.RGB接口,并行,时钟源选择

LCD

5.时钟分频

LCD

6. 时序反转

LCD

7.时序时间设置

LCD

8.物理屏幕设置

LCD

9.设置windows0使能,配置像素深度为24bpp

LCD

10.显存大小配置

LCD

11.配置显存地址,显存地址的空间大小

VIDW00ADD1B0 = (((HOZVAL + 1)4 + 0) (LINEVAL + 1)) & (0xffffff); 这句是将10进制数字转化为16进制的数

LCD

12.使能channel 0传输数据

LCD

示例代码:

// 配置引脚用于LCD功能
    GPF0CON = 0x22222222;
    GPF1CON = 0x22222222;
    GPF2CON = 0x22222222;
    GPF3CON = 0x22222222;

    // 打开背光 GPD0_0(PWMTOUT0)
    GPD0CON &= ~(0xf<<0);
    GPD0CON |= (1<<0);          // output mode
    GPD0DAT &= ~(1<<0);            // output 0 to enable backlight

    // 10: RGB=FIMD I80=FIMD ITU=FIMD
    DISPLAY_CONTROL = 2<<0;

    // bit[26~28]:使用RGB接口
    // bit[18]:RGB 并行
    // bit[2]:选择时钟源为HCLK_DSYS=166MHz
    VIDCON0 &= ~( (3<<26)|(1<<18)|(1<<2) );

    // bit[1]:使能lcd控制器
    // bit[0]:当前帧结束后使能lcd控制器
    VIDCON0 |= ( (1<<0)|(1<<1) );

    // bit[6]:选择需要分频
    // bit[6~13]:分频系数为5,即VCLK = 166M/(4+1) = 33M
    VIDCON0 |= 4<<6 | 1<<4;


    // H43-HSD043I9W1.pdf(p13) 时序图:VSYNC和HSYNC都是低脉冲
    // s5pv210芯片手册(p1207) 时序图:VSYNC和HSYNC都是高脉冲有效,所以需要反转
    VIDCON1 |= 1<<5 | 1<<6;

    // 设置时序
    VIDTCON0 = VBPD<<16 | VFPD<<8 | VSPW<<0;
    VIDTCON1 = HBPD<<16 | HFPD<<8 | HSPW<<0;
    // 设置长宽(物理屏幕)
    VIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0);

    // 设置window0
    // bit[0]:使能
    // bit[2~5]:24bpp(RGB888)
    WINCON0 |= 1<<0;
    WINCON0 &= ~(0xf << 2);
    WINCON0 |= (0xB<<2) | (1<<15);

#define LeftTopX     0
#define LeftTopY     0
#define RightBotX   799
#define RightBotY   479

    // 设置window0的上下左右
    // 设置的是显存空间的大小
    VIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0);
    VIDOSD0B = (RightBotX<<11) | (RightBotY << 0);
    VIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1);


    // 设置fb的地址
    VIDW00ADD0B0 = FB_ADDR;
    VIDW00ADD1B0 = (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff);

    // 使能channel 0传输数据
    SHADOWCON = 0x1;

代码解析:将显存地址转化为(u32类型)的指针,指针加上像素点所在的位置再把颜色赋值

**注意区别:因为不乘4 的原因是

内存指针(占4个内存)+1 是4位占4个char(一个像素点用RGB+一个空内存存储的)也就是内存地址和指针的表示方法不同**

u32 *pfb = (u32 *)FB_ADDR;
// 在像素点(x, y)处填充为color颜色
static inline void lcd_draw_pixel(u32 x, u32 y, u32 color)
{
    *(pfb + COL * y + x) = color;
}#或者
static inline void lcd_draw_pixel(u32 x, u32 y, u32 color)
{
    *(0x23000000 + (COL * y + x)*4) = color;
}

屏幕的几种玩法:

1.画横线,竖线,斜线

解析:把起始点和终点坐标确定,把这个线上的像素点显示,其他位背景色

2.画圆并填充颜色
3.画出英文字符

解析:找出ascill码表对应的ascill的值,data[count/8]的值是二维数组的内部的第count/8个第一个元素,

// 在坐标(i, j)这个像素处判断是0还是1,如果是1写color;如果是0直接跳过
                if (data[count/8] & (1<<(count%8)))
                    lcd_draw_pixel(i, j, color);
4.显示图片(目前只会:必须是1024*600的像素)

解析:

1.使用Imag2LCD工具把每个图像转化成RGB三原色的值组成的数组

注意:Image2LCD工具必须关闭播放器,不然保存会闪退)。

2.由于程序的空间超过16kb,所以采用SD卡,先初始化BL1,再用BL2

3.老师的代码BL1缺少clock.c文件需要添加(添加这个文件引起Makefile和start.S需要做相应的改动),添加makefile中main.o 和lcd_init.o,添加制作出来的图片数组声明,更改频率以解决闪的问题,将数值4改成3
4.更改显示图片的函数位制作出来的图片数组
5.更改SD 扇区 位3MB
#define SD_BLOCK_CNT (3*2048)