S3C2440驱动开发(六)

裸机程序开发之LCD程序

先上代码,代码有点长,共409行。涉及到的寄存器比较多。本节只做代码解释,详细原理不再这里展开。

#include "def.h"

#include "option.h"

#include "2440addr.h"    

#include "2440lib.h"

#include "2440slib.h"

#include "mmu.h"

//================================

#define LCD_WIDTH 240

#define LCD_HEIGHT 320

 

#define LCD_XSIZE  LCD_WIDTH

#define LCD_YSIZE  LCD_HEIGHT

#define SCR_XSIZE  LCD_WIDTH

#define SCR_YSIZE  LCD_HEIGHT

 

#define LCD_PIXCLOCK 4

#define LCD_RIGHT_MARGIN 100

#define LCD_LEFT_MARGIN 0

#define LCD_HSYNC_LEN 4

 

#define LCD_UPPER_MARGIN 0

#define LCD_LOWER_MARGIN 0

#define LCD_VSYNC_LEN 9

 

#define LCD_CON5 ((1<<11) | (1<<10) | (1<<8) | (1<<9) | (1<<0) )

 

void Delay(int time);

void TFT_LCD_Test(void);

void Lcd_Port_Init(void);

void LCD_Init(void);

void LcdBkLtSet(U32 HiRatio);

void Lcd_PowerEnable(int invpwren,int pwren);

void Lcd_EnvidOnOff(int onoff);

void Lcd_ClearScr( U16 c);

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

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

void Glib_Line(int x1,int y1,int x2,int y2, U16 color);

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

 

extern const unsigned char sunflower_240x320[];

volatile static unsigned short LCD_BUFFER[SCR_YSIZE][SCR_XSIZE];

 

void Delay(int time)

{

         U32 val = (PCLK>>3)/1000-1;

 

         rTCFG0 &= ~(0xff<<8);

         rTCFG0 |= 3<<8;                         //prescaler = 3+1

         rTCFG1 &= ~(0xf<<12);

         rTCFG1 |= 0<<12;             //mux = 1/2

 

         rTCNTB3 = val;

         rTCMPB3 = val>>1;           // 50%

         rTCON &= ~(0xf<<16);

         rTCON |= 0xb<<16;          //interval, inv-off, update TCNTB3&TCMPB3, start timer 3

         rTCON &= ~(2<<16);                  //clear manual update bit

         while(time--) {

                   while(rTCNTO3>=val>>1);

                   while(rTCNTO3<val>>1);

         };

}

 

int Main(int argc, char **argv)

{

         int i;

         U8 key;

         U32 mpll_val=0;

         int data;

         int readLength = 0;

         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);

 

         Uart_Init( 0,115200 );

         Uart_Select( 0 );

 

         rEXTINT0 = 0x22222222;    // EINT[7:0]

         rEXTINT1 = 0x22222222;    // EINT[15:8]

         rEXTINT2 = 0x22222222;    // EINT[23:16]

 

         pISR_SWI=(_ISR_STARTADDRESS+0xf0);

 

         Buzzer_Freq_Set( 2000 );

         Delay( 200 );

         Buzzer_Stop();

 

         Uart_SendByte('\n');

         Uart_Printf("<***********************************************>\n");

         Uart_Printf("\nKey Test\n");

         Uart_Printf("<***********************************************>\n");

 

//      rDSC0 = 0x2aa;

//      rDSC1 = 0x2aaaaaaa;

         //Enable NAND, USBD, PWM TImer, UART0,1 and GPIO clock,

         rCLKCON = 0xfffff0;

 

         MMU_Init();

 

//    MMU_DisableICache();

//    MMU_DisableDCache();

 

         TFT_LCD_Test();

 

     data = 0x06;

     while(1)

     {

//                     Uart_Printf("\nPlease input command : \n");

//                     Uart_Getch();

//               Uart_Printf("Your input string : \n");

//               Uart_SendByte(key);

 

         }

 

   return 0;

}

 

void TFT_LCD_Test(void)

