文档章节

arm9 lcd controller

季风_落地窗
 季风_落地窗
发布于 2014/05/19 16:55
字数 2089
阅读 617
收藏 1

2440的lcd控制器可以驱动 STN LCD 和 TFT LCD 本文以较为常见的 TFT LCD 来讲解使用方法:

基础知识:

首先, 我们来看下2440的 lcd controller 组成框图:

REGBANK: LCD控制器的寄存器组, 含有17个寄存器及一块256x16的调色板

LCDCDMA: LCD控制器的专用DMA通道, 可以自动从系统总线上获取图像数据, 显示图像时不需要cpu core的参与

TIMEGEN / LPC3600: 产生控制时序, 如: VSYNC, HSYNC, VCLK, VDEN, 而这些信号又与REGBANK中的LCDCON1/2/3/4的配置密切相关, 通过不同的配置产生不同的控制信号. 然后从VIDEO MUX中传递给液晶屏(LPC3600为STN屏专用)

VIDPRCS:  接收LCDCDMA 的数据, 然后转换为合适的数据格式, 比如 4 bit单扫 / 8ibt单扫 /4bit双扫, 然后由 VD[23:0]来显示


其次, 我们来分析一下lcd controller的时序:

VSYNC/VFRAME/STV:垂直同步信号(TFT)/帧同步信号(STN)/SEC TFT信号

HSYNC/VLINE/CPV: 水平同步信号(TFT)/行同步脉冲信号(STN)/SEC TFT信号

VCLK/LCD_HCLK:   像素时钟信号(TFT/STN)/SEC TFT信号

VD[23:0]:        LCD像素数据输出端口(TFT/STN/SEC TFT)

VDEN/VM/TP:      数据使能信号(TFT)/LCD驱动交流偏置信号(STN)/SEC TFT 信号

LEND/STH:        行结束信号(TFT)/SEC TFT信号

LCD_LPCOE:       SEC TFT OE信号

LCD_LPCREV:      SEC TFT REV信号

LCD_LPCREVB:     SEC TFT REVB信号

所有显示器显示图像的原理都是从上到下,从左到右的。这是什么意思呢?这么说吧,一副图像可以看做是一个矩形,由很多排列整齐的点一行一行组成,这些点称之为像素。那么这幅图在LCD上的显示原理就是:

A:显示指针从矩形左上角的第一行第一个点开始,一个点一个点的在LCD上显示,在上面的时序图上表示为VCLK,我们称之为像素时钟信号

B:当显示指针一直显示到矩形的右边就结束这一行,那么这一行的动作在上面的时序图中就称之为1 Line

C:接下来显示指针又回到矩形的左边从第二行开始显示,注意,显示指针在从第一行的右边回到第二行的左边是需要一定的时间的,我们称之为行切换

D:如此类推,显示指针就这样一行一行的显示至矩形的右下角才把一副图显示完成。行的显示在时序图上看就是HSYNC

E:然而,LCD要显示多个图片就要一幅一幅的切换, 那么这每一幅图像就称之为帧,在时序图上就表示为1 Frame,因此从时序图上可以看出1 Line只是1 Frame中的一行

F:同样的,在帧与帧切换之间也是需要一定的时间的,我们称之为帧切换,那么LCD整个显示的过程在时间线上看,就可表示为时序图上的VSYNC

上面时序图上各时钟延时参数的含义如下:(这些参数的值,LCD产生厂商会提供相应的数据手册)

VBPD(vertical back porch):表示在一帧图像开始时,垂直同步信号以后的无效的行数,对应驱动中的upper_margin

VFBD(vertical front porch):表示在一帧图像结束后,垂直同步信号以前的无效的行数,对应驱动中的lower_margin

VSPW(vertical sync pulse width):表示垂直同步脉冲的宽度,用行数计算,对应驱动中的vsync_len

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

HFPD(horizontal front porth):表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK的个数,对应驱动中的right_margin

HSPW(horizontal sync pulse width):表示水平同步信号的宽度,用VCLK计算,对应驱动中的hsync_len

使用LCD的步骤:

    Lcd_Port_Init();                     // 设置LCD引脚
    Tft_Lcd_Init(MODE_TFT_16BIT_240320); // 初始化LCD控制器, 这里配置了液晶的显示模式, 如: 分辨率 240x320 颜色深度 16bit
    Lcd_PowerEnable(0, 1);               // 设置LCD_PWREN有效,它用于打开LCD的电源
    Lcd_EnvidOnOff(1);                   // 使能LCD控制器输出信号
    ClearScr(0x0);                       // 清屏,黑色

