b-1:大体寄存器功能
从上面结构图可以看出:整个lcd控制器大致可以由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器几个部分组成。
b-1-1:REGBANK由17个可编程的寄存器组和一块256*16的调色板内存组成,它们用来配置LCD控制器的
b-1-2:LCDCDMA是一个专用的DMA,它能自动地把在侦内存中的视频数据传送到LCD驱动器,通过使用这个DMA通道,视频数据在不需要 CPU的干预的情况下显示在LCD屏上
b-1-2:VIDPRCS接收来自LCDCDMA的数据,将数据转换为合适的数据格式,比如说4/8位单扫,4位双扫显示模式,然后通过数据端口VD[23:0]传送视频数据到LCD驱动器
b-1-3:TIMEGEN由可编程的逻辑组成,他生成LCD驱动器需要的控制信号,比如VSYNC、HSYNC、VCLK和LEND等等,而这些控制信号又与REGBANK寄存器组中的LCDCON1/2/3/4/5的配置密切相关,通过不同的配置,TIMEGEN就能产生这些信号的不同形态,从而支持不同的LCD驱动器(即不同的STN/TFT屏)。
c:LCD提供的外部接口信号:
c-1:VSYNC/VFRAME/STV:垂直同步信号(TFT)/帧同步信号(STN)/SEC TFT信号
c-2:HSYNC/VLINE/CPV:水平同步信号(TFT)/行同步脉冲信号(STN)/SEC TFT信号
c-3:VD[23:0]:LCD像素数据输出端口(TFT/STN/SEC TFT);
c-4:VDEN/VM/TP:数据使能信号(TFT)/LCD驱动交流偏置信号(STN)/SEC TFT 信号
c-5:说明:
c-5-1:显示指针从矩形左上角的第一行第一个点开始,一个点一个点的在LCD上显示,在上面的时序图上用时间线表示就为VCLK,我们称之为像素时钟信号;
c-5-2:当显示指针一直显示到矩形的右边就结束这一行,那么这一行的动作在上面的时序图中就称之为1 Line;
c-5-3:接下来显示指针又回到矩形的左边从第二行开始显示,注意,显示指针在从第一行的右边回到第二行的左边是需要一定的时间的,我们称之为行切换;
c-5-4:如此类推,显示指针就这样一行一行的显示至矩形的右下角才把一副图显示完成。因此,这一行一行的显示在时间线上看,就是时序图上的HSYNC
c-5-5:然而,LCD的显示并不是对一副图像快速的显示一下,为了持续和稳定的在LCD上显示,就需要切换到另一幅图上(另一幅图可以和上一副图一样或者不一样,目的只是为了将图像持续的显示在LCD上)。那么这一副一副的图像就称之为帧,在时序图上就表示为1 Frame,因此从时序图上可以看出1 Line只是1 Frame中的一行;
c-5-6:同样的,在帧与帧切换之间也是需要一定的时间的,我们称之为帧切换,那么LCD整个显示的过程在时间线上看,就可表示为时序图上的VSYNC
下面是时序图:
VBPD(vertical back porch):表示在一帧图像开始时,垂直同步信号以后的无效的行数,对应驱动中的upper_margin;
VFBD(vertical front porch):表示在一帧图像结束后,垂直同步信号以前的无效的行数,对应驱动中的lower_margin;
VSPW(vertical sync pulse width):表示垂直同步脉冲的宽度,用行数计算,对应驱动中的vsync_len;
HBPD(horizontal back porch):表示从水平同步信号开始到一行的有效数据开始之间的VCLK的个数,对应驱动中的left_margin;
HFPD(horizontal front porth):表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK的个数,对应驱动中right_margin;
HSPW(horizontal sync pulse width):表示水平同步信号的宽度,用VCLK计算,对应驱动中的hsync_len;
行频和场频的计算:
行频 = VCLK /[(HSPW+1)+(HSPD+1)+(HFPD+1)+(HOZVAL+1)]
场频 =行频 /[(VSPW+1)+(VBPD+1)+(VFPD+1)+(LINEVAL+1)]
接下来了解下相关寄存器的字段结构:
对于以上这些参数的值将分别保存到REGBANK寄存器组中的LCDCON1/2/3/4/5寄存器中
LCDCON1:LINECNT18--27设置屏的行数,最大1024行,从LINECNT计数到0,真正要显示区域的大小是在LCDCON2中的LINEVAL设置;CLKVAL 8--17用于设置分频因子,STN: VCLK = HCLK / (CLKVAL x 2) ( CLKVAL ≥2 ) TFT: VCLK = HCLK / [(CLKVAL+1) x 2] ( CLKVAL ≥ 0 ); 6 - 5位扫描模式(对于STN屏:4位单/双扫、8位单扫); 4 - 1位色位模式(1BPP、8BPP、16BPP等);
LCDCON2:用于设置VBPD,LINEVAL,VFBD,VSPW,对于STN屏VBPD,VFBD,VSPW值都为0。
LCDCON3:功能类似LCDCON2,只是用于垂直方向的一些参数。
LCDCON5:用于查询和设置一些状态信息。
编程步骤:
1、打开LCD背光
将LCD背光对应的GPIO设置为禁止上拉(GPxUP相应位写入1),选择output类型(GPxCON相应位写入01),输出为高电平(GPxDAT相应位写入1)。
2、打开LCD电源
可以将GPG4选择为LCD_PWREN(GPGCON:9-8写入11),这时候LCD电源的打开/关闭可以通过LCDCON5:3来控制。
也可以自定义其他GPIO用作LCD电源开关,只需将此GPIO设置为禁止上拉(GPxUP相应位写入1),选择output类型(GPxCON相应位写入01),输出为高电平(GPxDAT相应位写入1)打开LCD电源。
3、设置其他信号线
其他信号线包括VD0-VD23和VFRAME、VLINE、VCLK等,分别在GPCCON,GPDCON中选择相应功能。
4、设置LCD的频率(VCLK)
LCD的Datasheet上一般会写有一个推荐的频率,比如我使用的屏幕推荐频率为6.4M,我需要通过一些计算选择一个合适的CLKVAL以产生这个频率:
对于TFT LCD,S3C2440提供的VCLK的计算公式为:
VCLK = HCLK / ((CLKVAL+1)*2)
可以得出:
CLKVAL = HCLK / (VCLK * 2) - 1
我的HCLK是100Mhz(CPU运行在400Mhz, CLKDIV_VAL设置为5,Fclk:Hclk:Pclk = 1:4:8),VCLK使用屏幕推荐的6.4M,得到:
CLKVAL = 100000000 / (6400000 * 2) - 1 = 6.8
选择最接近的整数值7,写入LCDCON1:17-8。
(VCLK其实就是根据 每秒帧数*帧行数*行像素 计算出来的,帧行数和行像素需要包含空白数和同步数)
5、设置其他相关参数
LCD相关的参数主要还有这几个:
LINEVAL: LCD水平像素-1,如320-1 = 319
HOZVAL: LCD垂直像素-1,如240-1 = 239
HFPD: 行开始前的VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)
HBPD: 行结束后的VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)
HSPW: 行之间水平同步的无效VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)
VFPD: 帧数据开始前的空白行数(LCD屏幕的Datasheet一般有推荐值)
VBPD: 帧数据结束后的空白行数(LCD屏幕的Datasheet一般有推荐值)
VSPW: 帧之间垂直同步的无效行数(LCD屏幕的Datasheet一般有推荐值)
(相关寄存器LCDCON2, LCDCON3, LCDCON4)
6、设置视频缓冲区的地址
2440支持虚拟屏幕,可以通过改变LCD寄存器实现屏幕快速移动
PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数,如16位宽320像素,设为320 * 2
OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为0
LCDBANK: 视频帧缓冲区内存地址30-22位
LCDBASEU: 视频帧缓冲区的开始地址21-1位
LCDBASEL: 视频帧缓冲区的结束地址21-1位
(相关寄存器LCDSADDR1,LCDSADDR2,LCDSADDR3)
7、确定信号的极性
2440的LCD控制器允许设置VCLK、VLINE、VFRAME等信号的极性(上升沿有效还是下降沿有效),需要对照LCD的Datasheet一一确认。
(相关寄存器LCDCON5)
8、禁止LPC3600/LCC3600模式!
如果不是使用三星LPC3600/LCC3600 LCD,必须禁止LPC3600/LCC3600模式(写入0到TCONSEL)!
9、打开视频输出
ENVID设为1 (LCDCON1:0写入1)
#define U32 unsigned long
#define U16 unsigned short
#define M5D(n) ((n) & 0x1fffff)// To get lower 21bits
//Color STN LCD Panel(320*240)
#define MODE_CSTN_8BIT (0x2001)
#define MODE_CSTN_12BIT (0x2002)
#define LCD_XSIZE_CSTN (320)
#define LCD_YSIZE_CSTN (240)
#define SCR_XSIZE_CSTN (LCD_XSIZE_CSTN) //*2for virtual screen
#define SCR_YSIZE_CSTN (LCD_YSIZE_CSTN)//*2
#define HOZVAL_CSTN(LCD_XSIZE_CSTN*3/8-1)// Valid VD data line number is 8.
#define LINEVAL_CSTN(LCD_YSIZE_CSTN-1)
//CSTN timing parameter for LCBHBT161M(NANYA)
#define LINEBLANK_CSTN(16 &0xff)
//Timing parameter for LTS350Q1(SAMSUNG)
#define VBPD_240320((2-1)&0xff)
#define VFPD_240320((3-1)&0xff)
#define VSPW_240320((2-1) &0x3f)
#define HBPD_240320((7-1)&0x7f)
#define HFPD_240320((3-1)&0xff)
#define HSPW_240320((4-1)&0xff)
// 130hz @50Mhz,WLH=16hclk,WDLY=16hclk,LINEBLANK=16*8hclk,VD=8
#define LCDFRAMEBUFFER 0x33800000 //_NONCACHE_STARTADDRESS
// 1. The LCD frame buffer should be write-through or non-cachable.
// 2. The total frame memory should be inside 4MB.
// 3. To meet above 2 conditions, the frame buffer should be
// inside the following regions.
// 0x31000000~0x313ffffff,
// 0x31400000~0x317ffffff,
// 0x31800000~0x31bffffff,
// 0x33800000~0x33bffffff
void Lcd_CstnOnOff(int onoff);
void Lcd_Port_Init(void);
#include <linux/config.h>
#include <linux/utsname.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/module.h>
#include <asm/hardware.h>
#include <asm/proc/pgtable.h>
#include <asm/arch/memory.h>
#include <asm/arch/smdk.h>
#define M5D(n) ((n) & 0x1fffff)// To get lower 21bits
#define LCD_XSIZE_CSTN (320)
#define LCD_YSIZE_CSTN (240)
#define SCR_XSIZE_CSTN (LCD_XSIZE_CSTN) //*2for virtual screen
#define SCR_YSIZE_CSTN (LCD_YSIZE_CSTN) //*2
#define HOZVAL_CSTN (LCD_XSIZE_CSTN*3/8-1) // Valid VD data line number is 8.
#define LINEVAL_CSTN (LCD_YSIZE_CSTN-1)
#define LINEBLANK_CSTN (16 &0xff)
#define LCDFRAMEBUFFER LCD_BASE //_NONCACHE_STARTADDRESS
#define BYTESPERLINE (LCD_XSIZE_CSTN)
typedef unsigned long tOff;
#define XY2OFF(x,y) (tOff)((tOff)y*(tOff)BYTESPERLINE + (x))
#define READ_MEM(Off, Data) Data = LCD_READ_MEM(Off)
#define WRITE_MEM(Off, Data) LCD_WRITE_MEM(Off, Data)
#define GETPIXEL(x, y) GetPixelIndex(x, y)
#define SETPIXEL(x, y, c) SetPixel(x, y, c)
void Lcd_CstnOnOff(int onoff);
*************************************************************************************************************
- 函数名称 : void CloseLCD(struct inode * inode, struct file * file)
- 输入参数 : struct inode * inode, struct file * file
*************************************************************************************************************
static void CloseLCD(struct inode * inode, struct file * file)
printk("LCD is closed\n");
*************************************************************************************************************
- 函数名称 : static int OpenLCD(struct inode * inode, struct file * file)
- 输入参数 : struct inode * inode, struct file * file
*************************************************************************************************************
static int OpenLCD(struct inode * inode, struct file * file)
*************************************************************************************************************
- 函数名称 : static int LCDIoctl(struct inode *inode,struct file * file,unsigned int cmd,unsigned long arg)
*************************************************************************************************************
static int LCDIoctl(struct inode *inode,struct file * file,unsigned long cmd,unsigned long arg)
printk("LCD_COLOR =%x\n",LCD_COLOR);
p_arg =(struct para *)arg;
LCD_DrawHLine(p_arg->a,p_arg->b,p_arg->c);// draw h_line
LCD_DrawHLine(p_arg->a,p_arg->b+15,p_arg->c);// draw h_line
LCD_DrawHLine(p_arg->a,p_arg->b+30,p_arg->c);// draw h_line
p_arg =(struct para *)arg;
LCD_DrawVLine(p_arg->a,p_arg->b,p_arg->c); // draw v_line
LCD_DrawVLine(p_arg->a+15,p_arg->b,p_arg->c); // draw v_line
LCD_DrawVLine(p_arg->a+30,p_arg->b,p_arg->c); // draw v_line
p_arg =(struct para *)arg;
LCD_DrawCircle(p_arg->a,p_arg->b,p_arg->c);// draw circle
p_arg =(struct para *)arg;
LCD_FillRect(p_arg->a,p_arg->b,p_arg->c,p_arg->d); // draw rect
printk("draw fillcircle\n");
p_arg =(struct para *)arg;
LCD_FillCircle(p_arg->a, p_arg->b, p_arg->c);// draw fillcircle
printk("LCD is clear\n");
LCD_Clear(0,0,319,239); // clear screen
p_arg =(struct para *)arg;
LCD_FillRect(p_arg->a,p_arg->b,p_arg->c,p_arg->d); // draw rect
*************************************************************************************************************
- 函数名称 : struct file_operations LCD_fops
*************************************************************************************************************
static struct file_operations LCD_fops =
ioctl: LCDIoctl, /* ioctl */
open: OpenLCD, /* just a selector for the real open */
release: CloseLCD, /* release */
*************************************************************************************************************
- 函数名称 : U16 LCD_Init(U8 Lcd_Bpp)
*************************************************************************************************************
long i; unsigned char * base;
GPCUP = 0xffffffff; // Disable Pull-up register
GPCCON= 0xaaaaaaaa; //Initialize VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND
GPDUP = 0xffffffff; // Disable Pull-up register
GPDCON= 0xaaaaaaaa; //Initialize VD[23:8]
// Packed Type : The L.C.M of 12 and 32 is 96.
LCDCON1 = (CLKVAL_CSTN<<8)|(MVAL_USED<<7)|(2<<5)|(3<<1)|0;
// 8-bit single scan,8bpp CSTN,ENVID=off
LCDCON2 = (0<<24)|(LINEVAL_CSTN<<14)|(0<<6)|0;
LCDCON3 = (WDLY_CSTN<<19)|(HOZVAL_CSTN<<8)|(LINEBLANK_CSTN<<0);
LCDCON4 = (MVAL<<8)|(WLH_CSTN<<0);
LCDADDR1 = ((U32)0x33800000>>22)<<21;
//use th physical address
LCDADDR2 = M5D((((SCR_XSIZE_CSTN )*LCD_YSIZE_CSTN))>>1);
LCDADDR3 = (((SCR_XSIZE_CSTN - LCD_XSIZE_CSTN)/2)<<11)|(LCD_XSIZE_CSTN / 2);
base =(unsigned char*)LCD_BASE;
*************************************************************************************************************
- 函数名称 : U16 LCD_READ_MEM(U32 off)
*************************************************************************************************************
U16 LCD_READ_MEM(U32 off)
return (*((U8*)LCDFRAMEBUFFER + (off)));
*************************************************************************************************************
- 函数名称 : void LCD_WRITE_MEM( U32 off,U8 Data)
*************************************************************************************************************
void LCD_WRITE_MEM( U32 off,U8 Data)
(* ((U8*)LCDFRAMEBUFFER + (off)) ) = Data;
*************************************************************************************************************
- 函数名称 : static void SetPixel(U16 x,U16 y,int c)
*************************************************************************************************************
static void SetPixel(U16 x, U16 y, U32 c)
*************************************************************************************************************
- 函数名称 : void LCD_DrawPixel (U16 x, U16 y)
*************************************************************************************************************
void LCD_DrawPixel (U16 x, U16 y)
SETPIXEL(x, y, LCD_COLOR);
*************************************************************************************************************
- 函数名称 : U32 GetPixelIndex(U16 x, U16 y)
*************************************************************************************************************
U32 GetPixelIndex(U16 x, U16 y)
*************************************************************************************************************
- 函数名称 : U32 LCD_GetPixel(U16 x, U16 y)
*************************************************************************************************************
U32 LCD_GetPixel(U16 x, U16 y)
*************************************************************************************************************
- 函数名称 : void LCD_DrawHLine (U16 x0, U16 y, U16 x1)
*************************************************************************************************************
void LCD_DrawHLine (U16 x0, U16 y0, U16 x1)
SETPIXEL(x0, y0, LCD_COLOR);
*************************************************************************************************************
- 函数名称 : void LCD_DrawVLine (U16 x, U16 y0, U16 y1)
*************************************************************************************************************
void LCD_DrawVLine(U16 x0, U16 y0, U16 y1)
SETPIXEL(x0, y0, LCD_COLOR);
*************************************************************************************************************
- 函数名称 : void LCD_FillRect(U16 x0, U16 y0, U16 x1, U16 y1)
*************************************************************************************************************
void LCD_FillRect(U16 x0, U16 y0, U16 x1, U16 y1)
LCD_DrawHLine(x0,y0, x1);
*************************************************************************************************************
- 函数名称 : void LCD_Clear(U16 x0, U16 y0, U16 x1, U16 y1)
*************************************************************************************************************
void LCD_Clear(U16 x0, U16 y0, U16 x1, U16 y1)
LCD_DrawHLine(x0,y0, x1);
*************************************************************************************************************
- 函数名称 : static void DrawPoint(U16 x0,U16 y0, U16 xoff, U16 yoff)
*************************************************************************************************************
static void _DrawPoint(U32 x0,U32 y0, U32 xoff, U32 yoff)
LCD_DrawPixel(x0+xoff,y0+yoff);
LCD_DrawPixel(x0-xoff,y0+yoff);
LCD_DrawPixel(x0+yoff,y0+xoff);
LCD_DrawPixel(x0+yoff,y0-xoff);
LCD_DrawPixel(x0+xoff,y0-yoff);
LCD_DrawPixel(x0-xoff,y0-yoff);
LCD_DrawPixel(x0-yoff,y0+xoff);
LCD_DrawPixel(x0-yoff,y0-xoff);
*************************************************************************************************************
- 函数名称 : void LCD_DrawCircle(U16 x0, U16 y0, U16 r)
*************************************************************************************************************
void LCD_DrawCircle(U32 x0, U32 y0, U32 r)
U32 imax = ((int)((int)r*707))/1000 + 1;
U32 sqmax = (int)r*(int)r + (int)r/2;
*************************************************************************************************************
- 函数名称 : void LCD_FillCircle(U16 x0, U16 y0, U16 r)
*************************************************************************************************************
void LCD_FillCircle (U16 x0, U16 y0, U16 r)
U32 imax = ((int)((int)r*707))/1000+1;
U32 sqmax = (int)r*(int)r+(int)r/2;
LCD_DrawHLine(x0-r,y0,x0+r);
LCD_DrawHLine (x0-i+1,y0+x, x0+i-1);
LCD_DrawHLine (x0-i+1,y0-x, x0+i-1);
LCD_DrawHLine(x0-x,y0+i, x0+x);
LCD_DrawHLine(x0-x,y0-i, x0+x);
*************************************************************************************************************
- 函数名称 : Log2Phy(int Color)
*************************************************************************************************************
return b + (g << 2) + (r << 5);
*************************************************************************************************************
- 函数名称 : LCD_Log2Phy(int Color)
*************************************************************************************************************
U16 LCD_Log2Phy(U32 Color)
PhyColor = Log2Phy(Color);
*************************************************************************************************************
- 函数名称 : void Set_Color(int color)
*************************************************************************************************************
void Set_Color(U32 color)
LCD_SetColor(LCD_Log2Phy(color));
*************************************************************************************************************
- 函数名称 : void Set_Color(int color)
*************************************************************************************************************
void LCD_SetColor(U16 PhyColor)
*************************************************************************************************************
- 函数名称 : void Set_Color(int color)
*************************************************************************************************************
void Set_BkColor(U32 color)
LCD_SetBkColor(LCD_Log2Phy(color));
*************************************************************************************************************
- 函数名称 : void Set_Color(int color)
*************************************************************************************************************
void LCD_SetBkColor(U16 PhyColor)
*************************************************************************************************************
- 函数名称 : int LCDInit(void)
*************************************************************************************************************
int __init LCD_Init(void)
printk("Registering S3C2410LCD Device\t--- >\t");
result = register_chrdev(LCD_MAJOR, "S3C2410LCD", &LCD_fops);//注册设备
printk(KERN_INFO"[FALLED: Cannot register S3C2410LCD_driver!]\n");
printk("Initializing S3C2410LCD Device\t--- >\t");
printk("S3C2410LCD Driver Installed.\n");
*************************************************************************************************************
*************************************************************************************************************
void Lcd_CstnOnOff(int onoff)
// 1:CSTN Panel on 0:CSTN Panel off //
{LCDCON1 |= 1; // ENVID=ON
printk("\nLCDCON1 is already enable.\n");
LCDCON1 = LCDCON1 & 0x3fffe; // ENVID Off
GPBUP = GPBUP|(1<<5); // Pull-up disable
GPBDAT =( GPBDAT & (~(1<<5))) |(onoff<<5); // GPB5=On or Off
GPBCON =( GPBCON & (~(3<<10)))|(1<<10); //GPD9=output
*************************************************************************************************************
*************************************************************************************************************
void __exit LCDdriver_Exit(void)
unregister_chrdev(LCD_MAJOR, "S3C2410LCD");
printk("You have uninstall The LCD Driver succesfully,\n if you want to install again,please use the insmod command \n");
module_exit(LCDdriver_Exit);
*****************************************************************************************************************
*****************************************************************************************************************
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">