張國華, 朱世偉, 高常波
在眾多的嵌入式系統中,尤其是一些人機交互較頻繁的嵌入式系統,顯示屏是一種應用較為廣泛的輸入輸出設備。由于嵌入式系統功能的不同,選擇的顯示屏的種類和特性不盡一致,需要根據嵌入式設備的實際功能和特殊需要來選擇相應特性的顯示屏并實現其驅動程序。
通過專用顯示芯片加外圍電路的方式實現嵌入式系統顯示硬件設計,但一般在系統設計時只考慮了操作系統內的顯示驅動,在 uboot的啟動和加載操作系統的過程[1]中沒有考慮開機圖片的顯示,在這段長時間的系統加載過程中能夠顯示開機圖片,為用戶顯示系統運行狀態顯的尤為重要。
文中以高溫寬的 EL屏 el320.240為例,講解uboot版本為1.1.2的linux驅動實現過程。
在linux下的顯示驅動由uboot配置直接管理和分層調用。程序開發者只需要開發硬件和硬件相關的顯示驅動就可以了。在linux uboot顯示設計開發中,整個設計架構如圖1所示[2]。
在以上框架中,內核配置與程序調用有關,首先要在內核配置的 config文件里定義 CONFIG_VIDEO_SED13806的宏;顯示驅動是和LCD 硬件密切相關的,驅動開發者必須根據LCD的硬件的特性來計算出驅動程序所需的幾個重要參數值。

圖1 顯示驅動框架
首先,要在include/configs/at91rm9200dk.h里面添加相應的宏。
#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等和硬件設計相關的空間配置。
#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
這段代碼定義了驅動320×240 分辨率LCD 屏所需的值,并根據顯示存儲器的片選管腳確定顯示驅動所需訪問的寄存器出示地址和偏移量等。
硬件主要有核心處理模塊、顯示控制模塊、電源轉換模塊、顯示屏等幾個部分組成,框圖如圖 2所示。

圖2 硬件設計框
核心處理模塊主要由核心處理芯片AT91RM9200及其外圍電路組成,主要完成bootloader和操作系統的運行及加載并完成顯示驅動和與顯示驅動模塊的交互,顯示驅動模塊完成顯示控制接口和顯示存儲等功能,通過顯示控制模塊接口實現與顯示屏的鏈接并將顯示內容顯示在顯示屏上,電源轉換模塊完成各功能模塊所需電源的轉換和供電。
第一步,在drivers/sed13806.c里面,添加對于s1d13506需要的操作函數。這里主要是對video_hw_init這個函數進行修改,這個函數就是將要在uboot初始化過程中被調用來初始化s1d13506的函數[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 (); /*設置s1d13506的寄存器*/
/*初始化顯示內存 */
i = s1d13806.memSize/4;
vm = (unsigned int *)s1d13806.frameAdrs;
printf("i is %d, vm is %x ", i, vm);
while(i--) *vm++ = 0xffffffff;
}
以上這個函數基本上就完成了對于驅動lcd所需要的硬件s1d13506的設置了并清除了現實內內存。
第二步,在board/at91rm9200dk/at91rm9200dk.c添加board_video_init()函數。
首先,拷貝static const S1D_REGS init_regs[ ]數組和頭文件,這個數組定義了s1d13506的寄存器配置,并用來初始化s1d13506的寄存器值。
然后,為board_video_init()函數賦值。
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()的工作就結束了,而對于EpsonSetRegs也通過對寄存器數組的修改完成。最后將這個函數包含到 uboot的初始化函數數組中進行調用。
第三步,打開文件 lib_arm/board.c,找到start_armboot(),這個函數就是板卡進行調用的初始函數,里面有一段代碼:
for (init_fnc_ptr = init_sequence; *init_fnc_ptr;++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
就是調用函數數組init_sequence來進行板卡初始化,找到該函數數組,將s1d13506的初始化函數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,
};
通過硬件設計和驅動代碼的編寫,完成了對uboot啟動后使能lcd驅動電路的工作,接下來就是在uboot中來使用這部分電路和驅動顯示圖形界面了。
為了能顯示開機 logo,可以使用 uboot的CONGIF_LOGO, CONFIG_SPALSH等機制來顯示相關像素陣列,也可通過tftp或者cp.b來將要顯示的數據拷貝到顯示存儲器相應位置進行顯示。
首先準備一張準備顯示的開機 logo,并通過圖像取模工具進行取模,然后將取模陣列燒到nor flash中,片選內存的地址為0x10300000開始,圖片的大小為 320x240=76800,為 0x12c00。使用命令 cp.b 10300000 30200000 12c00即可正確顯示圖片了。
通過上述計算結果不難看出,linux uboot下LCD 顯示驅動程序的架構相對固定。一般情況下,只需要根據 LCD 屏的電氣特性對其中某些參數進行調整。要完成對uboot的移植[4],關鍵是對linux代碼和 uboot代碼的熟悉,以及對芯片相關手冊的熟悉,若不能很好地理解 LCD 屏用戶手冊中的參數意義,就很難正確得到linux uboot所需的LCD 顯示參數,也就無法正確配置s1d13506寄存器,進而無法正確驅動LCD屏[5]。
[1] 霍東,張國華,亢碩.基于AT91RM9200系統的Boot loader設計[J].通信技術,2010,43(02):105-106,109.
[2] 馬忠梅.ARM&Linux嵌入式系統教程[M].北京:北京航空航天大學出版社,2004:102-103.
[3] CORBET J,RUBINI A,Kroah-Hartman G.Linux設備驅動程序[M].魏永明,駱剛,姜君,譯.出版地不詳:中國電力出版社,2002:8-15.
[4] 龍怡翔,李海濤,胡薇.戰術網絡中基于策略的網絡管理技術研究[J].信息安全與通信保密,2012(07):87-89.
[5] 陸平林.一種基于TMS320C6205 DSP的在線升級方法[J].通信技術,2012,45(02):132-134.