S5PV210 LCD控制器

LCD简介

LCD(Liquid Crystal Display) ,即液晶显示屏,是一种采用了液晶控制透光度技术来实现色彩的显示器,LCD 有很多种类型,常见的有 :

  1. STN(超扭曲向列),它的特点是功耗低,但亮度不足,响应时间长;(1602那种类型的)
  2. TFT(薄膜晶体管),它的特点是响应时间短,画面清晰,但功耗稍高,(自己实验用的应该是这个类型的,这个类型当作计算机液晶显示设备)。
  3. LTPS(低温多晶硅),各方面性能优越,但技术要求高;
  4. OLED(有机发光二极管),各方面性能优越,但技术要求高。

S5PV210 LCD 控制器


S5PV210 的 LCD 控制器由一个逻辑单元组成,它的作用是: 把 LCD 图像数据从一个位于系统内存的 video buffer 传送到一个外部的 LCD 驱动器接口
LCD驱动接口支持 3 种接口:
  •    RGB 接口:(自己用的使这种)
  •   indirect-i80 接口
  •   UV 接口
S5PV210 的 LCD 控制器支持多种颜色格式,例如 

  • RGB (1BPP 到 24BPP)
  • YCbCr 4:4:4 (只有本地总线) 

LCD 控制器可以通过编程满足不同的需求, 即 满足水平、垂直方向的像素数目,满足数据接口的数据线宽度、接口时序和刷新速率

S5PV210 LCD 关键特性介绍

总线接口 : AMBA  AXI  64 位主模式 /AHB  32 位从模式,本地视频总线
(YCbCr/RGB).
视频输出接口:RGB 接口(并行 24 位,串行 8 位) ,Indirect i80 接口,YUV
接口.
  • 支持 i80/RGB 双输出模式
  • 支持 8/16/24 多种 BPP 模式
  • 4/8/16 位的可编程 DMA
  • 支持 256 x 32 位的调色板
  • 支持最大为 16MB 的虚拟屏幕 

信号类型

  • VSYNC:垂直同步信号,每个 VSYNC 信号表示一帧数据的开始.
  •  HSYNC: 水平同步信号,每个 HSYNC 信号表示一行数据的开始.
  •  VCLK:  像素时钟信号,每个 VCLK 信号表示一个像素数据.
  •  VDEN:  数据使能信号.
  •  VD:  Video Data,数据信号. 

S5PV210 LCD 控制器子模块概述

LCD 控制器模块由 VSFR,VDMA,VPRCS,VTIME 以及 video clock 组成。为了配置 LCD 显示控制模块,VSFR 有 121 个可编程寄存器集,一个 gamma LUT 寄存器集(64 个寄存器),一个 i80 命令寄存器集(12 个寄存器)和 5 个 256 x 32调色板内存。


VDMA 是一个专用的显示 DMA 通道,用于才能够 frame 内存里传输视频数据到VPRCS。利用特殊的 DMA,用户可以在没有 CPU 干涉的情况下传输视频数据到屏幕上示。

VPRCS 从 VDMA 中接收视频数据并在转换视频数据为合适的数据格式后(例如:8BPP 或 16BPP 模式) 通过 RGB_VD 或 SYS_VD 端口传送到显示设备上(如: LCD)

VTIME 由可编程逻辑模块组成, 在不同的 LCD 驱动下支持各种接口时序和波特率。 VTIME 模块产生 RGB_VSYNC, RGB_HSYNC, RGB_VCLK, RGB_VDEN SYS_CS0,SYS_CS1,SYS_WE 等等信号。

信号时序图分析

