張國華, 朱世偉, 高常波
在眾多的嵌入式系統(tǒng)中,尤其是一些人機交互較頻繁的嵌入式系統(tǒng),顯示屏是一種應(yīng)用較為廣泛的輸入輸出設(shè)備。由于嵌入式系統(tǒng)功能的不同,選擇的顯示屏的種類和特性不盡一致,需要根據(jù)嵌入式設(shè)備的實際功能和特殊需要來選擇相應(yīng)特性的顯示屏并實現(xiàn)其驅(qū)動程序。
通過專用顯示芯片加外圍電路的方式實現(xiàn)嵌入式系統(tǒng)顯示硬件設(shè)計,但一般在系統(tǒng)設(shè)計時只考慮了操作系統(tǒng)內(nèi)的顯示驅(qū)動,在 uboot的啟動和加載操作系統(tǒng)的過程[1]中沒有考慮開機圖片的顯示,在這段長時間的系統(tǒng)加載過程中能夠顯示開機圖片,為用戶顯示系統(tǒng)運行狀態(tài)顯的尤為重要。
文中以高溫寬的 EL屏 el320.240為例,講解uboot版本為1.1.2的linux驅(qū)動實現(xiàn)過程。
在linux下的顯示驅(qū)動由uboot配置直接管理和分層調(diào)用。程序開發(fā)者只需要開發(fā)硬件和硬件相關(guān)的顯示驅(qū)動就可以了。在linux uboot顯示設(shè)計開發(fā)中,整個設(shè)計架構(gòu)如圖1所示[2]。
在以上框架中,內(nèi)核配置與程序調(diào)用有關(guān),首先要在內(nèi)核配置的 config文件里定義 CONFIG_VIDEO_SED13806的宏;顯示驅(qū)動是和LCD 硬件密切相關(guān)的,驅(qū)動開發(fā)者必須根據(jù)LCD的硬件的特性來計算出驅(qū)動程序所需的幾個重要參數(shù)值。
圖1 顯示驅(qū)動框架
首先,要在include/configs/at91rm9200dk.h里面添加相應(yīng)的宏。
#define CONFIG_VIDEO_SED13806
#define CONFIG_VIDEO_SED13806_16BPP
#define CONFIG_NEC_NL644BC20
然后,在 include/sed13806.h中修改 FRAME_BUFFER_OFFSET、TOTAL_SPACE_SIZE 和DEFAULT_VIDEO_MEMORY_SIZE等和硬件設(shè)計相關(guān)的空間配置。
#define DISPLAY_WIDTH 320
#define DISPLAY_HEIGHT 240
#define SED13806_REG_ADDR 0x30000000
#define FRAME_BUFFER_OFFSET 0x200000
#define TOTAL_SPACE_SIZE 0x1400000
#define DEFAULT_VIDEO_MEMORY_SIZE 0x140000
這段代碼定義了驅(qū)動320×240 分辨率LCD 屏所需的值,并根據(jù)顯示存儲器的片選管腳確定顯示驅(qū)動所需訪問的寄存器出示地址和偏移量等。
硬件主要有核心處理模塊、顯示控制模塊、電源轉(zhuǎn)換模塊、顯示屏等幾個部分組成,框圖如圖 2所示。
圖2 硬件設(shè)計框
核心處理模塊主要由核心處理芯片AT91RM9200及其外圍電路組成,主要完成bootloader和操作系統(tǒng)的運行及加載并完成顯示驅(qū)動和與顯示驅(qū)動模塊的交互,顯示驅(qū)動模塊完成顯示控制接口和顯示存儲等功能,通過顯示控制模塊接口實現(xiàn)與顯示屏的鏈接并將顯示內(nèi)容顯示在顯示屏上,電源轉(zhuǎn)換模塊完成各功能模塊所需電源的轉(zhuǎn)換和供電。
第一步,在drivers/sed13806.c里面,添加對于s1d13506需要的操作函數(shù)。這里主要是對video_hw_init這個函數(shù)進行修改,這個函數(shù)就是將要在uboot初始化過程中被調(diào)用來初始化s1d13506的函數(shù)[3]。
void *video_hw_init (void)
{
unsigned int *vm, i;
memset (&s1d13806, 0, sizeof (Graphic Device));
s1d13806.frameAdrs=sed13806.isaBase+FAME_BUFFER_OFFSET;
s1d13806.winSizeX = board_get_width ();
s1d13806.winSizeY = board_get_height ();
s1d13806.gdfIndex=GDF_16BIT_565 RGB;
s1d13806.gdfBytesPP = 2;
s1d13806.memSize = s1d13806.winSizeX *s1d13806.winSizeY * s1d13806.gdfBytesPP;
EpsonSetRegs (); /*設(shè)置s1d13506的寄存器*/
/*初始化顯示內(nèi)存 */
i = s1d13806.memSize/4;
vm = (unsigned int *)s1d13806.frameAdrs;
printf("i is %d, vm is %x ", i, vm);
while(i--) *vm++ = 0xffffffff;
}
以上這個函數(shù)基本上就完成了對于驅(qū)動lcd所需要的硬件s1d13506的設(shè)置了并清除了現(xiàn)實內(nèi)內(nèi)存。
第二步,在board/at91rm9200dk/at91rm9200dk.c添加board_video_init()函數(shù)。
首先,拷貝static const S1D_REGS init_regs[ ]數(shù)組和頭文件,這個數(shù)組定義了s1d13506的寄存器配置,并用來初始化s1d13506的寄存器值。
然后,為board_video_init()函數(shù)賦值。
Unsigned int board_video_init (void)
{
(AT91PS_PIO)AT91C_BASE_PIOC->PIO_IDR = (unsigned int) (1 << 6);
(AT91PS_PIO)AT91C_BASE_PIOC->PIO_ASR = (unsigned int) (1 << 6);
(AT91PS_PIO)AT91C_BASE_PIOC->PIO_PDR = (unsigned int) (1 << 6);
AT91C_BASE_SMC2->SMC2_CSR[2] =(unsigned int)( (1 << 13) | (1 << 7) | (4 << 0) | (1 <<8) );
return (SED13806_REG_ADDR);
}
這樣,對于board_video_init()的工作就結(jié)束了,而對于EpsonSetRegs也通過對寄存器數(shù)組的修改完成。最后將這個函數(shù)包含到 uboot的初始化函數(shù)數(shù)組中進行調(diào)用。
第三步,打開文件 lib_arm/board.c,找到start_armboot(),這個函數(shù)就是板卡進行調(diào)用的初始函數(shù),里面有一段代碼:
for (init_fnc_ptr = init_sequence; *init_fnc_ptr;++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
就是調(diào)用函數(shù)數(shù)組init_sequence來進行板卡初始化,找到該函數(shù)數(shù)組,將s1d13506的初始化函數(shù)video_hw_init添加進去,如下:
init_fnc_t *init_sequence[ ] = {
cpu_init,/* basic cpu dependent setup */
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
dram_init, /* configure available RAM banks */
display_dram_config,
video_hw_init, /*zhs: init sed13506*/
#if defined(CONFIG_VCMA9)
checkboard,
#endif
NULL,
};
通過硬件設(shè)計和驅(qū)動代碼的編寫,完成了對uboot啟動后使能lcd驅(qū)動電路的工作,接下來就是在uboot中來使用這部分電路和驅(qū)動顯示圖形界面了。
為了能顯示開機 logo,可以使用 uboot的CONGIF_LOGO, CONFIG_SPALSH等機制來顯示相關(guān)像素陣列,也可通過tftp或者cp.b來將要顯示的數(shù)據(jù)拷貝到顯示存儲器相應(yīng)位置進行顯示。
首先準(zhǔn)備一張準(zhǔn)備顯示的開機 logo,并通過圖像取模工具進行取模,然后將取模陣列燒到nor flash中,片選內(nèi)存的地址為0x10300000開始,圖片的大小為 320x240=76800,為 0x12c00。使用命令 cp.b 10300000 30200000 12c00即可正確顯示圖片了。
通過上述計算結(jié)果不難看出,linux uboot下LCD 顯示驅(qū)動程序的架構(gòu)相對固定。一般情況下,只需要根據(jù) LCD 屏的電氣特性對其中某些參數(shù)進行調(diào)整。要完成對uboot的移植[4],關(guān)鍵是對linux代碼和 uboot代碼的熟悉,以及對芯片相關(guān)手冊的熟悉,若不能很好地理解 LCD 屏用戶手冊中的參數(shù)意義,就很難正確得到linux uboot所需的LCD 顯示參數(shù),也就無法正確配置s1d13506寄存器,進而無法正確驅(qū)動LCD屏[5]。
[1] 霍東,張國華,亢碩.基于AT91RM9200系統(tǒng)的Boot loader設(shè)計[J].通信技術(shù),2010,43(02):105-106,109.
[2] 馬忠梅.ARM&Linux嵌入式系統(tǒng)教程[M].北京:北京航空航天大學(xué)出版社,2004:102-103.
[3] CORBET J,RUBINI A,Kroah-Hartman G.Linux設(shè)備驅(qū)動程序[M].魏永明,駱剛,姜君,譯.出版地不詳:中國電力出版社,2002:8-15.
[4] 龍怡翔,李海濤,胡薇.戰(zhàn)術(shù)網(wǎng)絡(luò)中基于策略的網(wǎng)絡(luò)管理技術(shù)研究[J].信息安全與通信保密,2012(07):87-89.
[5] 陸平林.一種基于TMS320C6205 DSP的在線升級方法[J].通信技術(shù),2012,45(02):132-134.