历史上的今天
返回首页

历史上的今天

今天是:2024年10月19日(星期六)

正在发生

2021年10月19日 | S3C2440裸机实验(7)----LCD驱动

2021-10-19 来源:eefocus

lcd只要搞清楚了时序其实还是比较简单的,现在LINUX下的LCD驱动如果是像三星的处理器都有很好的支持,只需要修改一些参数就OK了,如果是芯片级的驱动那是比较复杂的,主要是涉及到Framebuffer会让人很抓狂,等完成了裸机的驱动我将会开始写linux的驱动程序编写的文章,请各位网友关注并提出宝贵意见!!!


先来看一下s3c2440中LCD控制器的结构:

     

从上面结构图可以看出:整个lcd控制器大致可以由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器几个部分组成。


1。REGBANK由17个可编程的寄存器组和一块256*16的调色板内存组成,它们用来配置LCD控制器的


2。LCDCDMA是一个专用的DMA,它能自动地把在侦内存中的视频数据传送到LCD驱动器,通过使用这个DMA通道,视频数据在不需要 CPU的干预的情况下显示在LCD屏上


3.VIDPRCS接收来自LCDCDMA的数据,将数据转换为合适的数据格式,比如说4/8位单扫,4位双扫显示模式,然后通过数据端口VD[23:0]传送视频数据到LCD驱动器


4.TIMEGEN由可编程的逻辑组成,他生成LCD驱动器需要的控制信号,比如VSYNC、HSYNC、VCLK和LEND等等,而这些控制信号又与REGBANK寄存器组中的LCDCON1/2/3/4/5的配置密切相关,通过不同的配置,TIMEGEN就能产生这些信号的不同形态,从而支持不同的LCD驱动器(即不同的STN/TFT屏)。


LCD提供的外部接口信号:


1.VSYNC/VFRAME/STV:垂直同步信号(TFT)/帧同步信号(STN)/SEC TFT信号


2.HSYNC/VLINE/CPV:水平同步信号(TFT)/行同步脉冲信号(STN)/SEC TFT信号


3.VD[23:0]:LCD像素数据输出端口(TFT/STN/SEC TFT);


4。VDEN/VM/TP:数据使能信号(TFT)/LCD驱动交流偏置信号(STN)/SEC TFT 信号


说明:


A:显示指针从矩形左上角的第一行第一个点开始,一个点一个点的在LCD上显示,在上面的时序图上用时间线表示就为VCLK,我们称之为像素时钟信号;


B:当显示指针一直显示到矩形的右边就结束这一行,那么这一行的动作在上面的时序图中就称之为1 Line;


C:接下来显示指针又回到矩形的左边从第二行开始显示,注意,显示指针在从第一行的右边回到第二行的左边是需要一定的时间的,我们称之为行切换;


D:如此类推,显示指针就这样一行一行的显示至矩形的右下角才把一副图显示完成。因此,这一行一行的显示在时间线上看,就是时序图上的HSYNC


E:然而,LCD的显示并不是对一副图像快速的显示一下,为了持续和稳定的在LCD上显示,就需要切换到另一幅图上(另一幅图可以和上一副图一样或者不一样,目的只是为了将图像持续的显示在LCD上)。那么这一副一副的图像就称之为帧,在时序图上就表示为1 Frame,因此从时序图上可以看出1 Line只是1 Frame中的一行;


F:同样的,在帧与帧切换之间也是需要一定的时间的,我们称之为帧切换,那么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)


核心代码:(特别注意LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH]中LCD_HEIGHT对应下面rLCDCON2中的行数LINEVAL)


#include "def.h"

#include "lcd.h"

#include "2440addr.h"


#define LCD_WIDTH 240

#define LCD_HEIGHT 320

#define LINEVAL (LCD_HEIGHT - 1)

#define HOZVAL (LCD_WIDTH - 1)



//水平同步信号

#define LCD_HSYNC 5

#define LCD_LEFT_MARGIN 19

#define LCD_RIGHT_MARGIN 36


//垂直同步信号

#define LCD_VSYNC 1

#define LCD_UPPER_MARGIN 1

#define LCD_LOWER_MARGIN 5


#define LCD_CLKVAL 4   //时钟分频因子,VCLK = HCLK/((LCD_CLKVAL+1)*2)

#define BPPMODE_TFT 12  //16位TFT

//for LCDCON5

#define PNRMODE 3 //显示模式:TFT LCD Panel

#define BPP24BL 1  //24位输出格式MSB Valid

#define FRM565  1 //16位输出格式:5:6:5

#define INVVCLK 0  //下降沿有效

#define INVVFRAME   1     //翻转VSYNC信号

#define INVVLINE       1     //翻转HSYNC信号

#define PWREN           1     //使能PWREN信号

#define INVVD            0     //正常VD信号极性

#define INVVDEN        0     //正常VDEN信号极性

#define INVVDEN        0     //正常VDEN信号极性

#define BSWP      0     //颜色数据字节不交换

#define HWSWP           0     //颜色数据半字不交换