S5PV210 LCD控制器_第1张图片
210手册(1207页)
  • VSYNC 的有效启动脉冲是高电平有效
  • VSYNC 脉冲宽度为(VSPW+1)个 HSYNC 信号周期,在这个周期内数据无效
  • VSYNC 有效启动脉冲后还要经过(VBPD+1)个 HSYNC 信号周期,有效的数据才会出现
  • 跟随着连续发出(LINEVAL+1)行的有效数据
  • 最后经过(VFPD+1)个无效行,完整的一帧数据就传输结束,紧接着下一次VSYNC 启动脉冲才能发出.

  • HSYNC 的有效启动脉冲是高电平有效.
  • HSYNC 脉冲宽度为(HSPW+1)个 VCLK 信号周期,在这个周期内像素数据无效.
  • HSYNC 有效启动脉冲后还要经过(HBPD+1)个 VLCK 信号周期,有效的像素数据才会出现.
  • 跟随着连续发出(HOZVAL+1)个的有效像素数据.
  • 最后经过(HFPD+1)个无效数据,完整的一行数据就传输结束,紧接着下一次HSYNC 启动脉冲才能发出.
基本模式是类似的。

参数的计算

查找数据手册:S70-AT070TN92.pdf,13和14页
S5PV210 LCD控制器_第2张图片
S5PV210 LCD控制器_第3张图片

根据表格和图计算相应参数


S5PV210 LCD控制器_第4张图片

S5PV210 LCD控制器_第5张图片
垂直信号参数

tvpw 可取 typ.值为 10(中间值) ,而 tvpw 的值就是 VSYNC 的脉冲宽度,也就是说 VSPW + 1 = 10,所以 VSPW = 9

tvb 可取 typ.值为 23,而 tvb 的值是 VSYNC 前面经过(VSPW + 1 )+(VBPD + 1)

tvfp 可取 typ.值为 22,而 tvfp 的值是后面经过(VFPD + 1)的无效行,也就是说 tvfp = VFPD + 1= 22,所以 VFPD = 21

tvd 可取 typ.值为 480, 而 tvd 的值就是 (LINEVAL+1) ,其实就是 y 轴的 LCD分辨率,也就说 tvd = (LINEVAL+1)= 480,所以 LINEVAL = 479的无效行,也就是说 tvb =

 (VSPW + 1 )+(VBPD + 1) = 23,相当于 10 + VBPD + 1 = 23,所以 VBPD = 12

水平信号参数

thpw 可取 typ.值为 20(中间值),而 thpw 的值就是 HSYNC 的脉冲宽度,也就是说 HSPW + 1 = 20,所以 VSPW = 19.

thb 可取 typ.值为 46,而 tvb 的值是 VSYNC 前面经过(HSPW + 1 )+(HBPD + 1)的无效行,也就是说 thb= (HSPW + 1 )+(HBPD + 1) =  46,相当于 20 + VBPD + 1 = 46,所以 HBPD = 25.

thfp 可取 typ.值为 210,而 thfp 的值是后面经过(HFPD + 1)的无效行,也就是说 thfp = HFPD + 1= 210,所以 VFPD = 209。

时钟频率计算

RGB_VCLK (Hz) = HCLK / (CLKVAL+1), CLKVAL >= 1


Frame Rate = 1/ [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1) } x 
{(HSPW+1) + (HBPD +1)  + (HFPD+1) + (HOZVAL + 1) } x { ( CLKVAL+1 ) / 
( HCLK ) } ]

数据格式

14BPP和24BPP,数据存储的地址方式不同,具体查手册。

硬件端口功能


该液晶屏接口有 45Pin,其中 VD0~VD23 是数据信号线引脚,VDEN 是数据信号使能引脚,VSYNC 是垂直同步信号引脚,HSYNC 是水平同步信号引脚,VCLK 是像素时钟信

号引脚,Xi2SCL2,Xi2SDA2 分别是 I2C 的 SCL、SDA 引脚,在电容屏的触摸中会用到。 XENIT14、 XEINT15 引脚是外部中断引脚。


S5PV210 LCD控制器_第6张图片 S5PV210 LCD控制器_第7张图片

程序的编写

根据210手册1218页,OVERVIEW OF PROGRAMMER’S MODEL里面提到了23个寄存器的作用,根据这个来编写程序。

一共9步,在程序里体现。

#define  GPF0CON			( *(volatile unsigned int *)0xE0200120 )
#define  GPF1CON			( *(volatile unsigned int *)0xE0200140 )
#define  GPF2CON			( *(volatile unsigned int *)0xE0200160 )
#define  GPF3CON			( *(volatile unsigned int *)0xE0200180 )

