实验目的
①了解LCD控制器的基本原理
②了解LCD控制器的配置方法
③掌握字符和图像的显示方法和编程实现过程
实验内容
①根据参考代码,分析和完成LCD显示实验程序代码
②程序的编译
③通过AXD下载编译后的文件到实验板上
④调试程序,并观察程序运行情况
⑤引导程序将特定的汉字和符号显示在液晶显示屏上
⑥显示一个或多个图标、背景图像等
实验原理
①帧缓冲
显示屏的显示区域,在系统内有一段存储空间与之对应,通过改变存储空间的内容,便可改变显示的内容,该存储空间成为帧缓冲或显存。显示屏上得每一点都必然与帧缓冲里的莫一位置相对应,要解决显示屏的显示问题,首先需要解决帧缓冲的大小以及屏上得每一像素与帧缓冲的映射关系。
②LCD控制器
PXA270内部集成了LCD控制器LCDC,它提供了PXA270处理器与显示屏的接口。LCDC的作用是将帧缓冲中的数据传输到LCDC的内部,经过处理后输出到LCD的输入引脚上。
③DMA控制器
LCDC内部有七个完全独立的DMA通道,分别用于从内部或外部内存传输调色板数据、帧数据、光标数据、命令数据等到LCD控制器。在使用DMAC前,必须对其进行初始化,DMAC被初始化完成后,它就会自动从帧缓冲中提取数据。
④输入FIFO
LCD控制器有七个输入FIFO,一个16*64bit的显示基层FIFO,一个16*64bit的显示层FIFO,三个16*64bit显示叠加层2FIFOs,一个16*64bit光标FIFO,一个4*64bit命令解析FIFO。DMAC的每次操作都会从帧缓冲中数据传输到其中的一个FIFO。
⑤输出FIFO
像素数据被发送到输出引脚之前会被锁存到输出FIFO。
⑥各个寄存器配置
LCD控制寄存器包括16个控制寄存器,35个DMA寄存器,2个状态寄存器和256*3字节的内部调色板。部分寄存器的描述及物理地址如下表所示
地址
| 名称
| 描述
|
0x4400_0000
| LCCR0
| LCD控制寄存器0
|
0x4400_0004
| LCCR1
| LCD控制寄存器1
|
0x4400_0008
| LCCR2
| LCD控制寄存器2
|
0x4400_000C
| LCCR3
| LCD控制寄存器3
|
0x4400_0020
| FBR0
|
|
0x4400_0024
| FBR1
|
|
0x4400_0038
| LCSR
| LCD控制器状态寄存器
|
0x4400_003C
| LIIDR
| LCD控制器中断ID寄存器
|
0x4400_0040
| TRGBR
|
|
0x4400_0044
| TCR
|
|
0x4400_0200
| FDADR0
| DMA通道0帧描述符地址寄存器
|
0x4400_0204
| FSADR0
| DMA通道0帧源地址寄存器
|
0x4400_0208
| FIDR0
| DMA通道0帧ID寄存器
|
0x4400_020C
| LDCMD0
| DMA通道0命令寄存器
|
0x4400_0210
| FDADR1
| DMA通道1帧描述符地址寄存器
|
0x4400_0214
| FSADR1
| DMA通道1帧源地址寄存器
|
0x4400_0218
| FIDR1
| DMA通道1帧ID寄存器
|
0x4400_021C
| LDCMD1
| DMA通道1命令寄存器
|
LCDC内的DMAC需要初始化才可以工作,因为在DMAC工作之前需要提供DMAC一些相关信息:下一个帧描述符的位置、帧缓冲的位置、当前传送的是调色板数据还是图像数据、帧开始/结束时是否需要产生中断,以及所传送的数据的总大小。
LCDC有四个关于帧描述符的寄存器,分别是:FDADRx,FSADRx,FIDRx,LDCMDx(x取0-6,与DMAC的相应通道相对应),这四个寄存器的初始化方式并不是通过程序赋值,而是通过DMAC自动提取预先在内存里写好的数值,然后自动为这些寄存器赋值。为了让DMAC能够找到这些预先写好的数值,第一次使用DMAC或停用LCDC后又重新使用时,需要通过软件来初始化FDADRx(因为FDADRx的数值就是表示下一个帧描述符的位置)。当DMAC获得描述符的位置后,它便从该位置获取相应的数值,然后将另外三个寄存器初始化,再读取写在内存的为FDADRx预先准备好的数值,根据该数值跳转到指定的位置读取其他的帧描述符。
帧描述符需要在启动LCDC前定义,必须定义在内存空间,而且必须是连续的4*4字节的空间,这个空间划分为4个单元,每个单元都是32位,并且帧描述符的开始抵制能够被8整出,即二进制表示的开始地址的最低3位必须为0。
LCD控制寄存器的配置在启动代码中已经用汇编代码给出,在启动代码跳转到main函数之间已经初始化完成,所以实验重点在于字符的显示和图片的显示部分。其中图片显示可以直接使用Debug调试工具将二进制的图片文件下载到PXA270指定的显存中来显示。字符的显示需要写函数来实现。在裸机编程中,一般字符都以点阵的形式存储。在显示的时候通过读取点阵数组的每一位来决定是否显示从而完成对整个字符的显示。
实验步骤
第一步 分析代码
结合以上说明,对本实验提供的示例代码分析,深入理解针对具体的硬件实现,软件是如何配合工作的。
第二步 程序的编译和下载
利用ADS打开示例工程文件,执行Project→Make,编译、链接生成可执行映像文件
第三步 观察系统运行情况,对系统进行源码调试
通过调试工具的“从文件导入到内存”功能,将bmp文件导入到PXA270指定的显存中,先前需要将bmp文件的前70个字节的文件头去掉。在导入过程中就可以看到LCD上显示在一行一行地刷新。
程序说明
①LCD初始化
LCD初始化部分本次实验的示例程序使用的是汇编代码来写的,主要完成对帧描述符的初始化和对LCD控制器的第0、1、2、3号控制寄存器的初始化,包括外接LCD的分辨率、颜色、接口、时序等信息的初始化。
②LCD底层驱动
LCD底层驱动采用C语言来写,主要完成功能包括用制定颜色填充显示屏,在LCD指定位置显示字符,在LCD上显示指定大小的图片。
程序源代码、注释
①LCD初始化
ldr r11, =desc_word_0 ldr r1, =init_word_0 str r1, [r11] nop
nop ldr r11, =desc_word_1 ldr r1, =init_word_1 str r1, [r11] nop nop ldr r11, =desc_word_2 ldr r1, =init_word_2 str r1, [r11] nop nop ldr r11, =desc_word_3 ldr r1, =init_word_3 str r1, [r11]上面一段汇编代码在内存的指定地址(寄存器间接寻址)设定初始化帧描述符。
ldr r11, =LCCR1
ldr r1, =init_LCCR1 str r1, [r11] nop nop ldr r11, =LCCR2 ldr r1, =init_LCCR2 str r1, [r11] nop nop ldr r11, =LCCR3 ldr r1, =init_LCCR3 str r1, [r11]上面一段汇编代码设置LCD的控制寄存器1、2、3。
ldr r11,=FDADR0 ldr r1, =init_FDADR0 str r1, [r11] nop nop ldr r11, =LCCR0 ldr r1, =init_LCCR0 str r1, [r11]上面一段汇编代码将LCD的帧描述符地址寄存器中的值设定为已经定义好的帧描述符的地址,并且设定LCD的控制寄存器0
ldr r11,=LCCR0 ldr r1, [r11] orr r1,r1,#0x01 str r1,[r11] mov pc,r14上面一段汇编代码打开LCD控制器并且返回调用函数
②LCD底层驱动
1)LCD.h文件
#ifndef __LCD_H__
#define __LCD_H__
#define FB0_ADDR (0xA0500000) //基层FramBuffer地址
#define LCD_XSIZE (800u) //LCD尺寸定义
#define LCD_YSIZE (480u)
#define CHAR_XSIZE (16u) //显示字符大小定义
#define CHAR_YSIZE (16u)
//系统颜色宏定义
#define COLOR_RED (0xF800)
#define COLOR_GREEN (0x07E0)
#define COLOR_BLUE (0x001F)
#define COLOR_BLACK (0x0000)
#define COLOR_WHITE (0xFFFF)
//字符覆盖性显示宏定义开关
#define CHAR_COVER
//点阵字库数组申明
extern unsigned char charNum[32 * 32 * 10];
extern signed char LCD_FillColor(unsignedshort);extern signed char LCD_DrawChar(unsignedchar *, unsigned short, unsigned short, unsigned short);extern signed char LCD_DrawGraph(unsignedshort *, unsigned short, unsigned short);
#endif
2)LCD.c文件
#include "LCD.h"
/*
名 称:LCD_FillColor() 功 能:将整个LCD屏幕用制定的颜色填充 入口参数:color:指定的颜色,推荐使用宏定义中的颜色,当然使用R:G:B=5:6:5的半字填充也可以
出口参数:始终为0
说 明:无 使用范例:LCD_FillColor(COLOR_GREEN);将整个屏幕填充成绿色
*/
signed char LCD_FillColor(unsigned shortcolor){
inti;
for(i= 0; i < LCD_XSIZE * LCD_YSIZE; i++) (*(volatile unsigned short *)(FB0_ADDR +i)) = color;
return0;}
/*
名 称:LCD_DrawChar() 功 能:在LCD的指定位置上显示制定颜色的字符 入口参数:*pChar:字符点阵数据的数组,存储字符点阵信息,通过字符取模工具获得
color:指定的颜色,推荐使用宏定义中的颜色,当然使用R:G:B=5:6:5的半字填充也可以
x,y:指定的坐标,取值范围和字符的大小有关系,0 <= x + CHAR_XSIZE <= LCD_XSIZE,y同理
出口参数:正确返回0,否则返回-1
说 明:确保字符整个都在屏幕范围内,否则会返回错误信息 使用范例:LCD_DrawChar(ch0, COLOR_GREEN,10, 20);在LCD的(10,20)坐标处显示绿色的字符ch0 */
signed char LCD_DrawChar(unsigned char*pChar, unsigned short color, unsigned short x, unsigned short y){
unsignedshort i, j; unsignedchar k = 0;
//参数合理性检查,确保字符能够完整的在LCD上显示
if((x+ CHAR_XSIZE > LCD_XSIZE) || (y + CHAR_YSIZE > LCD_YSIZE)) return -1;
for(j= y; j < y + CHAR_YSIZE; j++) //列 for(i = x; i < x + CHAR_XSIZE <<1; i += 2) //行 {
if(*pChar& 0x80) //检查点阵数组中一个字节的每一位 (*(volatile unsigned short *)(FB0_ADDR +j * LCD_XSIZE << 1 + i)) = color;
#ifdefCHAR_COVER //如果定义了CHAR_COVER 将字符不显示的部分填充黑色 else
(*(volatileunsigned short *)(FB0_ADDR + j * LCD_XSIZE << 1+ i)) = COLOR_BLACK; #endif
*pChar= *pChar << 1; k++;
if(k>= 8) //点阵数组中一个字节的数据检查完成后指针指向下一个字节 {
k = 0;
pChar++;
}
}
return0;}
/*
名 称:LCD_DrawGraph() 功 能:在LCD的指定位置上显示一幅图片 入口参数:*pGraph:指向图片数组的指针
width:图片的宽度/pixel
height:图片的高度/pixel
出口参数:正确返回0,否则返回-1
说 明:图片分辨率必须比LCD分辨率低,否则返回-1 使用范例:LCD_DrawGraph(*pGraph, 60, 60);在LCD上显示一幅60x60的图片,图片源由pGraph指针指定
*/
signed char LCD_DrawGraph(unsigned short*pGraph, unsigned short width, unsigned short height){
unsignedshort i, j;
if((width> LCD_XSIZE) || (height > LCD_YSIZE)) return -1;
for(j= 0; j < height; j++) for(i = 0; i < width << 1; i +=2) {
(*(volatileunsigned short *)(FB0_ADDR + j * LCD_XSIZE << 1 + i)) = *pGraph; pGraph++;
}
return0;}
3)字库文件
由于全是点阵数组,此处略
总结
实验中要求在LCD上显示图片,就以为需要写函数来实现,就写了显示图片的函数,后来发现在显示中下半屏显示有问题,本身加了800x480的图片数组导致编译出的调试文件体积非常大,用并口的JTAG下载非常耗时,调了好长时间。而实际实验中要求只需要将LCD初始化好,图片的显示可以通过在Debug方式下直接向LCD的显示缓冲区中传送相应的图片文件,这样代码中不需要存储图片数组,编译生成的调试文件体积非常小,用并口JTAG下载速度非常快,需要显示图片时用调试软件的传送文件到内存即可。