//注意这里的LCD_HEIGHT对应下面rLCDCON2中的行数LINEVAL,否则会出错

volatile static unsigned short LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];

extern const unsigned char sunflower_240x320[];


#define M5D(n) ((n)&0x1fffff)   //得到n的低21位

#define LCD_ADDR ((U32)LCD_BUFFER)


static void LCD_Port_Init()

{

  //*** PORT C GROUP

    //Ports  : GPC15 GPC14 GPC13 GPC12 GPC11 GPC10 GPC9 GPC8  GPC7   GPC6   GPC5 GPC4 GPC3  GPC2  GPC1 GPC0

    //Signal : VD7   VD6   VD5   VD4   VD3   VD2   VD1  VD0 LCDVF2 LCDVF    **   VM VFRAME VLINE VCLK  ***  

    //Binary :  10   10  , 10    10  , 10    10  , 10   01  , 00     00  ,  **   10 , 10     10 , 10   **

   // rGPCCON = 0xaaa956aa;       

    rGPCCON = 0xaaaa02a8; 

    rGPCUP  = 0xffff;     // The pull up function is disabled GPC[15:0]     


    //*** PORT D GROUP

    //Ports  : GPD15 GPD14 GPD13 GPD12 GPD11 GPD10 GPD9 GPD8 GPD7 GPD6 GPD5 GPD4 GPD3 GPD2 GPD1 GPD0

    //Signal : VD23  VD22  VD21  VD20  VD19  VD18  VD17 VD16 VD15 VD14 VD13 VD12 VD11 VD10 VD9  VD8

    //Binary : 10    10  , 10    10  , 10    10  , 10   10 , 10   10 , 10   10 , 10   10 ,10   10

    rGPDCON = 0xaaaaaaaa;       

    rGPDUP  = 0xffff;     // The pull up function is disabled GPD[15:0]


}

void LCD_Init(void)

{

    LCD_Port_Init();

rLCDCON1 = (LCD_CLKVAL << 8) | (PNRMODE<<5) | (BPPMODE_TFT <<1);

rLCDCON2 = (LCD_UPPER_MARGIN << 24) |(LINEVAL << 14) |(LCD_LOWER_MARGIN << 6) | (LCD_VSYNC<<0);

rLCDCON3 = (LCD_LEFT_MARGIN <<19) | (HOZVAL<<8) |(LCD_RIGHT_MARGIN<<0);

    rLCDCON4 = (LCD_HSYNC<<0);

rLCDCON5 = (FRM565 << 11)|(INVVCLK<<10) | (INVVLINE<<9) | (INVVFRAME<<8) | (0<<7) | (INVVDEN<<6) | (PWREN<<3)  |(BSWP<<1) | (HWSWP);

//将缓存首地址的A[30:22]存在寄存器[29:21]中,数据高地址A[21:1]存在寄存器[20:0]中

rLCDSADDR1 = ((LCD_ADDR>>22)<<21) | ((M5D(LCD_ADDR >> 1)) <<  0);

//将缓存的低地址A[21:1]写入寄存器,

rLCDSADDR2 = M5D((LCD_ADDR + LCD_WIDTH * LCD_HEIGHT * 2) >> 1);

//LCD_WIDTH×16/16;由于是选择的16位模式,

//如果是24位模式,每个像素4字节则为LCD_WIDTH×32/16

rLCDSADDR3 = LCD_WIDTH; 

rLCDINTMSK|=(3);      // 屏蔽LCD中断

rTCONSEL = 0;            //无效LPC3480

rLCDCON1|=1; // ENVID=ON

}


//背光开启

static void LCD_Backlight(void)

{

//GPG4 configure as LCD_PWREN

rGPGCON =rGPGCON &(~(3<<8)) | (3<<8) ;

rGPGUP =rGPGUP &(~(1<<4)) | (1<<4);

rGPGDAT = rGPGDAT | (1<<4) ;

    //Enable LCD POWER ENABLE Function

    rLCDCON5 = rLCDCON5&(~(1<<3))|(1<<3);   // 有效PWREN信号

    rLCDCON5 = rLCDCON5&(~(1<<5))|(0<<5);   // PWREN信号极性不翻转


}


/**************************************************************

320×240 TFT LCD单个象素的显示数据输出

**************************************************************/

static void PutPixel(U32 x,U32 y,U16 c)

