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]
好了,到此就配置完毕了,跟着看一下具体代码:
上面的代码是在LCD的第一列显示一条红色的线,在我的LCD上是可以成功显示出来的
===========================================================================================[b]============[/b]
好了,这次简单的LCD驱动就写到这里,其它的功能就以后再研究了。
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驱动就写到这里,其它的功能就以后再研究了。
相关文章推荐
- GEC210(S5PV210)裸机驱动之按键(外部)中断
- GEC210(S5PV210)裸机驱动之PWM定时器
- GEC210(S5PV210)裸机驱动之中断系统
- GEC210(S5PV210)裸机驱动之串口及串口中断
- S5PV210----裸机LCD驱动
- GEC210(S5PV210)裸机驱动之I2C
- S5PV210 -- HX8369 LCD 驱动
- 嵌入式裸机开发学习:2440驱动LCD的24bpp模式相关设置
- S5PV210 裸机开发驱动之LED灯
- [置顶] s5pv210,lcd驱动,x210,驱动
- 2440 裸机 之lcd驱动 编写出现问题及感悟
- S3C2440裸机学习 - LCD驱动原理及代码分析[一]
- S3C2440裸机学习[2] - LCD驱动原理及代码分析[一]
- S5PV210(TQ210)学习笔记——LCD驱动编写
- LCD裸机驱动
- S3C2440裸机学习- LCD驱动原理及代码分析[二]
- S3C2440裸机学习[2] - LCD驱动原理及代码分析[二]
- S5PV210 u-boot LCD驱动 自动更新增加进度条
- linux-3.8.0 S5PV210 LCD显示屏驱动移植
- mini2440裸机编程--------LCD驱动