s3c2440 LCD及触摸屏的学习笔记(1)

所用的LCD为TopPoly-TD035STED4(TFT)型号,240*320的 Display timing:
这里写图片描述

其VCLK为6.39MHz。 根据s3c2440手册s3c2440处理LCD的时钟源是HCLK,通过寄存器LCDCON1中的CLKVAL可以调整VCLK频率大小,它的公式为:VCLK=HCLK÷[(CLKVAL+1)×2],程序的内部分频为FCLK=400MHz、HCLK=100MHz、PCLK=50MHz(MPLLCON=(92<<12)|(1<<4)|1;),因此得到CLKVAL取整为6。

注:(LCD一般需要三个时序信号:VSYNC、HSYNC和VCLK。VSYNC是垂直同步信号,在每进行一个帧(即一个屏)的扫描之前,该信号就有效一次,由该信号可以确定LCD的场频,即每秒屏幕刷新的次数(单位Hz)。HSYNC是水平同步信号,在每进行一行的扫描之前,该信号就有效一次,由该信号可以确定LCD的行频,即每秒屏幕从左到右扫描一行的次数(单位Hz)。VCLK是像素时钟信号。

其中VSYNC是帧同步信号,VSYNC每发出1个脉冲,都意味着新的1屏视频资料开始发送。而HSYNC为行同步 信号,每个HSYNC脉冲都表明新的1行视频资料开始发送。而VDEN则用来标明视频资料的有效,VCLK是用来锁存视频资料的像数时钟。网上搜到的资料来解释这几个时序信号。

可以查看s3c2440手册‘Figure 15-6. TFT LCD Timing Example’图)

通过上图可以得到:

代码

#define LCD_WIDTH   240              //屏幕的宽
#define LCD_HEIGHT  320              //屏幕的高

//垂直同步信号的脉宽、后肩和前肩—–这些值是根据TopPoly-TD035STED4.pdf文件中的13页的表

#define VSPW      1 //(3-1)
#define VBPD      1 //(15-1)
#define VFPD      1 //(12-1)

//水平同步信号的脉宽、后肩和前肩—–这些值是根据TopPoly-TD035STED4.pdf文件中的13页的表

#define HSPW       (10-1)
#define HBPD       (20-1)
#define HFPD        (10-1)

//显示尺寸

#define LINEVAL  (LCD_HEIGHT-1)
#define HOZVAL   (LCD_WIDTH-1)

注:(对于一个已知尺寸的LCD屏,只要确定了VCLK值,行频和场频就应该知道了。但这样还不行的,因为在每一帧时钟信号中,还会有一些与屏显示无关的时钟出现,这就给确定行频和场频带来了一定的复杂性。如在HSYNC信号先后会有水平同步信号前肩(HFPD)和水平同步信号后肩(HBPD)出现,在VSYNC信号先后会有垂直同步信号前肩(VFPD)和垂直同步信号后肩(VBPD)出现,在这些信号时序内,不会有有效像素信号出现,另外HSYNC和VSYNC信号有效时,其电平要保持一定的时间,它们分别叫做水平同步信号脉宽HSPW和垂直同步信号脉宽VSPW,这段时间也不能有像素信号。因此计算行频和场频时,一定要包括这些信号。HBPD、HFPD和HSPW的单位是一个VCLK的时间,而VSPW、VFPD和VBPD的单位是扫描一行所用的时间。也是网上搜的。)

这些信号(VSPW、VFPD、VBPD、LINEVAL、HBPD、HFPD、HSPW和HOZVAL)是通过寄存器LCDCON2、LCDCON3和LCDCON4来配置的,具体查看s3c2440的手册。

LCDCON1寄存器:

 LINECNT :当前行扫描计数器值,标明当前扫描到了多少行。
 CLKVAL :决定VCLK的分频 比(上面已经提到过)。LCD控制器输出的VCLK是直接由系统总线(AHB) 的工作频率HCLK(一般为100MHZ)直接分频得到的。做为240*320的TFT屏,应保证得出的VCLK在5~10MHz之间。
 MMODE :VM信号的触发模式(仅对STN屏有效,对TFT屏无意义。)PNRMODE :选择当前的显示模式, 对于TFT屏而言,应选择[11],即TFT LCD panel。
 BPPMODE :选择色彩模式,对于真彩显示而言,选择16bpp(64K色)即可满足要求。
ENVID :使能LCD信号输出

LCDCON5寄存器:

 VSTATUS :当前VSYNC信号扫描状态,指明当前VSYNC同步信号处于何种扫描阶段。

 HSTATUS :当前HSYNC信号扫描状态,指明当前HSYNC同步信号处于何种扫描阶段。
 BPP24BL :设定24bpp显示模式时,视频资料在显示缓冲区中的排列顺序(即低位有效还是高位有效)。对于16bpp的 64K色显示模式,该设置位无意义。
 FRM565 :对于16bpp显示模式,有2中形式,一种是RGB=5:5:5:1,另一种是5:6:5。后一 种模式最为 常用,它的含义是表示64K种色彩的16bit RGB资料中,红色(R)占了5bit,绿色(G)占了6bit,兰色(B)占了5bit。
 INVVCLK 、INVLINE 、INVFRAME 、INVVD :通过前面提到的‘Figure 15-6’的时序图,我们知道,CPU的LCD控制器输出的时序默认是正脉冲,而LCD需要VSYNC(VFRAME)、 VLINE(HSYNC)均为负脉冲,因此 INVLINE 和 INVFRAME 必须设为“1 ”,即选择反相输出。 INVVDEN , INVPWREN , INVLEND 的功能同前面的类似。
    PWREN :LCD电源使能控制。在CPU LCD控制器的输出信号中,有一个电源使能管脚LCD_PWREN,用来做为LCD屏电源的开关信号。
   ENLEND :对普通的TFT屏无效,可以不考虑。
   INVVDEN、INVPWREN、INVLEND:是否翻转这些信号,一般为正常,不需要翻转。
   BSWP 、HWSWP : 为字节(Byte)或半字(Half-Word)交换使能。由于不同的GUI对FrameBuffer(显示缓冲区)的管理不同,必要时需要通过调整 BSWP 和 HWSWP
 来适应GUI。

因此:

代码

//for LCDCON1
#define CLKVAL_TFT       4            //设置时钟信号
#define MVAL_USED        0            //
#define PNRMODE_TFT      3            //TFT型LCD
#define BPPMODE_TFT      13           //24位TFT型LCD
//for LCDCON5  
#define BPP24BL        0       //32位数据表示24位颜色值时,低位数据有效,高8位无效
#define INVVCLK        0       //像素值在VCLK下降沿有效
#define INVVLINE       1       //翻转HSYNC信号
#define INVVFRAME      1       //翻转VSYNC信号
#define INVVD          0       //正常VD信号极性
#define INVVDEN        0       //正常VDEN信号极性
#define PWREN          1       //使能PWREN信号
#define BSWP           0       //颜色数据字节不交换
#define HWSWP          0       //颜色数据半字不交换

rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(PNRMODE_TFT<<5)|(BPPMODE_TFT<<1)|0;
rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);
rLCDCON3=(HBPD<<19)|(HOZVAL<<8)|(HFPD);
rLCDCON4=(HSPW);//

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

LCDSADDR1和LCDSADDR2:
              LCDBASEL=LCDBASEU+(PAGEWITH+OFFSIZE)×(LINEVAL+1

LCDSADDR3寄存器:
OFFSIZE:用于虚拟屏幕的偏移长度,如果我们不使用虚拟屏幕,就把它置为0

PAGEWIDTH:定义了视口的宽,单位是半字,如在上面的例子中,PAGEWIDTH应该为320×32÷16。

#define M5D(n)  ((n) & 0x1fffff)     //用于设置显示缓存区时,取低21位地址
//定义显示缓存区
volatile U32 LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];
rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)LCD_BUFFER>>1);
rLCDSADDR2=M5D((M5D((U32)LCD_BUFFER>>1)+((LCD_WIDTH*32/16+0)*320)));
rLCDSADDR3=(LCD_WIDTH*32/16)&0x7ff;//参考s3c2440的手册

简单程序实现:

代码
这里写代码片//*****************************************

#include "def.h"
#include "option.h"
#include "2440addr.h"     
#include "2440lib.h"
#include "2440slib.h"      
//================================

#define M5D(n)  ((n) & 0x1fffff)     //用于设置显示缓存区时,取低21位地址
#define LCD_WIDTH   240              //屏幕的宽
#define LCD_HEIGHT  320              //屏幕的高

//垂直同步信号的脉宽、后肩和前肩-----这些值是根据TopPoly-TD035STED4.pdf文件中的13页的表
#define VSPW      1 //(3-1)
#define VBPD      1 //(15-1)
#define VFPD      1 //(12-1)

//水平同步信号的脉宽、后肩和前肩-----这些值是根据TopPoly-TD035STED4.pdf文件中的13页的表
#define HSPW       (10-1)
#define HBPD       (20-1)
#define HFPD        (10-1)

//显示尺寸
#define LINEVAL  (LCD_HEIGHT-1)
#define HOZVAL   (LCD_WIDTH-1)