{

    if(x LCD_BUFFER[(y)][(x)] = c;

}


/**************************************************************

320×240 TFT LCD全屏填充特定颜色单元或清屏

**************************************************************/

static void Lcd_ClearScr( U16 c)

{

unsigned int x,y ;

    for( y = 0 ; y < LCD_HEIGHT ; y++ )

    {

    for( x = 0 ; x < LCD_WIDTH ; x++ )

    {

LCD_BUFFER[y][x] = c ;

    }

    }

}


/**************************************************************

在LCD屏幕上用颜色填充一个矩形

**************************************************************/

 void Glib_FilledRectangle(int x1,int y1,int x2,int y2, U16 color)

{

    int i;

int j;

    //for(i=y1;i<=y2;i++)

//Glib_Line(x1,i,x2,i,color);

for(i=x1;i for(j=y1;j     PutPixel(i,j,color);

}


/**************************************************************

在LCD屏幕上指定坐标点画一个指定大小的图片

**************************************************************/

static void Paint_Bmp(int x0,int y0,int h,int l,const unsigned char *bmp)

推荐阅读

史海拾趣

CITIZEN公司的发展小趣事

在20世纪中叶,西铁城公司迎来了一次重要的技术突破。1956年,公司成功研制出防震手表,并通过了空中坠表实验,这一创新轰动了整个行业。防震手表的推出不仅提升了西铁城产品的品质,也进一步巩固了其在全球腕表市场中的地位。这一技术的成功应用,也显示了西铁城在精密加工和测量技术方面的实力。

BCD Semi(Diodes)公司的发展小趣事

在电子行业的发展过程中,市场波动和风险挑战是不可避免的。某一年,全球半导体市场出现了严重的产能过剩,导致产品价格大幅下跌。面对这一挑战,BCD Semi(Diodes)公司及时调整生产策略,优化产品结构,降低生产成本,成功度过了这一行业寒冬。

Amphenol RF公司的发展小趣事

在电子行业的发展过程中,市场波动和风险挑战是不可避免的。某一年,全球半导体市场出现了严重的产能过剩,导致产品价格大幅下跌。面对这一挑战,BCD Semi(Diodes)公司及时调整生产策略,优化产品结构,降低生产成本,成功度过了这一行业寒冬。

台湾三礼(3L)公司的发展小趣事

随着汽车电子市场的快速发展,三礼公司敏锐地捕捉到了这一市场的巨大潜力。2011年,公司成功开发了超薄型模压电感,并完成了全厂70%以上的精益生产配置。同年,公司还取得了车载规范TS16949认证,成为世界第一客户的主要供货商。这一成就不仅彰显了公司在电感领域的技术实力,也为公司进一步拓展车载市场奠定了坚实基础。

Gould Fiber Optics公司的发展小趣事
可能是散热不良、负载过大或内部元件短路。
Eurofarad公司的发展小趣事

随着Eurofarad产品质量的不断提高和市场份额的逐步扩大,公司开始积极拓展国际市场。Eurofarad的产品已经广泛应用于航空航天、国防、医疗、铁路、石油勘探等领域,赢得了全球客户的信赖和好评。同时,Eurofarad还与国际知名企业建立了紧密的合作关系,共同推动电子行业的发展。

问答坊 | AI 解惑

一种提高无线局域网传输效率的技术

摘要:随着信息技术的快速发展,无线网络技术的应用越来越广泛,但是无线网络传输的效率一直比较低。针对这 种情况提出了一种提高无线局域网传输效率的技术。先在原理上讨论了使用包融合技术在无线局域网中使用的可 行性,然后通过在NS2 下的模拟 ...…

查看全部问答>

小白跪问 现有ARM9开发板上的RS232口怎么改成RS485的?

我的老师那里有一块开发板,其中J6接口如下图所示: 标号    名称           功能                  说明 J6   &n ...…

查看全部问答>

新手求助

大家好,本人大二,学习了模电和单片机.这个学期想参加电子设计比赛,初赛题要做一个基于fpga的频率计。我已经基本上了解了fpga的含义,但还是有一些问题想请教: 1.fpga的开发板价位从几十到几万…我看很多都是为嵌入式系统做的.如果只是要做频率 ...…

查看全部问答>

汇编高手乱入 关于十进制指令

看指令表有关与十进制指令 DADD.B 将十进制的进位位和源操作数加至目的操作数 语法 DADD.B src, dst 操作 src + dst + C -> dst (十进制) 有点不理解,大侠,斑竹指点 例如: CLRC ;复位进位位 CLR R5 DADD.B #99, R5 那 ...…

查看全部问答>

求助

I/O模拟I2C,假设P2.1接SDA,那么发送过来的8位数据放在什么地方?是P2IN吗?若是的话,8位数据是同时放在P2IN里吗(最高位在P2.7,最低位在P2.0)?但是,用户手册上说“Each bit in each PxIN register reflects the value of the input signal at t ...…

查看全部问答>

三星的eMMC iNAND和DDR3 SDRAM跳楼价甩了

三星的eMMC iNAND(型号KLM2G1DEHE)大概还有50片左右,DDR3 SDRAM(型号K4B2G0846C)大概30片的样子都是BGA封装,冰点吐血价5元每片,照例上图 淘宝小店:http://shop34118588.taobao.com/…

查看全部问答>

CCS5.2中C程序单步过程调用汇编子程序时,反汇编一片空白

点SUSPEND后,可以看到反汇编,也可以继续单步。这是怎么回事?…

查看全部问答>

数字基带编码软件

自己写的数字基带编码软件 征集网友验证程序的正确性, 跟帖给出验证的例子与结果…

查看全部问答>