现在的位置: 首页 > 综合 > 正文

lcd裸机驱动程序设计

2017年08月25日 ⁄ 综合 ⁄ 共 8912字 ⁄ 字号 评论关闭

驱动程序流程----

1----LCD初始化

---端口初始化

---显示模式初始化

---帧缓冲初始化

2----将图像写入帧缓冲


端口初始化----------

GPC5       

GPC6

GPC7

未用-----


GPC0-------10

lineend 信


static void Lcd_Port_Init( void )
{
    rGPCUP=0xffffffff; // Disable Pull-up register
    rGPCCON=0xaaaa02a8; //1010 1010 1010 1010 0000 0010 1010 1000Initialize VD[7:0],VM,VFRAME,VLINE,VCLK

    rGPDUP=0xffffffff; // Disable Pull-up register
    rGPDCON=0xaaaaaaaa; //Initialize VD[15:8]
}

显示模式初始化----------------------------------------------

CLKVAL---

确定VCLK频率的参数,单位为HZ。

MMODE--

确定VM的改变速度。在此选择MMODE=0,为每帧变化模式

VM----通过VM信号改变控制像素点得显示或熄灭。

PNRMODE---

确定扫描方式。选择PNRMODE=0x3,为TFT LCD面板扫描模式。

BPPMODE--

确定BPP(每像素位数)模式。在此选择BPPMODE=0xc,为TFT16位模式。

ENVID----

数据输出和逻辑信号使能控制位。选择ENVID=1,为允许数据输出和逻辑控制

LCD_PIXCLOCK=4;

/*bit[17:8](4:CLKVAL);bit[6:5](11:TFT LCD panel);bit[4:1](1100:16 bpp for TFT)*/
    rLCDCON1 = (LCD_PIXCLOCK << 8) | (3 <<  5) | (12 << 1);

0100 0000 0000

0000 0110 0000

0000 0001 1000

0100 0111  1000     


static void Lcd_EnvidOnOff(int onoff)
{
    if(onoff==1)
    rLCDCON1|=1; // ENVID=ON
    else
    rLCDCON1 =rLCDCON1 & 0x3fffe; // ENVID Off
}


#define LCD_UPPER_MARGIN 1

#define LCD_LOWER_MARGIN 5

#define LCD_HEIGHT 320

#define LCD_HSYNC_LEN 5

/*bit[31:24](1:VBPD);bit[23:14](320-1:行数);bit[13:6](5:VFPD);bit[5:0](1:VSPW)*/
       rLCDCON2 = (LCD_UPPER_MARGIN << 24) | ((LCD_HEIGHT - 1) << 14) | (LCD_LOWER_MARGIN << 6) | (LCD_VSYNC_LEN << 0);



VBPD----表示一帧图像开始时,帧同步信号以后的无效的行数,对应驱动中的upper_margin

VFBD-----表示在一帧图像结束后,帧同步信号以前的无效的行数,对应驱动中的lower_margin

VSPW-----表示垂直同步脉冲的宽带用行数计算,对应驱动中的vsync_len

LINEVAL----确定显示的垂直方向的尺寸

LINEVAL=YSIZE-1=479

若是480行,LINEVAL=479;


HBPD------表示从水平同步信号开始到一行有效数据开始之间的VCLK的个数,对应驱动中的left_margin

HFPD------表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK个数,对应

HOZVAL----确定显示的水平方向尺寸

公式HOZVAL=XSIZE-1

就是决定显示器有多少列。

/*bit[25:19](36:HBPD);bit[18:8](240-1:列数);bit[7:0](19:HFPD)*/
       rLCDCON3 = (LCD_RIGHT_MARGIN << 19) | ((LCD_WIDTH  - 1) <<  8) | (LCD_LEFT_MARGIN << 0);



HSPW-----表示水平同步信号的宽带,用VCLK计算,对应驱动中的hsync_len

/*bit[15:8](13:MVAL,只有当LCDCON1 bit[7]MMODE=1才有效);bit[7:0](5:HSPW)*/
       rLCDCON4 = (13 <<  8) | (LCD_HSYNC_LEN << 0);

/*bit[11](5:6:5 Format);bit[9](VLINE/HSYNC polarity inverted);bit[8](VFRAME/VSYNC inverted)
      bit[3](Enalbe PWERN signal),bit[1](half-word swap control bit)*/
    rLCDCON5   =  (1<<11) | (1 << 9) | (1 << 8) | (1 << 3) | (1 << 0);

FRM565---------三基色模式选择

帧缓冲初始化----告诉lcd控制器,帧缓冲--显示缓存的位置。

记录了帧缓冲的起始地址。



/*帧缓冲地址初始化*/
    /*
    LCDBANK: 视频帧缓冲区内存地址30-22位
    LCDBASEU: 视频帧缓冲区的开始地址21-1位
    LCDBASEL: 视频帧缓冲区的结束地址21-1位
    */
    /*bit[29:21]:LCDBANK,bit[20:0]:LCDBASEU*/
        rLCDSADDR1 = ((LCD_ADDR >> 22) << 21) | ((M5D(LCD_ADDR >> 1)) <<  0);
    
        /*bit[20:0]:LCDBASEL*/
        rLCDSADDR2 = M5D((LCD_ADDR + LCD_WIDTH * LCD_HEIGHT * 2) >> 1);
    
    
        /*PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数
      OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为0
    */
    /*bit[21:11]:OFFSIZE; bit[10:0]:PAGEWIDTH*/
        rLCDSADDR3 = LCD_WIDTH;       

#define    GLOBAL_CLK        1
#include <stdlib.h>
#include <string.h>
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include "mmu.h"
#include "profile.h"
#include "memtest.h"



#define LCD_N35 //NEC 256K色240*320/3.5英寸TFT真彩液晶屏,每一条水平线上包含240个像素点,共有320条这样的线

#if defined(LCD_N35)

#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_PIXCLOCK 4

#define LCD_RIGHT_MARGIN 39
#define LCD_LEFT_MARGIN 16
#define LCD_HSYNC_LEN 5

#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 5
#define LCD_VSYNC_LEN 1

#endif

void TFT_LCD_Test(void);

#define LCD_XSIZE  LCD_WIDTH
#define LCD_YSIZE  LCD_HEIGHT
#define SCR_XSIZE  LCD_WIDTH
#define SCR_YSIZE  LCD_HEIGHT

volatile static unsigned short LCD_BUFFER[SCR_YSIZE][SCR_XSIZE];  //定义320行,240列的数组,用于存放显示数据

extern unsigned char sunflower_240x320[];

#define    M5D(n)    ((n)&0x1fffff)
#define LCD_ADDR ((U32)LCD_BUFFER)

#define ADC_FREQ 2500000

volatile U32 preScaler;

static void cal_cpu_bus_clk(void);
void Set_Clk(void);

/*演示函数*/
void delay(int times)
{
    int i,j;
    for(i=0;i<times;i++)
       for(j=0;j<400;j++);
}

/*在屏幕上画图*/
static void Pait_Bmp(int x0,int y0,int h,int l,const unsigned char *bmp)
{
    int x,y;
    U32 c;
    int p = 0;
    
    for( y = 0 ; y < l ; y++ )
    {
        for( x = 0 ; x < h ; x++ )
        {
            c = bmp[p+1] | (bmp[p]<<8) ;

        if ( ( (x0+x) < SCR_XSIZE) && ( (y0+y) < SCR_YSIZE) )
            LCD_BUFFER[y0+y][x0+x] = c ;

            p = p + 2 ;
        }
    }
}


/*填充全屏为某一颜色*/
static void Lcd_ClearScr( U16 c)
{
    unsigned int x,y ;
        
    for( y = 0 ; y < SCR_YSIZE ; y++ )
    {
        for( x = 0 ; x < SCR_XSIZE ; x++ )
        {
        LCD_BUFFER[y][x] = c ;
        }
    }
}


/*LCD开关*/
static void Lcd_EnvidOnOff(int onoff)
{
    if(onoff==1)
    rLCDCON1|=1; // ENVID=ON
    else
    rLCDCON1 =rLCDCON1 & 0x3fffe; // ENVID Off
}


/*端口初始化*/
static void Lcd_Port_Init( void )
{
    rGPCUP=0xffffffff; // Disable Pull-up register
    rGPCCON=0xaaaa02a8; //Initialize VD[7:0],VM,VFRAME,VLINE,VCLK

    rGPDUP=0xffffffff; // Disable Pull-up register
    rGPDCON=0xaaaaaaaa; //Initialize VD[15:8]
}

/*LCD初始化*/
static void LCD_Init(void)
{
    Lcd_Port_Init();

    /*显示模式初始化*/
    /*bit[17:8](4:CLKVAL);bit[6:5](11:TFT LCD panel);bit[4:1](1100:16 bpp for TFT)*/
    rLCDCON1 = (LCD_PIXCLOCK << 8) | (3 <<  5) | (12 << 1);
    
    /*bit[31:24](1:VBPD);bit[23:14](320-1:行数);bit[13:6](5:VFPD);bit[5:0](1:VSPW)*/
       rLCDCON2 = (LCD_UPPER_MARGIN << 24) | ((LCD_HEIGHT - 1) << 14) | (LCD_LOWER_MARGIN << 6) | (LCD_VSYNC_LEN << 0);
       
       /*bit[25:19](36:HBPD);bit[18:8](240-1:列数);bit[7:0](19:HFPD)*/
       rLCDCON3 = (LCD_RIGHT_MARGIN << 19) | ((LCD_WIDTH  - 1) <<  8) | (LCD_LEFT_MARGIN << 0);
       
       /*bit[15:8](13:MVAL,只有当LCDCON1 bit[7]MMODE=1才有效);bit[7:0](5:HSPW)*/
       rLCDCON4 = (13 <<  8) | (LCD_HSYNC_LEN << 0);
       
       /*bit[11](5:6:5 Format);bit[9](VLINE/HSYNC polarity inverted);bit[8](VFRAME/VSYNC inverted)
      bit[3](Enalbe PWERN signal),bit[1](half-word swap control bit)*/
    rLCDCON5   =  (1<<11) | (1 << 9) | (1 << 8) | (1 << 3) | (1 << 0);
    
    
    

        /*帧缓冲地址初始化*/
    /*
    LCDBANK: 视频帧缓冲区内存地址30-22位
    LCDBASEU: 视频帧缓冲区的开始地址21-1位
    LCDBASEL: 视频帧缓冲区的结束地址21-1位
    */
    /*bit[29:21]:LCDBANK,bit[20:0]:LCDBASEU*/
        rLCDSADDR1 = ((LCD_ADDR >> 22) << 21) | ((M5D(LCD_ADDR >> 1)) <<  0);
    
        /*bit[20:0]:LCDBASEL*/
        rLCDSADDR2 = M5D((LCD_ADDR + LCD_WIDTH * LCD_HEIGHT * 2) >> 1);
    
    
        /*PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数
      OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为0
    */
    /*bit[21:11]:OFFSIZE; bit[10:0]:PAGEWIDTH*/
        rLCDSADDR3 = LCD_WIDTH;        

    /*屏蔽中断*/
        rLCDINTMSK |= 3;
      rTCONSEL   &= (~7);
 
    /*disable调色板*/
       rTPAL = 0x0;
       
       /*禁止LPC3600/LCC3600模式*/
       rTCONSEL &= ~((1<<4) | 1);
       
       /*打开LCD*/
       Lcd_EnvidOnOff(1);    

}


void TFT_LCD_Show(void)
{    
    /*红(255:0:0);绿(0:255:0);蓝(0:0:255);黑(0:0:0);白(255,255,255)*/
    
    /*在屏幕上显示三基色*/
    
    Lcd_ClearScr( (0x00<<11) | (0x00<<5) | (0x00)  )  ;        //clear screen black
    delay(10000);
        
    Lcd_ClearScr((0x1f<<11) | (0x00<<5) | (0x00));            //red
    delay(10000);
        
    Lcd_ClearScr((0x00<<11) | (0x3f<<5) | (0x00));            //green
    delay(10000);
    
    Lcd_ClearScr((0x00<<11) | (0x00<<5) | (0x1f));            //blue
    delay(10000);

    Lcd_ClearScr( (0x1f<<11) | (0x3f<<5) | (0x1f)  )  ;        //clear screen white
    delay(10000);
    
    /*显示一副图片在屏幕上*/
    Pait_Bmp(0, 0, 240, 320, sunflower_240x320);
}
   

/*************************************************
Function name: Set_Clk()
Parameter    : void
Description     : 设置CPU的时钟频率
Return         : void
Argument     : void
Autor & date : Daniel
**************************************************/
void Set_Clk(void)
{
    int i;
    U8 key;
    U32 mpll_val = 0 ;
    i = 2 ;                 //don't use 100M!
                         //boot_params.cpu_clk.val = 3;
    switch ( i ) {
    case 0:    //200
        key = 12;
        mpll_val = (92<<12)|(4<<4)|(1);
        break;
    case 1:    //300
        key = 13;
        mpll_val = (67<<12)|(1<<4)|(1);
        break;
    case 2:    //400
        key = 14;
        mpll_val = (92<<12)|(1<<4)|(1);
        break;
    case 3:    //440!!!
        key = 14;
        mpll_val = (102<<12)|(1<<4)|(1);
        break;
    default:
        key = 14;
        mpll_val = (92<<12)|(1<<4)|(1);
        break;
    }
    
    //init FCLK=400M, so change MPLL first
    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);   //set the register--rMPLLCON
    ChangeClockDivider(key, 12);    //the result of rCLKDIVN [0:1:0:1] 3-0 bit
    cal_cpu_bus_clk();    //HCLK=100M   PCLK=50M
}
/*************************************************
Function name: cal_cpu_bus_clk
Parameter    : void
Description     : 设置PCLK\HCLK\FCLK的频率
Return         : void
Argument     : void
Autor & date : Daniel
**************************************************/
static void cal_cpu_bus_clk(void)
{
    static U32 cpu_freq;
    static U32 UPLL;
    
    U32 val;
    U8 m, p, s;
    
    val = rMPLLCON;
    m = (val>>12)&0xff;
    p = (val>>4)&0x3f;
    s = val&3;

    //(m+8)*FIN*2 不要超出32位数!
    FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;     //FCLK=400M  FIN=12000000
    
    val = rCLKDIVN;
    m = (val>>1)&3;
    p = val&1;    
    val = rCAMDIVN;
    s = val>>8;
    
    switch (m) {
    case 0:
        HCLK = FCLK;
        break;
    case 1:
        HCLK = FCLK>>1;
        break;
    case 2:
        if(s&2)
            HCLK = FCLK>>3;
        else
            HCLK = FCLK>>2;
        break;
    case 3:
        if(s&1)
            HCLK = FCLK/6;
        else
            HCLK = FCLK/3;
        break;
    }
    
    if(p)
        PCLK = HCLK>>1;
    else
        PCLK = HCLK;
    
    if(s&0x10)
        cpu_freq = HCLK;
    else
        cpu_freq = FCLK;
        
    val = rUPLLCON;
    m = (val>>12)&0xff;
    p = (val>>4)&0x3f;
    s = val&3;
    UPLL = ((m+8)*FIN)/((p+2)*(1<<s));
    UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;
    Uart_Printf("\nFCLK:%dMHz,HCLK:%dMHz,PCLK=%dMHZ\n",FCLK/1000/1000,HCLK/1000/1000,PCLK/1000/1000);
}

/*主函数*/
int Main(void)
{    
    Set_Clk();
    
    LCD_Init();
    
    TFT_LCD_Show();
    
    return 0;
}

抱歉!评论已关闭.