您的位置:首页 > 其它

GEC210(S5PV210)裸机驱动之LCD(1)

2015-01-12 13:36 225 查看
主机平台:Linux CentOS 6.5

arm平台:粤嵌GEC210开发板(S5PV210)

这次写一下简单的LCD驱动,只是在LCD上显示一帧静止的画面。

LCD本身的时序还算简单,但在S5PV210上,因为添加了很多的功能,所以构成了一个比较复杂的显示控制器(display controller),数据手册上这个章节就有一百多页,看完就花了几个小时了。

=======================================================================================================

开始还是先看几张图:

1.显示控制器的结构图



简单讲下这张图:

1.最左边是图像数据来源的接口部分,可从摄像头或通过DMA从内存获取数据

2.然后是,通过上面的接口,可同时产生最多5个通道的数据

3.再对上面的数据根据一定的方式进行混合产生一张图

4.跟着是对这张图进行各种图像处理

5.最终通过相应的接口送到MIPI DSI System(注意:这里不是直接到LCD上)

2.MIPI DSI System)(这部分数据手册上写的不是很清楚,可能我的理解有问题,但DISPLAY_PATH_SEL(DISPLAY_CONTROLP[1:0])的确是必须配置的)



从display controller的数据送到这里MIPI DSI System,MIPI DSIM通过DISPLAY_PATH_SEL(DISPLAY_CONTROLP[1:0])来选择哪个Path输出到LCD上。见下图,其中FIMD指的就是display controller



这里再提醒下,如果你的LCD是RGB接口,DISPLAY_PATH_SEL必须要配置,这在数据手册上LCD的章节里只提过一次,而且也没有明确写出如何配置,所以我在调试时因为这个原因花了不少时间

3.再看看具体的数据流结构图



1.一共可产生5个数据窗口,其中所有窗口均可通过AXI总线(即从内存中)获取数据,WIN0/1/2/3同时支持从CAMIF摄像头接口获取数据

2.每个窗口都可以独立选择是否将其数据输出,控制器将会根据一定的规则(blending、color key)将各个窗口的数据混合成一张图像,然后还可以对图像进行各种处理

=======================================================================================================

然后就是初始化控制器了,这里以最简单的功能进行配置,采用的是RGB接口,只选则window1,输入为ch1,作为源图像,关闭所有混合、色键等图像处理选项,在LCD上显示一张内存中的图像

1.各个window共用的配置

(1)时钟配置

输入时钟主要由下面寄存器确定:

CLKVAL_F(VIDCON0[13:6]):当时钟源为HCLK时,设置分频系数

CLK_DIR(VIDCON0[4]):选择是否使用CLKVAL_F对输入时钟进行分频

CLKSEL_F:选择时钟源

(2)与LCD硬件相关的配置

a.与接口相关的设置,与接口类型、数据传输格式(并行或串行)等:VIDCONx

b. 与时序相关配置:

VIDCON1[7:4]:各信号极性配置

VIDTCON0、VIDTCON0:设置时序中各参数

c.LCD大小配置

VIDTCON2[21:11]:LCD的高

VIDTCON2[10:0]:LCD的宽

2.各窗口独立的配置

(1)与显示相关的配置

VIDW0xADD0Bx:图像内存缓冲区起始地址

VIDW0xADD1Bx:图像内存缓冲区结束地址

VIDW01ADD2:与Virtual screen相关的参数

VIDOSD1A:LCD上显示区域的左上角坐标,以LCD左上角为原点,单位为坐标

VIDOSD1B:LCD上显示区域的右下角坐标,以LCD左上角为原点,单位为坐标

WINCOMx:缓冲区内图像数据格式

具体可看下图:



3.引脚功能寄存器配置,详细看后面代码(这里要记住,写各种驱动时我已经忘记过好几次了,然后在写这篇文章也是最后才记起)

4.显示使能配置:

SHADOWCON[7:0]:各通道使能配置

WINCONx[0]:各窗口图像输出使能配置

VIDCON[0]:全局输出使能配置

VIDTCON3[31]:VSYNC信号使能配置

DISPLAY_PATH_SEL(DISPLAY_CONTROLP[1:0]):显示输入路径配置

================================================================[b]=======================================[/b]

下面以我手上的LCD为例具体配置各寄存器

1.时钟配置



由上图,将LCD输入时钟设置为9MHz

时钟源选择HCLK(CLKSEL_F=0),使用分频(CLKDIR=1),分频系数(CLKVAL_F)由下面公式计算:

VCLK = HCLK/(YHCLK/(CLKVAL+1))

2.接口设置

我的LCD为RGB接口,数据并行传送,因此:VIDCON0[28:26]=0;VIDCON0[18]=0

3.具体时序参数配置

先看一下LCD的时序图:



然后是相关参数:



与寄存器VIDTCON0、VIDTCON1中个参数的对应关系为:

VBPD = tvb =2

VFPD = tvf = 2

VSPW = tvp = 10

HBPD = thb = 2

HFPD = thf = 2

HSPW = thp = 41