一 设置引脚

    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;    // GPB0控制液晶的背光ic输出使能
    GPBDAT  &= ~(1<<0);	    // Power off
    printf("Initializing GPIO ports..........\n");

二 设置LCD控制器  (以 分辨率: 640x480 颜色深度: 16bit 液晶类型: TFT-LCD 颜色格式: 565 等为例)

(1) LCD控制寄存器

LCDCON1:

    #define CLKVAL_TFT_640480 	(1)
    #define LCDTYPE_TFT         0x3
    #define BPPMODE_16BPP       0xC
    #define ENVID_DISABLE       0
    LCDCON1 = (CLKVAL_TFT_640480<<8) | (LCDTYPE_TFT<<5) | (BPPMODE_16BPP<<1) | (ENVID_DISABLE<<0);
/*  设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2]
    选择LCD类型: TFT LCD
    设置显示模式: 16BPP
    先禁止LCD信号输出            */

LCDCON2:

    #define VBPD_640480		((33-1)&0xff)
    #define LINEVAL_TFT_640480	(LCD_YSIZE_TFT_640480-1)
    #define VFPD_640480		((10-1)&0xff)
    #define VSPW_640480    	((2-1) &0x3f)
    LCDCON2 = (VBPD_640480<<24) | (LINEVAL_TFT_640480<<14) | (VFPD_640480<<6) | (VSPW_640480);

LCDCON3:

    #define HBPD_640480		((48-1)&0x7f)
    #define HOZVAL_TFT_640480	(LCD_XSIZE_TFT_640480-1)
    #define HFPD_640480		((16-1)&0xff)
    LCDCON3 = (HBPD_640480<<19) | (HOZVAL_TFT_640480<<8) | (HFPD_640480);

LCDCON4:

    #define HSPW_640480		((96-1)&0xff)
    LCDCON4 = HSPW_640480;

LCDCON5:

    #define FORMAT8BPP_565  1  
    #define HSYNC_INV       1
    #define VSYNC_INV       1
    #define HWSWP           1
    LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | (HWSWP<<1);
/*  16bpp 565
    设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转
    半字(2字节)交换使能      */

(2)帧内存寄存器

LCDSADDR1:

    #define LCDFRAMEBUFFER 0x30400000
    #define LOWER21BITS(n)  ((n) & 0x1fffff)
    LCDSADDR1 = ((LCDFRAMEBUFFER>>22)<<21) | LOWER21BITS(LCDFRAMEBUFFER>>1);
/*  0x30400000的[30:22]值为LCDSADDR1[29:21]的值, 所以0x30400000>>22之后再左移21位
    0x30400000的[21:1]值为LCDSADDR1[20:0]的值, 所以0x30400000>>1 为应该配置的值, 这个值只保留低21位, 所以 又与 0x1fffff相与    */

LCDSADDR2:

    #define HOZVAL_TFT_640480	(LCD_XSIZE_TFT_640480-1)
    #define LINEVAL_TFT_640480	(LCD_YSIZE_TFT_640480-1)
    LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER+(LINEVAL_TFT_640480+1)*(HOZVAL_TFT_640480+1)*2)>>1);
/*  这里是计算帧缓冲的结束地址, 本例中占用缓冲区大小为:  (LINEVAL_TFT_640480+1) * 640 * 480 * 2, 这里 *2 是因为16bpp, 如果是8bpp则应 *1. 这个大小再加上起始地址LCDFRAMEBUFFER就得到了结束地址 */

LCDSADDR3:

    #define LCD_XSIZE_TFT_640480 	(640)	
    #define LCD_YSIZE_TFT_640480 	(480)
    LCDSADDR3 = (0<<11) | (LCD_XSIZE_TFT_640480*2/2);

如果需要禁止调色板:

   /* 禁止临时调色板寄存器 */
   TPAL = 0;

帧地址:

    unsigned int fb_base_addr;
    unsigned int bpp;
    unsigned int xsize;
    unsigned int ysize;
    fb_base_addr = LCDFRAMEBUFFER;
    bpp = 16;
    xsize = 640;
    ysize = 480;

三 打开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
}

四 开启控制器输出

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