//for LCDCON1
#define CLKVAL_TFT          4            //设置时钟信号
#define MVAL_USED          0            //
#define PNRMODE_TFT      3            //TFT型LCD
#define BPPMODE_TFT      13           //24位TFT型LCD

//for LCDCON5  
#define BPP24BL        0       //32位数据表示24位颜色值时,低位数据有效,高8位无效
#define INVVCLK        0       //像素值在VCLK下降沿有效
#define INVVLINE       1       //翻转HSYNC信号
#define INVVFRAME      1       //翻转VSYNC信号
#define INVVD          0       //正常VD信号极性
#define INVVDEN        0       //正常VDEN信号极性
#define PWREN          1       //使能PWREN信号
#define BSWP           0       //颜色数据字节不交换
#define HWSWP          0       //颜色数据半字不交换
这里写代码片
//定义显示缓存区
volatile U32 LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];
//**********************************************************

//延时程序
void delay(int a)
{
       int k;
       for(k=0;k<a;k++)              ;
}

//绘制屏幕背景颜色,颜色为c
void Brush_Background( U32 c)
{
   int x,y ;
    for( y = 0 ; y < LCD_HEIGHT ; y++ )
    {
        for( x = 0 ; x < LCD_WIDTH ; x++ )
        {
            LCD_BUFFER[y][x] = c ;
        }
    }
}

 void init_port_lcd()
 {
    rGPCCON = 0xaaaaaaaa;       
        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; 

    rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(PNRMODE_TFT<<5)|(BPPMODE_TFT<<1)|0;
    rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);
    rLCDCON3=(HBPD<<19)|(HOZVAL<<8)|(HFPD);
    rLCDCON4=(HSPW);
    //rLCDCON4 =  (5<< 0);
    rLCDCON5 = (BPP24BL<<12) | (INVVCLK<<10) | (INVVLINE<<9) | (INVVFRAME<<8) | (0<<7) | (INVVDEN<<6) | (PWREN<<3)  |(BSWP<<1) | (HWSWP);

    rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)LCD_BUFFER>>1);
    rLCDSADDR2=M5D( (M5D((U32)LCD_BUFFER>>1)+((LCD_WIDTH*32/16+0)*320))  );//LCD_WIDTH*LCD_HEIGHT*4
    rLCDSADDR3=(LCD_WIDTH*32/16)&0x7ff;//参考s3c2440的手册
    rLCDINTMSK|=(3);      // 屏蔽LCD中断
    //rTCONSEL = 0;            //无效LPC3480
        rTCONSEL   &= (~7);


        rTPAL     = 0x0;
        rTCONSEL &= ~((1<<4) | 1);

    rGPGUP=rGPGUP&(~(1<<4))|(1<<4);      //GPG4上拉电阻无效
    rGPGCON=rGPGCON&(~(3<<8))|(3<<8); //设置GPG4为LCD_PWREN
    rGPGDAT = rGPGDAT | (1<<4) ;               //GPG4置1

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

    rLCDCON1|=1;                   //LCD开启
 }

int Main(int argc, char **argv)
{
    int i;
    U8 key;
    U32 mpll_val=0;
    int data;

    mpll_val = (92<<12)|(1<<4)|(1);

    //init FCLK=400M, so change MPLL first
    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
    ChangeClockDivider(key, 12);    

    //ChangeClockDivider(1,1);    // 1:2:4    FCLK:HCLK:PCLK
        // rCLKDIVN=0x4;    //  1:4:4
        //ChangeMPllValue(82,2,1);     //FCLK=135.0Mhz     
    //ChangeMPllValue(82,1,1);     //FCLK=180.0Mhz     
        //ChangeMPllValue(161,3,1);    //FCLK=202.8Mhz 
        //ChangeMPllValue(117,1,1);    //FCLK=250.0Mhz 
        //ChangeMPllValue(122,1,1);    //FCLK=260.0Mhz 
        //ChangeMPllValue(125,1,1);    //FCLK=266.0Mhz 
        //ChangeMPllValue(127,1,1);    //FCLK=270.0Mhz  

        //MMU_EnableICache();
        //MMU_EnableDCache();

        MMU_DisableICache();
        MMU_DisableDCache();

    init_port_lcd();
    while(1)
    {
        //黑色背景
        Brush_Background(0x0000);
        delay(5000000);
        //白色背景
        Brush_Background(0xffffff);
        delay(5000000);
        //蓝色背景
        Brush_Background(0x00ff);
        delay(5000000);
        //绿色背景
        Brush_Background(0xff00);
        delay(5000000);
        //黄色背景
        Brush_Background(0xffff00);
        delay(5000000);
    }
   return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39420903/article/details/81225204