s3c2440裸板驱动之LCD

来源:互联网 发布:mac os内存清理命令 编辑:程序博客网 时间:2024/06/13 13:28

        s3c2440片上集成了LCD控制器,用于驱动外接LCD屏,LCD屏的硬件特性是固定的,LCD裸板编程重

点是根据外接LCD的硬件特性和用户需求配置LCD控制器的寄存器组。而配置寄存器的重点又是理解LCD

工作时序,本文重点分析了LCD的工作时序和与时序相关的寄存器的配置,也结合代码简单介绍LCD使用

思路。

 

        LCD控制器提供了驱动外接LCD屏所需的所有控制信号,REGBANKLCD控制器的寄存器组,含17个寄

存器及一块256*16的调色板内存,用来设置各项参数,LCDCDMALCD控制器专用的DMA信道,可以自动的

从系统总线上取到图像数据。将相关寄存器设置好后,并将帧内存frame memory)的地址告诉LCD控制

器,它即可自动的发起DMA传输,从帧内存中得到图像数据,最终在上述信号的控制下出现在数据总线,

VD[23:0]上。用户只需要把要显示的图像数据写入帧内存中。

 

LCD相关名词解释:

        数据传输方式有4位单扫,4位双扫,8位单扫等

单扫:从上到下,从左到右,一个一个地发送数据。

双扫:整屏分上下两部分,每一部分单扫

4位、8位:多少位表示多少根数据线,4位双扫亦是8根数据线

BPPbit per piexl,表示每个像素使用多少位来表示其颜色。

    1BPP:单色(黑白)

    2BPP4级灰度(共四种颜色)

    4BPP16级灰度(共16种颜色)

    8BPP256

    2BPP4096

    16BPP64k

调色板:颜色库,一块存着RGB颜色值的内存。调色板颜色值一般为16BPP565格式或5551格式。

        一般8BPP的显示模式要用到调色板,此时帧缓冲区中的数据不是像素的颜色值,而是

色板中颜色值的索引值,真正的颜色值是调色板中的颜色值。这样8BPP显示模式的像素实际是

16BPP的。

 

 TFT LCD Timing Example

 

 名词解释:

 

VSYNC:垂直同步信号

VSYNC频率:帧/秒,垂直频率或场频率,相当于显示器的频率

VDEN:数据有效使能

HSYNC:水平同步信号

VCLK:像素时钟

VD:数据信号

LEND:行结束信号(行有效数据结束信号)(这不是必须的)

 

VSPW (vertical sync pulse width):表示VSYNC信号脉冲宽度值为(VSPW+1)个HSYNC信号周期。(

                                放在一周期最后,则可形象理解为电子枪回扫所需的时间),即

                                (VSPW+1)行,这(VSPW+1)行数据无效。

VBPD (vertical back porch):表示VSYNC脉冲信号结束以后还要经过(VBPD+1)个HSYNC信号周期,有

                          效的行数据才出现。所以,在VSYNC信号刚刚开始之后,总共要经过

                         (VSPW+1 +VBPD+1)个无效的行,第一个有效的行才出现。

LINEVAL:表示(LINEVAL+1)个有效行。

VFPD (vertical front porch):表示有效行结束后要经过(VFPD+1)个无效行。

 