{

         Uart_Printf("\nTest TFT LCD 240x320!\n");

 

    Lcd_Port_Init();

    LCD_Init();

         LcdBkLtSet( 70 ) ;

         Lcd_PowerEnable(0, 1);

    Lcd_EnvidOnOff(1);           //turn on vedio

 

         Lcd_ClearScr( (0x00<<11) | (0x00<<5) | (0x00)  )  ;              //clear screen

         Uart_Printf( "\nLCD clear screen is finished! press any key to continue!\n" );

    Uart_Getch() ;          //wait uart input

 

         Lcd_ClearScr( (0x1f<<11) | (0x3f<<5) | (0x1f)  )  ;                 //clear screen

         Uart_Printf( "LCD clear screen is finished! press any key to continue!\n" );

    Uart_Getch() ;          //wait uart input

 

         Lcd_ClearScr(0xffff);                  //fill all screen with some color

         #define LCD_BLANK                  30

         #define C_UP            ( LCD_XSIZE - LCD_BLANK*2 )

         #define C_RIGHT              ( LCD_XSIZE - LCD_BLANK*2 )

         #define V_BLACK              ( ( LCD_YSIZE - LCD_BLANK*4 ) / 6 )

         Glib_FilledRectangle( LCD_BLANK, LCD_BLANK, ( LCD_XSIZE - LCD_BLANK ), ( LCD_YSIZE - LCD_BLANK ),0x0000);           //fill a Rectangle with some color

 

         Glib_FilledRectangle( (LCD_BLANK*2), (LCD_BLANK*2 + V_BLACK*0), (C_RIGHT), (LCD_BLANK*2 + V_BLACK*1),0x001f);                   //fill a Rectangle with some color

         Glib_FilledRectangle( (LCD_BLANK*2), (LCD_BLANK*2 + V_BLACK*1), (C_RIGHT), (LCD_BLANK*2 + V_BLACK*2),0x07e0);                   //fill a Rectangle with some color

         Glib_FilledRectangle( (LCD_BLANK*2), (LCD_BLANK*2 + V_BLACK*2), (C_RIGHT), (LCD_BLANK*2 + V_BLACK*3),0xf800);                   //fill a Rectangle with some color

         Glib_FilledRectangle( (LCD_BLANK*2), (LCD_BLANK*2 + V_BLACK*3), (C_RIGHT), (LCD_BLANK*2 + V_BLACK*4),0xffe0);                   //fill a Rectangle with some color

         Glib_FilledRectangle( (LCD_BLANK*2), (LCD_BLANK*2 + V_BLACK*4), (C_RIGHT), (LCD_BLANK*2 + V_BLACK*5),0xf81f);                   //fill a Rectangle with some color

         Glib_FilledRectangle( (LCD_BLANK*2), (LCD_BLANK*2 + V_BLACK*5), (C_RIGHT), (LCD_BLANK*2 + V_BLACK*6),0x07ff);                   //fill a Rectangle with some color

     Uart_Printf( "LCD color test, please look! press any key to continue!\n" );

    Uart_Getch() ;          //wait uart input

 

         Paint_Bmp(0, 0, 240, 320, sunflower_240x320);

     Uart_Printf( "LCD paint a bmp, please look! press any key to continue! \n" );

    Uart_Getch() ;          //wait uart input

 

    Lcd_EnvidOnOff(0);          //turn off vedio

}

 

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]

}

 

void LCD_Init(void)

{

#define     M5D(n)    ((n)&0x1fffff)

#define LCD_ADDR ((U32)LCD_BUFFER)

         rLCDCON1 = (LCD_PIXCLOCK << 8) | (3 <<  5) | (12 << 1);

     rLCDCON2 = (LCD_UPPER_MARGIN << 24) | ((LCD_HEIGHT - 1) << 14) | (LCD_LOWER_MARGIN << 6) | (LCD_VSYNC_LEN << 0);

     rLCDCON3 = (LCD_RIGHT_MARGIN << 19) | ((LCD_WIDTH  - 1) <<  8) | (LCD_LEFT_MARGIN << 0);

     rLCDCON4 = (13 <<  8) | (LCD_HSYNC_LEN << 0);

 

//#if !defined(LCD_CON5)

//#    define LCD_CON5 ((1<<11) | (1 << 9) | (1 << 8) | (1 << 3) | (1 << 0))

//#endif

    rLCDCON5   =  LCD_CON5;

 

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

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

    rLCDSADDR3 = LCD_WIDTH;

 

    rLCDINTMSK |= 3;

       rTCONSEL   &= (~7);

 

     rTPAL     = 0x0;

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

}

 

void LcdBkLtSet(U32 HiRatio)

{

#define FREQ_PWM1                1000

 

         if(!HiRatio)

         {

                   rGPBCON  = rGPBCON & (~(3<<2)) | (1<<2) ;        //GPB1设置为output

                   rGPBDAT &= ~(1<<1);

                   return;

         }

         rGPBCON = rGPBCON & (~(3<<2)) | (2<<2) ;            //GPB1设置为TOUT1

 

         if( HiRatio > 100 )

                   HiRatio = 100 ;

 

         rTCON = rTCON & (~(0xf<<8)) ;                          // clear manual update bit, stop Timer1

 

         rTCFG0   &= 0xffffff00;                                        // set Timer 0&1 prescaler 0

         rTCFG0 |= 15;                                                          //prescaler = 15+1

 

         rTCFG1   &= 0xffffff0f;                                         // set Timer 1 MUX 1/16

         rTCFG1  |= 0x00000030;                                             // set Timer 1 MUX 1/16

 

         rTCNTB1  = ( 100000000>>8 )/FREQ_PWM1;                  //if set inverter off, when TCNT2<=TCMP2, TOUT is high, TCNT2>TCMP2, TOUT is low

         rTCMPB1  = ( rTCNTB1*(100-HiRatio))/100 ;        //if set inverter on,  when TCNT2<=TCMP2, TOUT is low,  TCNT2>TCMP2, TOUT is high

 

         rTCON = rTCON & (~(0xf<<8)) | (0x0e<<8) ;

         //自动重装,输出取反关闭,更新TCNTBn、TCMPBn,死区控制器关闭

         rTCON = rTCON & (~(0xf<<8)) | (0x0d<<8) ;             //开启背光控制

}

 

void Lcd_PowerEnable(int invpwren,int pwren)

{

    //GPG4 is setted as LCD_PWREN

    rGPGUP = rGPGUP|(1<<4); // Pull-up disable

    rGPGCON = rGPGCON|(3<<8); //GPG4=LCD_PWREN

 

    //Enable LCD POWER ENABLE Function

    rLCDCON5 = rLCDCON5&(~(1<<3))|(pwren<<3);   // PWREN

    rLCDCON5 = rLCDCON5&(~(1<<5))|(invpwren<<5);   // INVPWREN

}

 

void Lcd_EnvidOnOff(int onoff)

{

    if(onoff==1)

         rLCDCON1|=1; // ENVID=ON

    else

         rLCDCON1 =rLCDCON1 & 0x3fffe; // ENVID Off

}

 

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 ;

             }

    }

}

 

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

{

    int i;

 

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

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

}

 

void Paint_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 ;

             }

    }

}

 

void Glib_Line(int x1,int y1,int x2,int y2, U16 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 PutPixel(U32 x,U32 y,U16 c)

{

    if(x<SCR_XSIZE && y<SCR_YSIZE)

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

}

函数TFT_LCD_Test是LCD显示的核心代码。

函数Lcd_Port_Init用于初始化LCD的端口。

查看原理图可知端口GPC0~GP7为LCD控制信号,GPC8~GPC15,GPD0~GPD15为VD信号。

rGPCUP=0xffffffff;//禁用C端口所有引脚的上拉电阻功能,显示屏显示不需要上拉。

rGPCCON=0xaaaa02a8;//设置了 GPC0~GP7中VM,VFRAME,VLINE,VCLK四种LCD控制信号,GPC8~GPC15为VD信号。

rGPDUP=0xffffffff;//禁用D端口所有引脚的上拉电阻功能,显示屏显示不需要上拉。

rGPDCON=0xaaaaaaaa;//设置GPD0~GPD15为VD信号。

详细定义查看以下两张表。

 

rLCDCON1 = (LCD_PIXCLOCK << 8) | (3 << 5) | (12 << 1);// LCDCON1的bit8~17为CLKVAL ,而VCLK = HCLK / [(CLKVAL+1) x 2]。VCLK为显示屏的时钟信号。LCD_PIXCLOCK宏展开后为4,经简单计算VCLK=100MHz/((4+1)*2)=10MHz。LCDCON1的bit5~6为PNRMODE,用于显示模式,此处的3表示TFT LCD显示屏。LCDCON1的bit1~4为BPPMODE,表示每个像素对应的bit位数,此处的12表示每个像素对应16位。

rLCDCON2 = (LCD_UPPER_MARGIN << 24) | ((LCD_HEIGHT - 1) << 14) | (LCD_LOWER_MARGIN << 6) | (LCD_VSYNC_LEN << 0);// LCDCON2的bit24~31为VBPD,表示垂直同步周期后一帧中起始位置处未激活的行数,此处设置了0。LCDCON2的bit14~23为LINEVAL,表示显示屏的垂直尺寸,LINEVAL=实际垂直尺寸-1,此处设置320-1。LCDCON2的bit6~13为VFPD,表示表示垂直同步周期后一帧中终止位置处未激活的行数,此处设置了0。LCDCON2的bit0~5为VSPW,该值通过统计未激活行数确定了VSYNC的高电平宽度,此处设置9。

rLCDCON3 = (LCD_RIGHT_MARGIN << 19) | ((LCD_WIDTH  - 1) <<  8) | (LCD_LEFT_MARGIN << 0);// LCDCON3的bit19~25为HBPD,表示HSYNC的下降沿和起始激活数据之间的VCLK周期数,此处设置100。LCDCON3的bit8~18为HOZVAL,表示显示屏的水平尺寸HOZVAL=实际水平尺寸-1,此处设置240-1。LCDCON3的bit0~7为HFPD,表示终止位置处激活数据和HSYNC上升沿之间的VCLK周期数,此处设置0。

rLCDCON4 = (13 << 8) | (LCD_HSYNC_LEN << 0);// LCDCON4的bit8~15为MVAL,官方手册只对STN进行了描述,缺少TFT的描述。LCDCON4的bit0~7为HSPW,该值通过统计VCLK周期数确定了HSYNC的高电平宽度,此处设置4。

rLCDCON5 = LCD_CON5;// LCDCON5的bit11为FRM565,表示用于选择16bpp数据视频数据的格式,此处选择的是5:6:5颜色格式,该颜色格式可自行百度查询。LCDCON5的bit10为INVVCLK,表示视频数据在上升沿处抓取。LCDCON5的bit8为INVVFRAME,表示VFRAME/VSYNC的极性,此处这是为取反。LCDCON5的bit9为INVVLINE,表示VLINE/HSYNC的极性,此处这是为取反。LCDCON5的bit0为HWSWP,此处为交换启用。

rLCDSADDR1 = ((LCD_ADDR >> 22) << 21) | ((M5D(LCD_ADDR >> 1)) << 0);//LCDSADDR1的bit21~29为LCDBANK,表示系统内存中的视频数据缓冲区地址的bit22~30。LCDSADDR1的bit0~20为LCDBASEU,表示缓冲区地址的bit1~bit21。

rLCDSADDR2 = M5D((LCD_ADDR + LCD_WIDTH * LCD_HEIGHT * 2) >> 1);//LCDSADDR2的bit0~20为LCDBASEL。LCDBASEU和LCDBASEL可用于滚屏。详细说明后面补充。此处没有看懂。

rLCDSADDR3 = LCD_WIDTH;// LCDSADDR3的bit0~10为PAGEWIDTH,表示虚拟屏幕宽度,此处为实际屏幕宽度240。LCDSADDR3的bit11~21为OFFSIZE,表示虚拟屏幕偏移量。

rLCDINTMSK |= 3;//表示屏幕的帧同步中断和FIFO中断都被屏蔽。

rTCONSEL &= (~7);//表示模式选择同步模式,屏幕分辩率为320*240,禁用LPC3600。

rTPAL     = 0x0;//表示禁用调色板寄存器。

rTCONSEL &= ~((1<<4) | 1);//表示禁用LCC3600,禁用LPC3600。

 

函数LcdBkLtSet用于设置背光灯的亮度。

rGPBCON = rGPBCON & (~(3<<2)) | (2<<2) ;//将GPB0引脚设置为pwm输出。

之后代码是定时器1操作,可查看之前章节介绍。

 

函数Lcd_PowerEnable用于控制LCD电源引脚使能

rGPGUP = rGPGUP|(1<<4);//禁用GPG4的上拉电阻功能

rGPGCON = rGPGCON|(3<<8);//将GPG4引脚设置为LCD_PWREN

rLCDCON5 = rLCDCON5&(~(1<<3))|(pwren<<3);//设置LCD_PWREN是否输出

rLCDCON5 = rLCDCON5&(~(1<<5))|(invpwren<<5);//设置PWREN信号的极性

 

函数Lcd_EnvidOnOff用于控制视频信号输出

rLCDCON1|=1;//开启视频输出信号以及LCD控制信号

 

函数Lcd_ClearScr用于清屏,输入参数为清屏的颜色。

 

函数Glib_Line为绘制线条的逻辑,具体算法此处不做介绍。

 

函数Paint_Bmp用于绘制图片,参数分别是左上角左边和图片长宽,以及数据缓冲区地址。

 

显示效果图如下:

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值