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