ARM9的LCD
2019-07-13 05:51发布
生成海报
实验前须知:关于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);
/* 禁止临时调 {MOD}板寄存器 */
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); // 清屏,黑 {MOD} " 这个来分析吧代码如下:/* * 将屏幕清成单 {MOD} * 输入参数: * color: 颜 {MOD}值 * 对于16BPP: color的格式为0xAARRGGBB (AA = 透明度), * 需要转换为5:6:5格式 * 对于8BPP: color为调 {MOD}板中的索引值, * 其颜 {MOD}取决于调 {MOD}板中的数值 */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是你传进来的时候对应的一个数值,代表某种颜 {MOD}。
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;
}
我们可以很清晰地看到:
我们只需要往对应地址赋颜 {MOD}对应的值即可。那么在显示屏上就可以看到我们在某个位置对应的颜 {MOD}了,简单吧!上述这段代码没有用到
调 {MOD}板。关于调 {MOD}板的如何使用,可自行再去分析其中的代码,原理相似。
关注微信公众号获取更多资讯
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