#define  GPD0CON			( *(volatile unsigned int *)0xE02000A0 )
#define  GPD0DAT			( *(volatile unsigned int *)0xE02000A4 )


#define  CLK_SRC1			( *(volatile unsigned int *)0xe0100204 )
#define  CLK_DIV1			( *(volatile unsigned int *)0xe0100304 )
#define  DISPLAY_CONTROL	( *(volatile unsigned int *)0xe0107008 )

/* LCD Controler Pins */
#define  VIDCON0			( *(volatile unsigned int *)0xF8000000 )
#define  VIDCON1			( *(volatile unsigned int *)0xF8000004 )
#define  VIDTCON2 			( *(volatile unsigned int *)0xF8000018 )
#define  VIDTCON3			( *(volatile unsigned int *)0xF800001c )
#define  WINCON0 			( *(volatile unsigned int *)0xF8000020 )
#define  WINCON2 			( *(volatile unsigned int *)0xF8000028 )
#define  SHADOWCON 			( *(volatile unsigned int *)0xF8000034 )
#define  VIDOSD0A 			( *(volatile unsigned int *)0xF8000040 )
#define  VIDOSD0B 			( *(volatile unsigned int *)0xF8000044 )
#define  VIDOSD0C 			( *(volatile unsigned int *)0xF8000048 )

#define  VIDW00ADD0B0 		( *(volatile unsigned int *)0xF80000A0 )
#define  VIDW00ADD1B0 		( *(volatile unsigned int *)0xF80000D0 )
#define  VIDW00ADD2   		( *(volatile unsigned int *)0xF8000100 )

#define  VIDTCON0 			( *(volatile unsigned int *)0xF8000010 )
#define  VIDTCON1 			( *(volatile unsigned int *)0xF8000014 )

/*垂直信号*/
#define VSPW       9  //tvpw=VSPW+1的值是VSYNC的脉冲宽度,现根据表确定tvpw
#define VBPD       12 //tvb = (VSPW + 1 )+(VBPD + 1),tvb 的值前面(VSPW + 1 )+(VBPD + 1)的无效行,先根据表确定tvb
#define LINEVAL    479//tvd =  (LINEVAL+1)= 480,根据表确定tvd的值,表示y轴大小
#define VFPD       21 //tvfp 的值是后面经过(VFPD + 1)的无效行,现根据表确定tvfp
/*水平信号*/
#define HSPW       19 //thpw =HSPW + 1 = 20,现根据表确定thpw
#define HBPD       25 //thb= (HSPW + 1 )+(HBPD + 1) = 46, thb 的值是 VSYNC 前面经过(HSPW + 1 )+(HBPD + 1)的无效行,根据表先确定thb
#define HOZVAL     799//thd=HOZVAL +1,表示的x轴大小
#define HFPD       209//thfp = HFPD + 1= 210, thfp 的值是后面经过(HFPD + 1)的无效行,先根据表确定thfp
/****描述上下左右定点的位置*/
#define LeftTopX     0
#define LeftTopY     0
#define RightBotX   799
#define RightBotY   479
/**SCR_YSIZE_TFT  = 480,SCR_XSIZE_TFT  = 800,描述行和列的大小*/
#define SCR_XSIZE_TFT 	(800)
#define SCR_YSIZE_TFT 	(480)

volatile unsigned int LCD_BUFFER[SCR_YSIZE_TFT][SCR_XSIZE_TFT];

void lcd_init(void);
void lcd_draw_pixel(int row, int col, int color);
void lcd_clear_screen(unsigned long color);
void Glib_Rectangle(int x1,int y1,int x2,int y2,int color);

void lcd_init(void)
{
	/** 1.设置相关GPIO引脚用于LCD */
	GPF0CON = 0x22222222;		// GPF0[7:0]  LCD_VD[0-23]
	GPF1CON = 0x22222222;		// GPF1[7:0]
	GPF2CON = 0x22222222;		// GPF2[7:0]
	GPF3CON = 0x22222222;		// GPF3[7:0]
	/**
	 **2.显示路径的选择
	 * 0b10: RGB=FIMD I80=FIMD ITU=FIMD
	 */
	DISPLAY_CONTROL = 2<<0;
	/**3.打开背光,见原理图不再核心板上*/
	GPD0CON |= 1<<4;
	GPD0DAT |= 1<<1;

	/**4.VIDCONx,设置接口类型、时钟、极性和使能LCD控制器等*/

    /* 4.1:设置VIDCON0 -->CLKVAL_F[13:6]:该值需要根据LCD手册做相应的修改
	 *   HCLKD=166.75MHz,DCLK(min) = 20ns(50MHz)
	 *   VCLK = 166.75 / (4+1) = 33.35MHz
	 * (手册P14页可知DCLK频率的经典为33.3MHz)
	 * CLKDIR  [4]:1 = 由CLKVAL_F分频
	 * ENVID   [1]:1 = 使能视频输出
	 * ENVID_F [0]:1 = 在当前帧结束的情况下使能视频输出
	 */

	VIDCON0 &= ~((3<<26) | (1<<18) | (0xff<<6)  | (1<<2));
	VIDCON0 |= ((4<<6) | (1<<4) );
	VIDCON0  |= 0x3; 	/* 开启总控制器 */

	/*4.2设置VINC0N1---->. 设置极性(该值需要根据LCD手册做相应的修改)

	 * IVDEN [4]:0 = 正常
	 * IVSYNC[5]:1 = 反极性
	 * IHSYNC[6]:1 = 反极性
	 * IVCLK [7]:0 = Video data is fetched at VCLK falling edge
	 */

	 /*.设置极性相反的原因:
     S70-AT070TN92(p13页):VSYNC 和 HSYNC 都是低脉冲
    S5PV210 芯片手册(p1207) 时序图:VSYNC 和 HSYNC 都是高脉冲有效,所以需要反转。*/
	VIDCON1 &= ~(1<<7);   			/* 在vclk的下降沿获取数据 */
	VIDCON1 |= ((1<<6) | (1<<5));   /* HSYNC极性反转, VSYNC极性反转 */


	/**5.VIDTCONx,设置时序和长宽等 ,所用参数前面已经提到*/
	VIDTCON0 = (VBPD << 16) | (VFPD << 8) | (VSPW << 0);/*时序*/
	VIDTCON1 = (HBPD << 16) | (HFPD << 8) | (HSPW << 0);
	/* 设置长宽LINEVAL[21:11]:多少行   = 480,HOZVAL [10:0] :水平大小 = 800*/
	VIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0);

	/** 6.配置WINCON0,设置window0的数据格式
      Swap使能),很关键的一位,能够解决掉重影问题
	  BPPMODE_F[5:2]:1011 = 24 BPP
	  ENWIN_F  [0]:  1    = 使能视频输出及视频控制信号
	 /
	WINCON0 &= ~(0xf << 2);
	WINCON0 |= (1<<15)|(0xB<<2);
	WINCON0 |= 1;       /* 开启窗口0 */

	/**7. 配置VIDOSD0A/B/C,设置window0的坐标系 */
	/* 窗口0,右下角的位置(800,480) */
	VIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0);
	VIDOSD0B = (RightBotX<<11) | (RightBotY << 0);
	VIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1);/*Window Shadow Control Register*/

    /**8.配置VIDW00ADD0B0和VIDW00ADD1B0,设置framebuffer的地址*/
	VIDW00ADD0B0 = LCD_BUFFER;
	/* VBASEL = VBASEU + (LINEWIDTH+OFFSIZE) x (LINEVAL+1)
	 *        = 0 + (800*4 + 0) * 479
	 *        =
	 */
	VIDW00ADD1B0 =  (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff);

	/**配置SHADOWCON,使能dma通道0;*/
	SHADOWCON = 0x1; 	/* 使能通道0 */



}