还有的就是信号极性配置(VIDCON1[7:4]):

根据上面的时序图:

VCLK时钟有效沿为下降沿,IVCLK=0

HSYNC脉冲信号为低电平脉冲,IHSYNC=1

VSYNC脉冲信号为低电平脉冲,IVSYNC=1

VDEN数据有效信号为高电平,VDEN=0

4.LCD屏幕大小配置

此处使用的LCD分辨率大小为480*272,因此

VIDTCON2 = ((LCD_HEIGHT-1)<<11) + (LCD_WIDTH-1);

5.窗口1显示相关寄存器配置(这里最好看上面 ”2(1)与显示相关配置“ 那一点的图,把各个参数的关系先弄清楚)

(1)缓冲区地址配置,这里使用缓冲区0

VIDW01ADD0B0 = (unsigned)fbuf0;

VIDW01ADD1B0 = (unsigned)(fbuf0 +480*272);

(2)LCD显示区域配置,这里LCD大小和缓冲区大小相同,所以

VIDW01ADD2 = (0<<13)+((480)*4);

(3)OSD(LCD实际可视区域)配置,此处是将数据在整个屏幕上都显示出来,即左上角坐标为(0,0),右下角坐标为(479,271)

VIDOSD1A = ((0)<<11)+(0); //显示区域左上角坐标

VIDOSD1B = ((480-1)<<11)+(272-1); //显示区域右下角坐标

(4)缓冲区数据格式设置

这里将格式设置为:WINCON1[5:2]=1011:Unpacked 24 bpp(non-palletized R:8-G:8-B:8)

6.显示使能配置

DISPLAY_PATH_SEL(DISPLAY_CONTROLP[1:0]) = 2:显示输入路径配置

VIDTCON3[31] = 1:VSYNC信号使能配置

SHADOWCON[1] = 1:使能channel 1

WINCON1[0] = 1 :窗口1图像输出使能

VIDCON[0] = 3:全局输出使能配置

===========================================================================================[b]============[/b]

好了,到此就配置完毕了,跟着看一下具体代码:

<span style="font-size:14px;">#define VBPDE 0
#define VBPD 2
#define VFPD 2
#define VSPW 10
#define VFPDE 0
#define HBPD 2
#define HFPD 2
#define HSPW 41
#define LCD_WIDTH  480
#define LCD_HEIGHT 272

unsigned long fbuf1[480*272];

void lcd_init()
{
int i;

for(i=0;i<480*272;i++)
{
fbuf1[i] = 0x00000000;

if(i%480==0)
fbuf<span style="font-size:14px;">1</span>[i] = 0x00ff0000;

}

//引脚相关寄存器配置
GPF0CON = 0x22222222;
GPF0DRV = 0xffffffff;
GPF0PUD = 0;
GPF1CON = 0x22222222;
GPF1DRV = 0xffffffff;
GPF1PUD = 0;
GPF2CON = 0x22222222;
GPF2DRV = 0xffffffff;
GPF2PUD = 0;
GPF3CON = (GPF3CON & ~(0xffff<<0) | (0x2222<<0));
GPF3DRV = (GPF3DRV & ~(0xff<<0) | (0xff<<0));
GPF3PUD = (GPF3PUD & ~(0xff<<0) | (0x00<<0));

VIDCON0 = 0x1050; //set the clock source and frequency
VIDCON1 = 0xe0; //各信号极性配置

VIDTCON0 = ((VBPDE<<24)+(VBPD<<16) + (VFPD<<8) + VSPW); //时序相关配置
VIDTCON1 = ((VFPDE<<24)+(HBPD<<16) + (HFPD<<8) + HSPW); //时序相关配置
VIDTCON2 = ((LCD_HEIGHT-1)<<11) + (LCD_WIDTH-1); //LCD分辨率配置
VIDTCON3 = (1<<31); //使能VSYNC信号输出

VIDW01ADD0B0 = (unsigned)fbuf1; //缓冲区起始地址
VIDW01ADD1B0 = (unsigned)(fbuf1 +480*272); //缓冲区结束地址配置
VIDW01ADD2 = (4<<13)+((480-1)*4);
SHADOWCON |= (0x2);//使能channel 1
VIDOSD1A = 0;//<span style="font-size:14px;">OSD<span style="font-size:14px;">左上角坐标</span></span>
VIDOSD1B = ((480-1)<<11)+(272-1);//<span style="font-size:14px;">OSD右下角坐标</span>
WINCON1 = 0x2c; //缓冲区数据格式配置

S5PV210_DISPLAY_CONTROL=(((S5PV210_DISPLAY_CONTROL) & ~(0x3<<0)) | (0x2<<0));

WINCON1 |= 0x1; //使能WIN1输出

VIDCON0 |=0x3; //使能全局输出

}</span>


上面的代码是在LCD的第一列显示一条红色的线,在我的LCD上是可以成功显示出来的

===========================================================================================[b]============[/b]

好了,这次简单的LCD驱动就写到这里,其它的功能就以后再研究了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: