您的位置:首页 > 其它

ARM9的LCD

2015-10-10 10:53 218 查看
实验前须知:
关于LCD的知识,你可以参考《嵌入式Linux应用开发完全手册》的第13章,只要你静下心来看,里边的知识点完全可以看懂。
待你看懂后,LCD的知识你就了解差不多了。接下来就从代码中去解读LCD的实际操作了。

操作LCD的大体流程如下:
1>配置GPIO为相应的功能管脚
2>配置寄存器,其中LCDCON1-LCDCON5和LCDSADDR1-LCDSADDR3可能相对难配置一点。待会在问题总结给大家解释。
3>LCD的实际操作(从代码中去理解吧)

实验的目的:
操作LCD,让其显示不同的画面。

实验的源程序:


lcd.rar


实验的问题总结:
I. 关于LCD比较关键的一点的就是Tft_Lcd_Init()这个函数。我们进入Tft_Lcd_Init(MODE_TFT_16BIT_480272)看一下吧。
在里边我们可以看到,主要是配置LCDCON1-LCDCON5和LCDSADDR1-LCDSADDR3这几个寄存器。刚开始看,我也没大整明白

为何要这样设置。现在我就给大伙讲讲这样配置的原因。

摘录其中一段源码如下:

case MODE_TFT_16BIT_480272:

        /* 

         * 设置LCD控制器的控制寄存器LCDCON1~5

         * 1. LCDCON1:

         *    设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2]

         *    选择LCD类型: TFT LCD   

         *    设置显示模式: 16BPP

         *    先禁止LCD信号输出

         * 2. LCDCON2/3/4:

         *    设置控制信号的时间参数

         *    设置分辨率,即行数及列数

         * 现在,可以根据公式计算出显示器的频率:

         * 当HCLK=100MHz时,

         * Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x

         *              {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x

         *              {2x(CLKVAL+1)/(HCLK)}]

         *            = 60Hz

* Frame Rate = 60Hz 是根据LCD手册来的。 /* LCD手册表示Dclk=9MHz~15MHz, HCLK=100MHz, Dclk=VCLK=HCLK/[(CLKVAL+1)x2]=100/((4+1)*2)=10MHz */ 从而就确定CLKVAL的值。

         * 3. LCDCON5:

         *    设置显示模式为16BPP时的数据格式: 5:6:5

         *    设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转

         *    半字(2字节)交换使能

         */

        LCDCON1 = (CLKVAL_TFT_480272<<8) | (LCDTYPE_TFT<<5) | \

                  (BPPMODE_16BPP<<1) | (ENVID_DISABLE<<0);

        LCDCON2 = (VBPD_480272<<24) | (LINEVAL_TFT_480272<<14) | \

                  (VFPD_480272<<6) | (VSPW_480272);

        LCDCON3 = (HBPD_480272<<19) | (HOZVAL_TFT_480272<<8) | (HFPD_480272);

        LCDCON4 = HSPW_480272;

        LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | \

                  (HWSWP<<1);

        /*

         * 设置LCD控制器的地址寄存器LCDSADDR1~3

         * 帧内存与视口(view point)完全吻合,

         * 图像数据格式如下:

         *         |----PAGEWIDTH----|

         *    y/x  0   1   2       479

         *     0   rgb rgb rgb ... rgb

         *     1   rgb rgb rgb ... rgb

         * 1. LCDSADDR1:

         *    设置LCDBANK、LCDBASEU

         * 2. LCDSADDR2:

         *    设置LCDBASEL: 帧缓冲区的结束地址A[21:1]

         * 3. LCDSADDR3:

         *    OFFSIZE等于0,PAGEWIDTH等于(480*2/2)

         */

        LCDSADDR1 = ((LCDFRAMEBUFFER>>22)<<21) | LOWER21BITS(LCDFRAMEBUFFER>>1);

        LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER+ \

                    (LINEVAL_TFT_480272+1)*(HOZVAL_TFT_480272+1)*2)>>1);

        LCDSADDR3 = (0<<11) | (LCD_XSIZE_TFT_480272*2/2);

        /* 禁止临时调色板寄存器 */

        TPAL = 0;

        fb_base_addr = LCDFRAMEBUFFER;

        bpp = 16;

        xsize = 480;

        ysize = 272;

        break;

1>LCDCON1寄存器的配置

主要讲一下:CLKVAL_TFT_480272<<8这条语句。查看其宏可以知道:#define CLKVAL_TFT_480272 (4)  /* LCD手册表示Dclk=9MHz~15MHz, HCLK=100MHz, Dclk=VCLK=HCLK/[(CLKVAL+1)x2]=100/((4+1)*2)=10MHz */

