文獻(xiàn)標(biāo)識碼: B
文章編號: 0258-7998(2011)10-0042-04
電子紙可以實現(xiàn)顯示內(nèi)容的重寫,具有對比度高、重量輕、可以適當(dāng)彎曲,且在斷電的情況下,能保持原有的顯示內(nèi)容等優(yōu)點。Linux是一種具有開放性、多用戶、多任務(wù)、設(shè)備獨立性、系統(tǒng)可靠安全、良好移植性等優(yōu)點的操作系統(tǒng)[1],其內(nèi)核可根據(jù)具體的運行平臺進(jìn)行適當(dāng)?shù)牟眉?,這對于資源有限的嵌入式系統(tǒng)至關(guān)重要。因此,如何將電子紙顯示屏移植應(yīng)用到Linux操作系統(tǒng)的嵌入式平臺下,引起了業(yè)界的廣泛關(guān)注。
本文采用GD6210E作為電子紙顯示屏的控制芯片,在S3C2440處理器上使用GPIO口對GD6210E進(jìn)行擴(kuò)展。編寫、編譯基于Linux中framebuffer的電子紙顯示屏驅(qū)動程序。
1 系統(tǒng)架構(gòu)與電子紙顯示屏驅(qū)動電路接口設(shè)計
1.1 系統(tǒng)架構(gòu)設(shè)計
本文搭建的嵌入式系統(tǒng)采用Samsung公司推出的S3C2440芯片為處理器。S3C2440采用ARM920T內(nèi)核,擁有豐富的GPIO口,能夠很好地對電子紙顯示屏控制芯片實現(xiàn)擴(kuò)展;外圍設(shè)備有容量為128 MB的NAND Flash、64 MB的SDRAM、以太網(wǎng)以及擴(kuò)展GD6210E電子紙顯示屏控制芯片[2-3]等。嵌入式系統(tǒng)架構(gòu)框圖如圖1所示。
1.2 電子紙顯示屏控制芯片接口設(shè)計
GD6210E芯片是Giga Device Semiconductor公司開發(fā)的電子紙控制芯片。該控制芯片提供多種顯示功能,如支持部分屏或整屏顯示、全局或局部刷新、支持圖像翻轉(zhuǎn)等,從而能夠減少CPU的運算時間,并支持CPU用命令訪問內(nèi)部寄存器和存儲介質(zhì)。
在接口設(shè)計上,本文使用S3C2440的GPD0~GPD15作為數(shù)據(jù)/命令的輸入/輸出口;GPC15作為探測GD6210E是否準(zhǔn)備好下一次操作的引腳,若為1,說明在GD6210E上已完成一個操作,進(jìn)入等待接收下一個操作命令狀態(tài);利用S3C2440的CLKOUT0引腳為GD6210E提供時鐘源/S3C2440對GD6210E擴(kuò)展接口如圖2所示。
2 Linux下電子紙驅(qū)動程序設(shè)計
2.1 Linux驅(qū)動程序的一般編寫方法
驅(qū)動程序是應(yīng)用程序與硬件之間的一個中間軟件層,沒有main()函數(shù),其工作過程是通過使用宏module_init(初始化函數(shù)名)將初始化函數(shù)加入內(nèi)核全局初始化函數(shù)列表中,在內(nèi)核初始化時執(zhí)行驅(qū)動的初始化函數(shù),從而完成驅(qū)動的初始化和注冊,之后驅(qū)動便停止,等待被應(yīng)用程序調(diào)用。應(yīng)用程序通過調(diào)用設(shè)備驅(qū)動程序中實現(xiàn)的接口函數(shù)(如read()、ioctl()等)實現(xiàn)對硬件的操作。
本文設(shè)計的電子紙驅(qū)動程序基于framebuffer,整體分為兩大部分:(1)GD6210E的驅(qū)動程序,其任務(wù)是完成S3C2440 GPIO口的設(shè)置、GD6210E初始化并使其處在運行狀態(tài);(2)完成framebuffer的填寫和內(nèi)核對顯示設(shè)備驅(qū)動的注冊。
2.2 Linux下GD6210E驅(qū)動程序
GD6210E是一個從設(shè)備,無法自主地工作,必須由外部的CPU對其發(fā)送命令,再把命令轉(zhuǎn)換成能使電子紙顯示屏做出相應(yīng)動作的電平時序。GD6210E驅(qū)動程序分為以下部分。
(1)初始化GD6210E。首先分別利用Linux中的s3c-2410_gpio_cfgpin()和s3c2410 _gpio_setpin()兩個函數(shù)設(shè)置復(fù)用GPIO口的引腳功能和引腳值。接口配置完后,再向GD6210E發(fā)出INIT_SYS_RUN命令,使芯片進(jìn)入等待初始化狀態(tài);然后初始化GD6210E中的display engine,填寫顯示時序寄存器,配置顯示時序。其中時序包括行數(shù)據(jù)輸出時間、行同步時間、幀數(shù)據(jù)輸出時間、幀同步時間;最后設(shè)置Image buffer和Updimage buffer在GD6210E中SDRAM的開始地址,至此初始化完成。GD6210E初始化流程如圖3所示。
(2)實現(xiàn)GD6210E對顯示數(shù)據(jù)的裝載和更新顯示屏。首先ARM9向GD6210E發(fā)送WAIT_DSPE_FREND命令,等待GD6210E當(dāng)前工作完成。若Ready引腳為1,ARM9發(fā)送LD_IMG命令,再判斷Ready是否為1,若是,則開始向GD6210E內(nèi)部的存儲器件發(fā)送圖像數(shù)據(jù)。數(shù)據(jù)發(fā)送完畢,ARM9發(fā)送LD_IMG_END命令,表示數(shù)據(jù)發(fā)送完成;最后發(fā)送UPD_FULL命令,開始電子紙更新。GD6210E更新電子紙顯示內(nèi)容過程如圖4所示。
2.3 Linux下幀緩沖設(shè)備接口設(shè)置
Linux操作系統(tǒng)為顯示設(shè)備提供專用接口即幀緩沖(framebuffer),它將顯示緩沖區(qū)進(jìn)行抽象,允許上層應(yīng)用程序在圖形模式下直接對顯示緩存區(qū)進(jìn)行讀寫操作[4]。在Linux系統(tǒng)中,每個顯示外設(shè)都與自己的一個fb_info結(jié)構(gòu)體相對應(yīng)。顯示驅(qū)動的實現(xiàn)很大部分是在初始化fb_info各項。fb_info包含fb_fix_screeninfo、fb_var_screeninfo、fb_cmap、fb_ops 4個結(jié)構(gòu)體[5]。
(1)fb_fix_screeninfo結(jié)構(gòu)體主要設(shè)置:①顯示設(shè)備的id、顯示緩沖區(qū)的大小、顯示屏每行在緩沖區(qū)字節(jié)數(shù)。②設(shè)置顯示屏的行像素數(shù)、列像素數(shù)、像素深度、色彩模式等。這兩個結(jié)構(gòu)體的設(shè)置較為簡單,根據(jù)實際情況對顯示屏進(jìn)行具體設(shè)置即可。
(2)fb_info最關(guān)鍵的是要填寫fb_ops。fb_ops要實現(xiàn)fb_mmap()和fb_ioctl()兩個關(guān)鍵的函數(shù)。
①fb_mmap():在Linux系統(tǒng)中,應(yīng)用程序不可能直接訪問設(shè)備驅(qū)動所在的內(nèi)核空間。但是,可通過調(diào)用mmap()函數(shù),使應(yīng)用程序能直接訪問設(shè)備所在的物理地址。mmap()將用戶空間的一段內(nèi)存與設(shè)備內(nèi)存進(jìn)行映射,當(dāng)用戶訪問用戶空間的這段地址范圍時,實際上會轉(zhuǎn)化為對設(shè)備的訪問,但mmap()必須以PAGE_SIZE為單位進(jìn)行映射。所以在fb_mmap()函數(shù)中,首先為應(yīng)用程序建立一個VMA(VMA描述的是一段連續(xù)的、具有相同訪問屬性的虛存空間)。建立VMA后只是說明進(jìn)程可以訪問這個虛存空間,但還沒有為其分配相應(yīng)的物理頁面,所以在訪問VMA時,就會產(chǎn)生一個缺頁異常,系統(tǒng)將自動調(diào)用VMA中的fault()函數(shù)。所以在填寫fault()函數(shù)時,首先調(diào)用vmalloc_to_page(*addr)找到電子紙顯示緩沖區(qū)所對應(yīng)的物理頁面;接著調(diào)用get_page(*struct page)函數(shù),獲得顯示緩沖區(qū)所在物理頁面的頁面描述符,再根據(jù)頁面描述符找到物理頁面地址,將物理頁面的地址填充到進(jìn)程的頁表中。這樣就能正常訪問VMA所描述的虛擬空間,從而完成電子紙的顯示緩沖區(qū)和用戶空間的映射。頁面映射的流程如圖5所示。
②fb_ioctl():fb_ioctl(fb_info *info、unsigned int cmd、unsigned long arg)函數(shù)最終實現(xiàn)用戶對I/O控制命令的執(zhí)行。其3個參數(shù)分別表示操作的fb_info對象、指令和指令所帶的參數(shù)。內(nèi)核中預(yù)定義了一些I/O控制命令,如framebuffer中的FBIOGET_VSCREENINFO、FBIOGET_FSCREENINFO分別為獲取可變的屏幕參數(shù)和固定屏幕參數(shù)。這些預(yù)定義的命令被內(nèi)核處理而不是被設(shè)備驅(qū)動處理。若命令為用戶自定義的,則調(diào)用設(shè)備驅(qū)動中的fb_ioctl()。本文自定義顯示更新命令為FBUPDATA,在fb_ioctl()中,若判斷出命令為FBUPDATA,則調(diào)用GD6210E驅(qū)動中的更新函數(shù)。Framebuffer中fb_ioctl()調(diào)用流程如圖6所示。
2.4 驅(qū)動程序整體架構(gòu)及工作過程
完整的電子紙驅(qū)動程序架構(gòu)如圖7所示。應(yīng)用程序首先打開顯示設(shè)備驅(qū)動,再調(diào)用framebuffer中fb_ops結(jié)構(gòu)體的fb_mmap()函數(shù),把驅(qū)動中的顯示緩存區(qū)映射到用戶空間,并填充顯示數(shù)據(jù)。再向顯示設(shè)備驅(qū)動發(fā)送cmd, fb_ioctl()接收cmd,再根據(jù)cmd調(diào)用GD6210E驅(qū)動程序中相對應(yīng)的操作函數(shù)。如刷新顯示屏,則調(diào)用GD6210E驅(qū)動程序中的刷新函數(shù)。
3 測試
3.1 測試環(huán)境
測試是在Fedroa 13 Linux操作系統(tǒng)下進(jìn)行,安裝arm-linux-gcc 4.4.3版本的交叉編譯工具。把電子紙驅(qū)動程序放在Linux 2.6.32.2內(nèi)核/drivers/vedio目錄下,并修改該目錄下Makefile和Kconfig這兩個文件,目的是為了在配置內(nèi)核時能添加電子紙驅(qū)動。運行make menuconfig指令重新配置內(nèi)核,把電子紙顯示屏驅(qū)動配置進(jìn)內(nèi)核。最后運行make zImage指令,用交叉編譯工具重新編譯內(nèi)核,完成Linux 內(nèi)核對電子紙驅(qū)動的添加。
3.2 驅(qū)動測試程序
驅(qū)動測試程序首先用open()打開電子紙驅(qū)動,再用fopen()打開一個8BBP的bmp圖片文件,跳過頭文件信息,提取每個像素點的灰階值。由于測試中采用的電子紙顯示屏是4BBP,所以要把8BBP的灰階值提取高4 bit轉(zhuǎn)成4BBP;接著調(diào)用mmap()把幀緩沖區(qū)間映射到用戶空間,對緩沖區(qū)填充每個像素點的灰階值;最后調(diào)用ioctl(),向顯示驅(qū)動發(fā)送更新命令,更新電子紙顯示屏。
目前,Linux圖形用戶界面程序編譯工具大部分是基于framebuffer(如Qt),而本文中的電子紙顯示屏驅(qū)動也是基于framebuffer,所以圖形用戶界面程序的開發(fā)人員利用本文的方法就可以完全不用理會電子紙與其他顯示屏在硬件上的差異問題。從而可以大大縮短采用電子紙為顯示屏的電子產(chǎn)品的開發(fā)時間,更利于電子紙顯示屏的普及應(yīng)用。
參考文獻(xiàn)
[1] 陳博,孫宏彬,於岳.Linux實用教程[M].北京:人民郵電出版社,2010.
[2] 孫天澤,袁文菊.嵌入式設(shè)計及Linux驅(qū)動開發(fā)指南—基于ARM9處理器[M].二版.北京:電子工業(yè)出版社,2007.
[3] Christopher Hallinan.嵌入式Linux基礎(chǔ)教程[M].北京:人民郵電出版社,2009.
[4] 宋寶華.Linux設(shè)備驅(qū)動開發(fā)詳解[M].北京:人民郵電出版社,2008.
[5] 商斌.Linux設(shè)備驅(qū)動開發(fā)入門與編程實踐[M].北京:電子工業(yè)出版社,2009.