HSPW (hertical sync pulse width):概念与VSPW相似,表示HSYNC信号脉冲宽度值为(HSPW+1)个

                                                                VCLKC信号周期。(若放在一HSYNC周期最后,则可形象理解为电

                                子枪行回扫所需的时间),即(HSPW+1)个像素,这(HSPW+1

                                个像素数据无效。

HBPD (hertical back porch):表示HSYNC脉冲信号结束以后还要经过(HBPD+1)个VCLK信号周期,有

                           效的像素数据才出现。所以,在HSYNC信号刚刚开始之后,总共要经过

                          (HSPW+1 +HBPD+1)个无效的像素,第一个有效的像素才出现。

HOZVAL:表示一行中的(HOZVAL+1)个有效像素。

HFPD (vertical front porch):表示有效像素结束后要经过(HFPD+1)个无效像素。

 

反映在屏幕上的关系示意图:


 

 具体结合2440开发板上日立液晶模组TX09D70VM1CBA的时序图分析:

 

 

         时序图原图中T5的相对长度与实际不符,我用红色部分把它投影到VSYNC周期里面,相对关系就非

常清晰明了了。

 

 

 

 

 

 

 

 

 

 

 解释其中四个单词:

Vertical Sync Start:有效行开始到下一个VSYNC开始的行数

Vertical Sync end:有效行开始到下一个VSYNC结束的行数

       则有 Vertical Sync end - Vertical Sync Start = 1VSYNC信号脉冲宽度(VSPW+1 行)

Vertical Blank Time:总黑框行数,值为(VSPW+1+VBPD+1+VFPD+1)

Vertical Display End:有效行。

       

         对于s3c2440控制器,与时序相关的要配置的项是VBPDLINEVALVFPDVSPWHBPDHOZVAL

HFPD

    结合8.2时序图和表8.1数据分析得:

VSPW +1= T1=1,  VSPW=0

VBPD+1 = T0-T2-T1=327 - 322 - 1 = 4,  VBPD =3

VFPD+1 = T2-T5= 322 -320 = 2,  VFPD = 1

LINEVAL +1=T5 =320,  LINEVAL = 319

同理:

HSPW +1= T7=5,  HSPW=4

HBPD+1 = T6-T7-T8=273 - 5 - 251 = 17,  HBPD =16

HFPD+1 = T8-T11= 251 -240 = 11,  HFPD = 10

HOZVAL +1=T5 =240,  HOZVAL = 239

        其他寄存器的配置及寄存器的位操作技巧,由于内容多繁杂,就不展开讨论了。也不难,只是需要大

家花时间细心去推敲。

 

 裸板LCD的使用步骤:

 1、配置引脚用于LCD,函数:Lcd_Port_Init()

2、根据显示模式,配置LCD控制寄存器组,函数:void Tft_Lcd_Init(int type)

3、打开LCD电源

4、使能LCD控制器输出信号

5、初始化调色板: 函数:Lcd_Palette8Bit_Init() 

6、清屏 ClearScr(0x0) 

7、向帧内存中写图像。


下面的代码参考了百问网韦东山老师提供的源码。

 

1、配置引脚用于LCD,函数:Lcd_Port_Init()

/* * 初始化用于LCD的引脚 */void Lcd_Port_Init(void){    GPCUP   = 0xffffffff;   // 禁止内部上拉    GPCCON  = 0xaaaaaaaa;   // GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND    GPDUP   = 0xffffffff;   // 禁止内部上拉    GPDCON  = 0xaaaaaaaa;   // GPIO管脚用于VD[23:8]  GPBCON &= ~(GPB0_MSK);  // Power enable pin    GPBCON |= GPB0_out;    GPBDAT &= ~(1<<0);// Power off    printf("Initializing GPIO ports..........\n");}

2、根据显示模式,配置LCD控制寄存器组,以MODE_TFT_8BIT_240320为例。

           函数:void Tft_Lcd_Init(int type):

 

/* * 初始化LCD控制器 * 输入参数: * type: 显示模式 *      MODE_TFT_8BIT_240320  : 240*320 8bpp的TFT LCD *      MODE_TFT_16BIT_240320 : 240*320 16bpp的TFT LCD *      MODE_TFT_8BIT_640480  : 640*480 8bpp的TFT LCD *      MODE_TFT_16BIT_640480 : 640*480 16bpp的TFT LCD */void Tft_Lcd_Init(int type){    switch(type)    {    case MODE_TFT_8BIT_240320:        /*         * 设置LCD控制器的控制寄存器LCDCON1~5         * 1. LCDCON1:         *    设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2]         *    选择LCD类型: TFT LCD            *    设置显示模式: 8BPP         *    先禁止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         * 3. LCDCON5:         *    设置显示模式为8BPP时,调色板中的数据格式: 5:6:5         *    设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转         *    字节交换使能         */        LCDCON1 = (CLKVAL_TFT_240320<<8) | (LCDTYPE_TFT<<5) | \                  (BPPMODE_8BPP<<1) | (ENVID_DISABLE<<0);        LCDCON2 = (VBPD_240320<<24) | (LINEVAL_TFT_240320<<14) | \                  (VFPD_240320<<6) | (VSPW_240320);        LCDCON3 = (HBPD_240320<<19) | (HOZVAL_TFT_240320<<8) | (HFPD_240320);        LCDCON4 = HSPW_240320;        LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | \                  (BSWP<<1);         /*         * 设置LCD控制器的地址寄存器LCDSADDR1~3         * 帧内存与视口(view point)完全吻合,         * 图像数据格式如下(8BPP时,帧缓冲区中的数据为调色板中的索引值):         *         |----PAGEWIDTH----|         *    y/x  0   1   2       239         *     0   idx idx idx ... idx         *     1   idx idx idx ... idx         * 1. LCDSADDR1:         *    设置LCDBANK、LCDBASEU         * 2. LCDSADDR2:         *    设置LCDBASEL: 帧缓冲区的结束地址A[21:1]         * 3. LCDSADDR3:         *    OFFSIZE等于0,PAGEWIDTH等于(240/2)         */        LCDSADDR1 = ((LCDFRAMEBUFFER>>22)<<21) | LOWER21BITS(LCDFRAMEBUFFER>>1);        LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER+ \                    (LINEVAL_TFT_240320+1)*(HOZVAL_TFT_240320+1)*1)>>1);        LCDSADDR3 = (0<<11) | (LCD_XSIZE_TFT_240320/2);         /* 禁止临时调色板寄存器 */        TPAL = 0;         fb_base_addr = LCDFRAMEBUFFER;        bpp = 8;        xsize = 240;        ysize = 320;                break;            ......}

3、打开LCD电源。

函数:Lcd_PowerEnable(0, 1);       // 设置LCD_PWREN有效,它用于打开LCD的电源

 

/* * 设置是否输出LCD电源开关信号LCD_PWREN * 输入参数: *     invpwren: 0 - LCD_PWREN有效时为正常极性 *               1 - LCD_PWREN有效时为反转极性 *     pwren:    0 - LCD_PWREN输出有效 *               1 - LCD_PWREN输出无效 */void Lcd_PowerEnable(int invpwren, int pwren){    GPGCON = (GPGCON & (~(3<<8))) | (3<<8);   // GPG4用作LCD_PWREN    GPGUP  = (GPGUP & (~(1<<4))) | (1<<4);    // 禁止内部上拉                LCDCON5 = (LCDCON5 & (~(1<<5))) | (invpwren<<5);  // 设置LCD_PWREN的极性: 正常/反转    LCDCON5 = (LCDCON5 & (~(1<<3))) | (pwren<<3);     // 设置是否输出LCD_PWREN}    

4、使能LCD控制器输出信号

函数:Lcd_EnvidOnOff(1);          // 使能LCD控制器输出信号

/* * 设置LCD控制器是否输出信号 * 输入参数: * onoff: *      0 : 关闭 *      1 : 打开 */void Lcd_EnvidOnOff(int onoff){    if (onoff == 1)    {        LCDCON1 |= 1;         // ENVID ONGPBDAT |= (1<<0);// Power on    }    else    {        LCDCON1 &= 0x3fffe;  // ENVID Off    GPBDAT &= ~(1<<0); // Power off    }}    


5、初始化调色板:

 函数:Lcd_Palette8Bit_Init();     // 初始化调色板

 

/* * 设置调色板 */void Lcd_Palette8Bit_Init(void){    int i;      volatile unsigned int *palette; LCDCON1 &= ~0x01;// stop lcd controller        LCDCON5 |= (FORMAT8BPP_565<<11); // 设置调色板中数据格式为5:6:5     palette = (volatile unsigned int *)PALETTE;    for (i = 0; i < 256; i++)        *palette++ = DEMO256pal[i]; LCDCON1 |= 0x01;// re-enable lcd controller}、

6、清屏

ClearScr(0x0){//往帧内存中写0,或者用临时调色板方法。}          

 7、向帧内存中写图像。先在屏幕指定位置画一个点,再画一条线。

        函数:void PutPixel(UINT32 x, UINT32 y, UINT32 color)

      void DrawLine(int x1,int y1,int x2,int y2,int color)

指定位置画一点:

 /* * 画点 * 输入参数: *     x、y : 象素坐标 *     color: 颜色值 *         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度), *     需要转换为5:6:5格式 *         对于8BPP: color为调色板中的索引值, *     其颜色取决于调色板中的数值 */void PutPixel(UINT32 x, UINT32 y, UINT32 color){    UINT8 red,green,blue;     switch (bpp){        case 16:        {            UINT16 *addr = (UINT16 *)fb_base_addr + (y * xsize + x);            red   = (color >> 19) & 0x1f; // 5 BIT            green = (color >> 10) & 0x3f; // 6 bit            blue  = (color >>  3) & 0x1f; // 5 bit            color = (red << 11) | (green << 5) | blue; // 格式5:6:5            *addr = (UINT16) color;            break;        }                case 8:        {            UINT8 *addr = (UINT8 *)fb_base_addr + (y * xsize + x);            *addr = (UINT8) color;            break;        }         default:            break;    }}
需要注意的是PutPixel()传入的颜色值是32位的,格式是AARRGGBB,这里转为565格式,要取出

R、G、B所在位的高5位,高6位,高5位,然后合并为565格式。


画任意一条线段: 

/* * 画线 * 输入参数: *     x1、y1 : 起点坐标 *     x2、y2 : 终点坐标 *     color  : 颜色值 *         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度), *     需要转换为5:6:5格式 *         对于8BPP: color为调色板中的索引值, *     其颜色取决于调色板中的数值 */void DrawLine(int x1,int y1,int x2,int y2,int color){} 

        实现方法大家可以参考东山老师源码,也可以参考bresenham算法无非就是一条线段,取距离这

条线段最近的离散的整数点,每取一个整数点PutPixel.


 

 



 

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 吃了有蟑螂的汤怎么办 调节天平时指针向右怎么办 香薰蜡烛融化了怎么办 香薰蜡烛挂壁怎么办y 粗蜡烛只烧中间怎么办 紫薯馒头变绿怎么办 小孩手开水烫了怎么办 被油烫伤了怎么办才不留疤 烫伤水泡蹭破了怎么办 烧伤的水泡破了怎么办 烧伤后水泡破了怎么办 烫伤泡破了红肿怎么办 烧伤第二天水泡破了怎么办? 烧伤后换药特别疼怎么办 盐酸溅到皮肤上怎么办 磷性磷酸酶高440怎么办 浓硫酸沾到皮肤上怎么办 浓硫酸溅到皮肤上怎么办 浓硫酸滴到皮肤上怎么办 浓硫酸洒在皮肤上怎么办 浓硫酸溅到眼睛里怎么办 盐酸弄到眼睛了怎么办 稀硫酸进眼睛里怎么办 草酸弄到皮肤上怎么办 大理石被盐酸烧发白怎么办 香薰蜡烛化了怎么办 吸入了大量燃烧纸气体怎么办 狗链条上锈了怎么办 思维迟钝反应慢嘴笨怎么办 小孩思维慢反应迟钝怎么办 苹果4g网络慢怎么办 医院没有号了怎么办啊 fgo宝具动画卡顿怎么办 死刑犯在执行前死亡怎么办 汕头交警 违章扣分怎么办办理 幼儿园家长不保险应该怎么办 csgo掉白银坑了怎么办 错过教资认定现场确认怎么办 乡村建设导致民房开裂怎么办 项目部公章丢了怎么办 手机掉了没有卡怎么办