在其注释部分可以很清楚地知道, Dclk是根绝LCD手册来的。HCLK=100MHz是根据你在程序中设置的系统时钟来的。

这样我们就可以确定CLKVAL的值了。

2>LCDCON2寄存器的配置

在代码中,我们可以看到这样一条语句: LCDCON2 = (VBPD_480272<<24) | (LINEVAL_TFT_480272<<14) | \
                  (VFPD_480272<<6) | (VSPW_480272);

然后查看这些相关的宏之后我们得知:

#define VBPD_480272 ((2-1)&0xff)     /* tvb=2 */

#define VFPD_480272 ((2-1)&0xff)     /* tvf=2 */

#define VSPW_480272 ((10-1) &0x3f)   /* tvp=10 */

#define LINEVAL_TFT_480272 (LCD_YSIZE_TFT_480272-1) ----> #define LCD_YSIZE_TFT_480272 (272)

这些参数的设置是根据什么来的呢?

查看s3c2440手册,我们知道:



查看LCD手册,我们知道:





对照着这三幅图中,我们可以知道:

VSPW+1 =tvp ;

VBPD+1 = tvb;

VFPD+1 = tvf;

HSPW+1 = thp;

HBPD+1 = thb;

HFPD+1 = thf;

而查看Typ及Min这两列,我们便可以得知:

tvp = 10;

tvb = 2;

tvf = 2;

thp = 41;

thb = 2;

thf = 2;

所以
VSPW = 9;
VBPD = 1;
VFPD = 1;
HSPW = 40;
HBPD  = 1;
HFPD = 1;

这也就是为什么下面这些宏如此设置的原因。
#define VBPD_480272 ((2-1)&0xff)     /* tvb=2 */
#define VFPD_480272 ((2-1)&0xff)     /* tvf=2 */
#define VSPW_480272 ((10-1) &0x3f)   /* tvp=10 */
LCD_YSIZE_TFT_480272 设置为272是根据LCD的分辨率来的 (480 X 272)

注:我们一般情况下选择其Typ列对应的值,若没有,再选择考虑其Min列的值。从Typ字面意思去理解的话,

Typ列的值为其比较常用且典型的值。

3>LCDCON3和LCDCON4寄存器的配置

由于我们在步骤2中已经知道这些参数的设置方法,所以对于LCDCON3和LCDCON4寄存器的配置就不赘述了。

4>LCDCON5寄存器的配置

在这里主要讲一下关于极性的配置,这个之后我才了解到,默认极性是根据s3c2440的时序图来的。需不需要反转,这还得参考
LCD的各信号在什么电平期间有效和3c2440的是否一致。若一致,则不需要反转,若不一致,则需要反转。

可参考博客:http://blog.chinaunix.net/uid-25871104-id-3462676.html中的”判断HSYNC,VSYNC,VCLK,VDEN信号是否需要反转“

II.接下来我们看一下如何操作LCD,就拿 " ClearScr(0x0);  // 清屏,黑色 " 这个来分析吧
代码如下:
/* 
 * 将屏幕清成单色
 * 输入参数:
 *     color: 颜色值
 *         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),
 *     需要转换为5:6:5格式
 *         对于8BPP: color为调色板中的索引值,
 *     其颜色取决于调色板中的数值
 */
void ClearScr(UINT32 color)
{   
    UINT32 x,y;
    
    for (y = 0; y < ysize; y++)
        for (x = 0; x < xsize; x++)
            PutPixel(x, y, color);
}

进入到PutPixel(x, y, color)函数看一下:

case 16:

        {

            UINT16 *addr = (UINT16 *)fb_base_addr + (y * xsize + x);   //X,Y是从0开始的。

            red   = (color >> 19) & 0x1f; // 5 BIT            //color是你传进来的时候对应的一个数值,代表某种颜色。

            green = (color >> 10) & 0x3f; // 6 bit

            blue  = (color >>  3) & 0x1f; // 5 bit

            color = (red << 11) | (green << 5) | blue; // 格式5:6:5

            *addr = (UINT16) color;  //往adddr这个地址上写值为color;

            break;

        }

我们可以很清晰地看到:

我们只需要往对应地址赋颜色对应的值即可。那么在显示屏上就可以看到我们在某个位置对应的颜色了,简单吧!上述这段代码没有用到

调色板。关于调色板的如何使用,可自行再去分析其中的代码,原理相似。

关注微信公众号获取更多资讯



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: