【说明】
这一章我们来介绍一个很好玩的东西,那就是LCD,也就是我们开发板上的显示屏了,这个要理清一个概念,那就是LCD和触摸屏是完全没关系的两个设备,只不过他们一般都做在一起而已,我们这节只介绍LCD,没有触摸屏的内容。由于我用得是友善的TINY6410,而友善公司把触摸屏和LCD背光都做成了1线的,也就是一般的背光控制和触摸屏原理都不适用于这个6410。所以我们无视背光控制,单纯学习LCD的显示部分。
【控制器】
S3C6410自带有LCD控制器,所以操作LCD的事就交给他吧,当然,在让它控制LCD前我们需要设置控制器,比如分辨率,时序参数等等,当都设置好了之后,我们还需要分配一块内存给他当做显存,它就从里面取数据然后用LCD显然。
【硬件原理】
LCD的显然过程可以想象成有一把电子枪,从一行的第一个像素开始一个像素一个像素把颜色打到屏幕上,如果一行打完了,就到下一行,如果所有行打完了,就回到第一行继续打, 由于速度很快,所以人眼看起来就好像图像是一直存在的,其实是一个像素一个像素打出来的。
【原理图】
1)VD都是数据线,用来传输像素,一个像素用24位表示
2)HSYNC是当电子枪打到一行的最后面的时候,用来让电子枪回到最左边用的同步信号。
3)VSYNC是当电子枪打完最后一行后,用来让电子枪回到最上边的同步信号。
4)VDEN 是数据有效信号,当其有效的时候枪口才是打像素,但是不影响电子枪移动。
5)VCLK 时钟信号,来一个信号,打一个像素
【怎么写】
1】设置LCD控制器
1)分辨率
2)时间参数
3)极性(下面就知道是什么了)
2】分配显存
1)告诉LCD控制器
3】设置像素
1)颜色格式
【详细设置】
6410手册里面给出了初始化控制器的步骤如下
设置GPIO
在进行上面的设置之前我们要设置一下GPIO管脚配置成LCD功能。
由主板图知道,我们需要配置GPI和GPJ,关于GPIO的配置我想就不用再多说了吧。。。。。。
下面就按上图来
1】固定值
第1步骤就是往寄存器里设置固定的值,我们就按它的要求设置就可以了
2】像素模式
我们要使用RGB模式。。所以应该设置成01
3】配置VIDCON0寄存器
这个寄存器东西比较多,我们一个一个来理解
1)使能,显然要设置成11
2)选择时钟源,我们使用HCLK
3)时钟分频,HCLK是133MHZ不符合我们的LCD要求,所以我们需要用CLKVAL来分频,所以要设置下面这些位
分频系数应该为多少下面会说的
分频为多少呢
看LCD数据手册,里面要求得时钟频率如下,所以我们分频系数可以设置为3,即133 / (3 + 1) = 33.3
4)设置RGB的顺序,我们的是按R-G-B的顺序来的
4】配置VIDCON1寄存器
在这个寄存器中,我们需要设置一下同步信号的极性
那我们怎么知道要不要设置为1呢,也就是要不要反转极性呢,看下面2张图
在6410手册中的时序图是高脉冲
而在LCD数据手册中却是低脉冲,所以要反转
5】配置VIDTCON0寄存器和VIDTCON1寄存器,以及VIDTCON2寄存器
由于我们是用RGB模式,所以手册中第5,6两个步骤中的寄存器我们不用设置的,我们直接设置VIDTCON0寄存器
以及VIDTCON1寄存器,这两个寄存器都是用来设置时序的,VIDTCON2设置屏幕长宽
我们现在来分析一下其中要设置为多少
首先看下上面各个参数在S3C6410手册提供的时序图中的意思
对比一下LCD提供的时序
然后再看看LCD数据手册给我们的各个参数的数据
显然各个参数就可以一一对上号了。
1)HSPW = thpw
2)HBPD = thb - thpw
3)HFPD = thfp
4)VSPW = tvpw
5)VBPD = tvb
6)VFPD = tvfp
现在来设置一下屏幕的长宽
上面的数据图中已经给出了,应该是480和800
6】设置WINCON0寄存器
LCD控制器支持5个窗口,我们只用第一个窗口所以我们只要设置WINCON0就可以了
首先我们要使能,然后选择R8-G8-B8格式的像素
7】设置VIDOSD0A,VIDOSD0B,VIDOSD0C
其实就是设置一下四个角的坐标而已,另外就是设置一下窗口大小,也就是有多少像素
8】设置显存
终于到达最后一步了,也就是给一个显存给控制器,因为是裸机所以我们就直接给它一块不用得内存就可以了
【初始化源代码】
人生最蛋疼的事,就是尼玛分析了半天,,,结果代码写出来就一点点。。。
// 初始化LCD
void lcd_init(void)
{
// 配置GPIO用于LCD相关的功能
GPICON = 0xAAAAAAAA;
GPJCON = 0x00AAAAAA;
// normal mode
MIFPCON &= ~(1<<3);
// RGB I/F
SPCON = (SPCON & ~(0x3)) | 1;
// 配置VIDCONx,设置接口类型、时钟、极性和使能LCD控制器等
VIDCON0 = (0<<26)|(0<<17)|(0<<16)|(3<<6)|(0<<5)|(1<<4)|(0<<2)|(3<<0);
VIDCON1 |= 1<<5 | 1<<6;
// 配置VIDTCONx,设置时序和长宽等
// 设置时序
VIDTCON0 = VBPD<<16 | VFPD<<8 | VSPW<<0;
VIDTCON1 = HBPD<<16 | HFPD<<8 | HSPW<<0;
// 设置长宽
VIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0);
// 配置WINCON0,设置window0的数据格式
WINCON0 |= 1<<0;
WINCON0 &= ~(0xf << 2);
WINCON0 |= 0xB<<2;
// 配置VIDOSD0A/B/C,设置window0的坐标系
#define LeftTopX 0
#define LeftTopY 0
#define RightBotX 800
#define RightBotY 480
VIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0);
VIDOSD0B = (RightBotX<<11) | (RightBotY << 0);
VIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1);
// 置VIDW00ADD0B0和VIDW00ADD1B0,设置framebuffer的地址
VIDW00ADD0B0 = FRAME_BUFFER;
VIDW00ADD1B0 = FRAME_BUFFER + (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff);
}
【控制像素】
在任意一点画一个像素的函数
// 描点
void lcd_draw_pixel(int row, int col, int color)
{
unsigned long * pixel = (unsigned long *)FRAME_BUFFER;
*(pixel + row * COL + col) = color;
}