五 写点函数

屏幕上任何写操作都是由写一个个的点来组合完成的, 写点函数如下:

/* 
 * 画点
 * 输入参数:
 *     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);
            //这里fb_base_addr已经指向了帧内存首地址, 还有帧内存与视图虽然类比为窗口一样的形状, 但是在内存里只有线性结构, 就如同二维数组照样是线性存储的. 所以这里可以这样寻址每个点的内存中的位置
            red   = (color >> 19) & 0x1f;
            green = (color >> 10) & 0x3f;
            blue  = (color >>  3) & 0x1f;
            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;
    }
}

本文转载自:http://www.cnblogs.com/armlinux/archive/2011/01/14/2396864.html

上一篇: arm9 adc及触摸屏
下一篇: arm9 IIC
季风_落地窗
粉丝 4
博文 16
码字总数 16829
作品 0
杨浦
程序员
私信 提问
【.Net Micro Framework PortingKit – 13】LCD驱动开发

LCD驱动其实对TinyCLR并无必要,特别是在EM-STM3210E开发板上,因为该开发板上的内存太小了,片内64K,片外扩展了128K,加起来也不过172K,而我们知道针对320*240的显示大小,16bit的位图所占...

刘洪峰iot
2010/02/17
0
0
开源BOOT方案 - U-Boot

UBoot 是由开源项目PPCBoot发展起来的,ARMboot并入了PPCBoot,和其他一些arch的Loader合称U-Boot。2002年12月17日第一个版本U-Boot-0.2.0发布,同时PPCBoot和ARMboot停止维护。 U-Boot支持的...

匿名
2009/06/01
4.3K
0
怎样写Linux LCD 驱动程序

基本原理 通过 framebuffer ,应用程序用 mmap 把显存映射到应用程序虚拟地址空间,将要显示的数据写入这个内存空间就可以在屏幕上显示出来; 驱动程序分配系统内存作为显存;实现 fileoper...

慎思
2012/08/16
363
0
UCGUI移植初级解析

转自http://www.openedv.com/posts/list/20610.htm UCGUI移植初级解析 -----------------如何建立一个简单的UC/GUI工程 仅供像我这样的新手学习UCGUI使用 做UCGUI移植,首先要选择好自己硬件...

文剑Boy
2014/09/09
0
0
15.3. ipmitool - utility for controlling IPMI-enabled devices

确定硬件是否支持 IPMI neo@monitor:~$ sudo dmidecode |grep -C 5 IPMI[sudo] password for neo:Handle 0x2000, DMI type 32, 11 bytesSystem Boot Information Handle 0x2600, DMI type 38......

玄学酱
2018/01/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

代理模式之JDK动态代理 — “JDK Dynamic Proxy“

动态代理的原理是什么? 所谓的动态代理,他是一个代理机制,代理机制可以看作是对调用目标的一个包装,这样我们对目标代码的调用不是直接发生的,而是通过代理完成,通过代理可以有效的让调...

code-ortaerc
今天
5
0
学习记录(day05-标签操作、属性绑定、语句控制、数据绑定、事件绑定、案例用户登录)

[TOC] 1.1.1标签操作v-text&v-html v-text:会把data中绑定的数据值原样输出。 v-html:会把data中值输出,且会自动解析html代码 <!--可以将指定的内容显示到标签体中--><标签 v-text=""></......

庭前云落
今天
8
0
VMware vSphere的两种RDM磁盘

在VMware vSphere vCenter中创建虚拟机时,可以添加一种叫RDM的磁盘。 RDM - Raw Device Mapping,原始设备映射,那么,RDM磁盘是不是就可以称作为“原始设备映射磁盘”呢?这也是一种可以热...

大别阿郎
今天
12
0
【AngularJS学习笔记】02 小杂烩及学习总结

本文转载于:专业的前端网站☞【AngularJS学习笔记】02 小杂烩及学习总结 表格示例 <div ng-app="myApp" ng-controller="customersCtrl"> <table> <tr ng-repeat="x in names | orderBy ......

前端老手
昨天
16
0
Linux 内核的五大创新

在科技行业,创新这个词几乎和革命一样到处泛滥,所以很难将那些夸张的东西与真正令人振奋的东西区分开来。Linux内核被称为创新,但它又被称为现代计算中最大的奇迹,一个微观世界中的庞然大...

阮鹏
昨天
20
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部