/* 画一个像素点 */
void PutPixel(unsigned long x,unsigned long y, unsigned long c )
{
	if ( (x < SCR_XSIZE_TFT) && (y < SCR_YSIZE_TFT) )
		LCD_BUFFER[(y)][(x)] = c;
}

/* 清屏 */
/***先扫描行,行里面描像素。
lcd_clear_screen 函数就是利用这个原理,外循环表示一行一行的扫,内循环表
示一行里面一个一个像素描。总共有 480 行,每行里面有 800 个像素点。这就
是 Webee210 液晶屏的分辨率 800*480.*/
void lcd_clear_screen( unsigned long c)
{
	unsigned int x,y ;

	for( y = 0 ; y < SCR_YSIZE_TFT ; y++ )
	{
		for( x = 0 ; x < SCR_XSIZE_TFT ; x++ )
		{
			LCD_BUFFER[y][x] = c ;
		}
	}
}

/* 用于画直线:横线和竖线 */
void Glib_Line(int x1,int y1,int x2,int y2,int color)
{
	int dx,dy,e;
	dx=x2-x1;
	dy=y2-y1;

	if(dx>=0)
	{
		if(dy >= 0) // dy>=0
		{
			if(dx>=dy) // 1/8 octant
			{
				e=dy-dx/2;
				while(x1<=x2)
				{
					PutPixel(x1,y1,color);
					if(e>0){y1+=1;e-=dx;}
					x1+=1;
					e+=dy;
				}
			}
			else		// 2/8 octant
			{
				e=dx-dy/2;
				while(y1<=y2)
				{
					PutPixel(x1,y1,color);
					if(e>0){x1+=1;e-=dy;}
					y1+=1;
					e+=dx;
				}
			}
		}
		else		   // dy<0
		{
			dy=-dy;   // dy=abs(dy)

			if(dx>=dy) // 8/8 octant
			{
				e=dy-dx/2;
				while(x1<=x2)
				{
					PutPixel(x1,y1,color);
					if(e>0){y1-=1;e-=dx;}
					x1+=1;
					e+=dy;
				}
			}
			else		// 7/8 octant
			{
				e=dx-dy/2;
				while(y1>=y2)
				{
					PutPixel(x1,y1,color);
					if(e>0){x1+=1;e-=dy;}
					y1-=1;
					e+=dx;
				}
			}
		}
	}
	else //dx<0
	{
		dx=-dx;		//dx=abs(dx)
		if(dy >= 0) // dy>=0
		{
			if(dx>=dy) // 4/8 octant
			{
				e=dy-dx/2;
				while(x1>=x2)
				{
					PutPixel(x1,y1,color);
					if(e>0){y1+=1;e-=dx;}
					x1-=1;
					e+=dy;
				}
			}
			else		// 3/8 octant
			{
				e=dx-dy/2;
				while(y1<=y2)
				{
					PutPixel(x1,y1,color);
					if(e>0){x1-=1;e-=dy;}
					y1+=1;
					e+=dx;
				}
			}
		}
		else		   // dy<0
		{
			dy=-dy;   // dy=abs(dy)

			if(dx>=dy) // 5/8 octant
			{
				e=dy-dx/2;
				while(x1>=x2)
				{
					PutPixel(x1,y1,color);
					if(e>0){y1-=1;e-=dx;}
					x1-=1;
					e+=dy;
				}
			}
			else		// 6/8 octant
			{
				e=dx-dy/2;
				while(y1>=y2)
				{
					PutPixel(x1,y1,color);
					if(e>0){x1-=1;e-=dy;}
					y1-=1;
					e+=dx;
				}
			}
		}
	}
}

/* 用于画方框 */
void Glib_Rectangle(int x1,int y1,int x2,int y2,int color)
{
    Glib_Line(x1,y1,x2,y1,color);	//矩形的上边长
    Glib_Line(x2,y1,x2,y2,color);	//矩形的右边长
    Glib_Line(x1,y2,x2,y2,color);	//矩形的下边长
    Glib_Line(x1,y1,x1,y2,color);	//矩形的左边长
}





 
   



你可能感兴趣的:(嵌入式)