實(shí)驗(yàn)?zāi)康?/font>
①了解LCD控制器的基本原理
②了解LCD控制器的配置方法
③掌握字符和圖像的顯示方法和編程實(shí)現(xiàn)過程
實(shí)驗(yàn)內(nèi)容
①根據(jù)參考代碼,分析和完成LCD顯示實(shí)驗(yàn)程序代碼
②程序的編譯
③通過AXD下載編譯后的文件到實(shí)驗(yàn)板上
④調(diào)試程序,并觀察程序運(yùn)行情況
⑤引導(dǎo)程序?qū)⑻囟ǖ臐h字和符號顯示在液晶顯示屏上
⑥顯示一個或多個圖標(biāo)、背景圖像等
實(shí)驗(yàn)原理
①幀緩沖
顯示屏的顯示區(qū)域,在系統(tǒng)內(nèi)有一段存儲空間與之對應(yīng),通過改變存儲空間的內(nèi)容,便可改變顯示的內(nèi)容,該存儲空間成為幀緩沖或顯存。顯示屏上得每一點(diǎn)都必然與幀緩沖里的莫一位置相對應(yīng),要解決顯示屏的顯示問題,首先需要解決幀緩沖的大小以及屏上得每一像素與幀緩沖的映射關(guān)系。
②LCD控制器
PXA270內(nèi)部集成了LCD控制器LCDC,它提供了PXA270處理器與顯示屏的接口。LCDC的作用是將幀緩沖中的數(shù)據(jù)傳輸?shù)絃CDC的內(nèi)部,經(jīng)過處理后輸出到LCD的輸入引腳上。
③DMA控制器
LCDC內(nèi)部有七個完全獨(dú)立的DMA通道,分別用于從內(nèi)部或外部內(nèi)存?zhèn)鬏斦{(diào)色板數(shù)據(jù)、幀數(shù)據(jù)、光標(biāo)數(shù)據(jù)、命令數(shù)據(jù)等到LCD控制器。在使用DMAC前,必須對其進(jìn)行初始化,DMAC被初始化完成后,它就會自動從幀緩沖中提取數(shù)據(jù)。
④輸入FIFO
LCD控制器有七個輸入FIFO,一個16*64bit的顯示基層FIFO,一個16*64bit的顯示層FIFO,三個16*64bit顯示疊加層2FIFOs,一個16*64bit光標(biāo)FIFO,一個4*64bit命令解析FIFO。DMAC的每次操作都會從幀緩沖中數(shù)據(jù)傳輸?shù)狡渲械囊粋FIFO。
⑤輸出FIFO
像素?cái)?shù)據(jù)被發(fā)送到輸出引腳之前會被鎖存到輸出FIFO。
⑥各個寄存器配置
LCD控制寄存器包括16個控制寄存器,35個DMA寄存器,2個狀態(tài)寄存器和256*3字節(jié)的內(nèi)部調(diào)色板。部分寄存器的描述及物理地址如下表所示
地址
| 名稱
| 描述
|
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控制器狀態(tài)寄存器
|
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內(nèi)的DMAC需要初始化才可以工作,因?yàn)樵贒MAC工作之前需要提供DMAC一些相關(guān)信息:下一個幀描述符的位置、幀緩沖的位置、當(dāng)前傳送的是調(diào)色板數(shù)據(jù)還是圖像數(shù)據(jù)、幀開始/結(jié)束時是否需要產(chǎn)生中斷,以及所傳送的數(shù)據(jù)的總大小。
LCDC有四個關(guān)于幀描述符的寄存器,分別是:FDADRx,F(xiàn)SADRx,F(xiàn)IDRx,LDCMDx(x取0-6,與DMAC的相應(yīng)通道相對應(yīng)),這四個寄存器的初始化方式并不是通過程序賦值,而是通過DMAC自動提取預(yù)先在內(nèi)存里寫好的數(shù)值,然后自動為這些寄存器賦值。為了讓DMAC能夠找到這些預(yù)先寫好的數(shù)值,第一次使用DMAC或停用LCDC后又重新使用時,需要通過軟件來初始化FDADRx(因?yàn)镕DADRx的數(shù)值就是表示下一個幀描述符的位置)。當(dāng)DMAC獲得描述符的位置后,它便從該位置獲取相應(yīng)的數(shù)值,然后將另外三個寄存器初始化,再讀取寫在內(nèi)存的為FDADRx預(yù)先準(zhǔn)備好的數(shù)值,根據(jù)該數(shù)值跳轉(zhuǎn)到指定的位置讀取其他的幀描述符。
幀描述符需要在啟動LCDC前定義,必須定義在內(nèi)存空間,而且必須是連續(xù)的4*4字節(jié)的空間,這個空間劃分為4個單元,每個單元都是32位,并且?guī)枋龇拈_始抵制能夠被8整出,即二進(jìn)制表示的開始地址的最低3位必須為0。
LCD控制寄存器的配置在啟動代碼中已經(jīng)用匯編代碼給出,在啟動代碼跳轉(zhuǎn)到main函數(shù)之間已經(jīng)初始化完成,所以實(shí)驗(yàn)重點(diǎn)在于字符的顯示和圖片的顯示部分。其中圖片顯示可以直接使用Debug調(diào)試工具將二進(jìn)制的圖片文件下載到PXA270指定的顯存中來顯示。字符的顯示需要寫函數(shù)來實(shí)現(xiàn)。在裸機(jī)編程中,一般字符都以點(diǎn)陣的形式存儲。在顯示的時候通過讀取點(diǎn)陣數(shù)組的每一位來決定是否顯示從而完成對整個字符的顯示。
實(shí)驗(yàn)步驟
第一步 分析代碼
結(jié)合以上說明,對本實(shí)驗(yàn)提供的示例代碼分析,深入理解針對具體的硬件實(shí)現(xiàn),軟件是如何配合工作的。
第二步 程序的編譯和下載
利用ADS打開示例工程文件,執(zhí)行Project→Make,編譯、鏈接生成可執(zhí)行映像文件
第三步 觀察系統(tǒng)運(yùn)行情況,對系統(tǒng)進(jìn)行源碼調(diào)試
通過調(diào)試工具的“從文件導(dǎo)入到內(nèi)存”功能,將bmp文件導(dǎo)入到PXA270指定的顯存中,先前需要將bmp文件的前70個字節(jié)的文件頭去掉。在導(dǎo)入過程中就可以看到LCD上顯示在一行一行地刷新。
程序說明
①LCD初始化
LCD初始化部分本次實(shí)驗(yàn)的示例程序使用的是匯編代碼來寫的,主要完成對幀描述符的初始化和對LCD控制器的第0、1、2、3號控制寄存器的初始化,包括外接LCD的分辨率、顏色、接口、時序等信息的初始化。
②LCD底層驅(qū)動
LCD底層驅(qū)動采用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]上面一段匯編代碼在內(nèi)存的指定地址(寄存器間接尋址)設(shè)定初始化幀描述符。
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]上面一段匯編代碼設(shè)置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的幀描述符地址寄存器中的值設(shè)定為已經(jīng)定義好的幀描述符的地址,并且設(shè)定LCD的控制寄存器0
ldr r11,=LCCR0 ldr r1, [r11] orr r1,r1,#0x01 str r1,[r11] mov pc,r14上面一段匯編代碼打開LCD控制器并且返回調(diào)用函數(shù)
②LCD底層驅(qū)動
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)
//系統(tǒng)顏色宏定義
#define COLOR_RED (0xF800)
#define COLOR_GREEN (0x07E0)
#define COLOR_BLUE (0x001F)
#define COLOR_BLACK (0x0000)
#define COLOR_WHITE (0xFFFF)
//字符覆蓋性顯示宏定義開關(guān)
#define CHAR_COVER
//點(diǎn)陣字庫數(shù)組申明
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屏幕用制定的顏色填充 入口參數(shù):color:指定的顏色,推薦使用宏定義中的顏色,當(dāng)然使用R:G:B=5:6:5的半字填充也可以
出口參數(shù):始終為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的指定位置上顯示制定顏色的字符 入口參數(shù):*pChar:字符點(diǎn)陣數(shù)據(jù)的數(shù)組,存儲字符點(diǎn)陣信息,通過字符取模工具獲得
color:指定的顏色,推薦使用宏定義中的顏色,當(dāng)然使用R:G:B=5:6:5的半字填充也可以
x,y:指定的坐標(biāo),取值范圍和字符的大小有關(guān)系,0 <= x + CHAR_XSIZE <= LCD_XSIZE,y同理
出口參數(shù):正確返回0,否則返回-1
說 明:確保字符整個都在屏幕范圍內(nèi),否則會返回錯誤信息 使用范例:LCD_DrawChar(ch0, COLOR_GREEN,10, 20);在LCD的(10,20)坐標(biāo)處顯示綠色的字符ch0 */
signed char LCD_DrawChar(unsigned char*pChar, unsigned short color, unsigned short x, unsigned short y){
unsignedshort i, j; unsignedchar k = 0;
//參數(shù)合理性檢查,確保字符能夠完整的在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) //檢查點(diǎn)陣數(shù)組中一個字節(jié)的每一位 (*(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) //點(diǎn)陣數(shù)組中一個字節(jié)的數(shù)據(jù)檢查完成后指針指向下一個字節(jié) {
k = 0;
pChar++;
}
}
return0;}
/*
名 稱:LCD_DrawGraph() 功 能:在LCD的指定位置上顯示一幅圖片 入口參數(shù):*pGraph:指向圖片數(shù)組的指針
width:圖片的寬度/pixel
height:圖片的高度/pixel
出口參數(shù):正確返回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)字庫文件
由于全是點(diǎn)陣數(shù)組,此處略
總結(jié)
實(shí)驗(yàn)中要求在LCD上顯示圖片,就以為需要寫函數(shù)來實(shí)現(xiàn),就寫了顯示圖片的函數(shù),后來發(fā)現(xiàn)在顯示中下半屏顯示有問題,本身加了800x480的圖片數(shù)組導(dǎo)致編譯出的調(diào)試文件體積非常大,用并口的JTAG下載非常耗時,調(diào)了好長時間。而實(shí)際實(shí)驗(yàn)中要求只需要將LCD初始化好,圖片的顯示可以通過在Debug方式下直接向LCD的顯示緩沖區(qū)中傳送相應(yīng)的圖片文件,這樣代碼中不需要存儲圖片數(shù)組,編譯生成的調(diào)試文件體積非常小,用并口JTAG下載速度非?欤枰@示圖片時用調(diào)試軟件的傳送文件到內(nèi)存即可。