結合三星公司arm9系列嵌入式處理器s3c2410,講解如何進行lcd驅動程式模組化程式設計及如何將驅動程式靜態載入進系統核心。
lcd(液晶顯示)模組滿足了嵌入式系統日益提高的要求,它可以顯示漢字、字元和圖形,同時還具有低壓、低功耗、體積小、重量輕和超薄等很多優點。隨著嵌入式系統的應用越來越廣泛,功能也越來越強大,對系統中的人機介面的要求也越來越高,在應用需求的驅使下,許多任務作在linux下的圖形介面軟體包的開發和移植工作中都涉及到底層lcd驅動的開發問題。因此在嵌入式系統中開發lcd驅動得以廣泛運用。
本文以三星公司arm9核心晶元s3c2410的lcd介面為基礎,介紹了在linux平台上開發嵌入式lcd驅動程式的一般方法。
本文硬體採用三星公司的s3c2410晶元的開發板,軟體採用linux 2.4.19平台,編譯器為arm-linux-gcc的交叉編譯器,使用640×480解析度的tft彩色lcd,通過對其linux驅動程式進行改寫和除錯,成功地實現了對該種屏的驅動和顯示。
嵌入式驅動的概念
裝置驅動程式是作業系統核心和機器硬體之間的介面,裝置驅動程式為應用程式遮蔽了硬體的細節,這樣在應用程式看來,硬體裝置只是乙個裝置檔案,應用程式可以像操作普通檔案一樣對硬體裝置進行操作。裝置驅動程式是核心的一部分,它主要完成的功能有:對裝置進行初始化和釋放;把資料從核心傳送到硬體和從硬體讀取資料;讀取應用程式傳送給裝置檔案的資料、回送應用程式請求的資料以及檢測和處理裝置出現的錯誤。
linux將裝置分為最基本的兩大類:一類是字元裝置,另一類是塊裝置。字元裝置和塊裝置的主要區別是:在對字元裝置發出讀/寫請求時,實際的硬體i/o一般就緊接著發生了。字元裝置以單個位元組為單位進行順序讀寫操作,通常不使用緩衝技術;塊裝置則是以固定大小的資料塊進行儲存和讀寫的,如硬碟、軟盤等,並利用一塊系統記憶體作為緩衝區。為提高效率,系統對於塊裝置的讀寫提供了快取機制,由於涉及緩衝區管理、排程和同步等問題,實現起來比字元裝置複雜得多。lcd是以字元裝置方式加以訪問和管理的,linux把顯示驅動看做字元裝置,把要顯示的資料一位元組一位元組地送往lcd驅動器。
linux的裝置管理是和檔案系統緊密結合的,各種裝置都以檔案的形式存放在/dev目錄下,稱為裝置檔案。應用程式可以開啟、關閉和讀寫這些裝置檔案,完成對裝置的操作,就像操作普通的資料檔案一樣。為了管理這些裝置,系統為裝置編了號,每個裝置號又分為主裝置號和次裝置號。主裝置號用來區分不同種類的裝置,而次裝置號用來區分同一型別的多個裝置。對於常用裝置,linux有約定俗成的編號,如硬碟的主裝置號是3。linux為所有的裝置檔案都提供了統一的操作函式介面,方法是使用資料結構struct file_operations。這個資料結構中包括許多操作函式的指標,如open()、close()、read()和write()等,但由於外設的種類較多,操作方式各不相同。struct file_operations結構體中的成員為一系列的介面函式,如用於讀/寫的read/write函式和用於控制的ioctl等。開啟乙個檔案就是呼叫這個檔案file_operations中的open操作。不同型別的檔案有不同的file_operations成員函式,如普通的磁碟資料檔案,介面函式完成磁碟資料塊讀寫操作;而對於各種裝置檔案,則最終呼叫各自驅動程式中的i/o函式進行具體裝置的操作。這樣,應用程式根本不必考慮操作的是裝置還是普通檔案,可一律當作檔案處理,具有非常清晰統一的i/o介面。所以file_operations是檔案層次的i/o介面。
lcd控制器
lcd控制器的功能是顯示驅動訊號,進而驅動lcd。使用者只需要通過讀寫一系列的暫存器,完成配置和顯示驅動。在驅動lcd設計的過程中首要的是配置lcd控制器,而在配置lcd控制器中最重要的一步則是幀緩衝區(framebuffer)的指定。使用者所要顯示的內容皆是從緩衝區中讀出,從而顯示到螢幕上的。幀緩衝區的大小由螢幕的解析度和顯示色彩數決定。驅動幀緩衝的實現是整個驅動開發過程的重點。s3c2410中的lcd控制器可支援stn和tft兩種液晶。對於stn 液晶平板,該lcd控制器可支援4位雙掃瞄、4位單掃瞄和8位單掃瞄三種顯示型別,支援4級和16級灰度級單色顯示模式,支援256色和4096色顯示,可接多種解析度的lcd,例如640×480、320×240和160×160等,在256色顯示模式時,最大可支援4096×1024、2048×2048和1024×4096顯示。tft液晶平板可支援1-2-4-8bpp(bits per pixel)調色盤顯示模式和16bpp非調色盤真彩顯示。
幀緩衝裝置對應的裝置檔案是/dev/fb*。如果系統有多個顯示卡,linux還支援多個幀緩衝裝置,最多可達32個,即/dev/fb0~/dev/fb31。而/dev/fb則指向當前的幀緩衝裝置,通常情況下,預設的幀緩衝裝置為/dev/fb0。
幀緩衝裝置也屬於字元裝置,採用「檔案層-驅動層」的介面方式。在檔案層為之定義了以下資料結構。
static struct file_operations fb_fops=
其成員函式都在linux/driver/video/fbmem.c中定義,其中的函式對具體的硬體進行操作,對暫存器進行設定,對顯示緩衝進行對映。主要結構體還有以下幾個。
●struct fb_fix_screeninfo:記錄了幀緩衝裝置和指定顯示模式的不可修改資訊。它包含了螢幕緩衝區的實體地址和長度。
●struct fb_var_screeninfo:記錄了幀緩衝裝置和指定顯示模式的可修改資訊。它包括顯示螢幕的解析度、每個畫素的位元數和一些時序變數。其中變數xres定義了螢幕一行所佔的畫素數,yres定義了螢幕一列所佔的畫素數,bits_per_pixel定義了每個畫素用多少個位來表示。
●struct fb_info:linux為幀緩衝裝置定義的驅動層介面。它不僅包含了底層函式,而且還有記錄裝置狀態的資料。每個幀緩衝裝置都與乙個fb_info結構相對應。其中成員變數modename為裝置名稱,fontname為顯示字型,fbops為指向底層操作的函式的指標。
lcd驅動開發的主要工作
1 編寫初始化函式
初始化函式首先初始化lcd控制器,通過寫暫存器設定顯示模式和顏色數,然後分配lcd顯示緩衝區。在linux中可以用kmalloc()函式分配一段連續的空間。緩衝區大小為:點陣行數×點陣列數×用於表示乙個畫素的位元數/8。緩衝區通常分配在大容量的片外sdram中,起始位址儲存在lcd控制暫存器中。本文採用的lcd顯示方式為640×480,16位彩色,則需要分配的顯示緩衝區為640×480×2=600kb。最後是初始化乙個fb_info結構,填充其中的成員變數,並呼叫register_framebuffer(&fb_info),將fb_info登記入核心。
2 編寫成員函式
編寫結構fb_info中函式指標fb_ops對應的成員函式,對於嵌入式系統的簡單實現,只需要下列三個函式就可以了。
struct fb_ops
struct fb_ops在include/linux/fb.h中定義。這些函式都是用來設定/獲取fb_info結構中的成員變數的。當應用程式對裝置檔案進行ioctl操作時候會呼叫它們。對於fb_get_fix(),應用程式傳入的是fb_fix_screeninfo結構,在函式中對其成員變數賦值,主要是**em_start(緩衝區起始位址)和**em_len(緩衝區長度),最終返回給應用程式。而fb_set_var()函式的傳入引數是fb_var_screeninfo,函式中需要對xres、yres和bits_per_pixel賦值。
對於/dev/fb,對顯示裝置的操作主要有以下幾種。
● 讀/寫(read/write)/dev/fb:相當於讀/寫螢幕緩衝區。
● 對映(map)操作:由於linux工作在保護模式,每個應用程式都有自己的虛擬位址空間,在應用程式中是不能直接訪問物理緩衝區位址的。為此,linux在檔案操作 file_operations結構中提供了mmap函式,可將檔案的內容對映到使用者空間。對於幀緩衝裝置,則可通過對映操作,可將螢幕緩衝區的物理位址對映到使用者空間的一段虛擬位址中,之後使用者就可以通過讀寫這段虛擬位址訪問螢幕緩衝區,在螢幕上繪圖了。
●i/o控制:對於幀緩衝裝置,對裝置檔案的ioctl操作可讀取/設定顯示裝置及螢幕的引數,如解析度、顯示顏色數和螢幕大小等。ioctl的操作是由底層的驅動程式來完成的。在應用程式中,操作/dev/fb的一般步驟如下:開啟/dev/fb裝置檔案;用ioctrl操作取得當前顯示螢幕的引數,如螢幕解析度和每個畫素的位元數,根據螢幕引數可計算螢幕緩衝區的大小;將螢幕緩衝區對映到使用者空間;對映後即可直接讀寫螢幕緩衝區,進行繪圖和顯示了。
lcd模組化驅動
在對s3c2410的lcd編寫模組化驅動程式時,首先要從核心中去除lcd驅動。這裡需要做一些改動,系統呼叫被加在以下檔案中,需去除:/root/usr/src/arm/linux/kernel/sys.c;/root/usr/src/arm/linux/include/arm-arm下的unistd.h和lcd.h;/root/usr/src/arm/linux/arch/arm/kernel下的calls.s。
編寫模組化驅動程式,有以下幾個關鍵的函式。
●lcd_kernel_init(void)//當模組被載入時執行
●lcd_kernel_exit(void)//當模組被移出核心空間時被執行
●lcd_kernel1_ioctl(struct*inode, struct*file, unsigned int cmd, unsigned longarg) //其他功能
每當裝配裝置驅動程式時,系統自動呼叫初始化模組lcd_kernel_init(void)。
另乙個必須提供的函式是lcd_kernel_exit(void),它在模組被解除安裝時呼叫,負責進行裝置驅動程式的工作。
執行in**od lcd.o命令即可將lcd驅動新增到核心中,執行rmmod lcd命令即可從核心中刪除lcd驅動。
靜態載入lcd驅動
將寫好的lcd驅動程式lcd.c放到arm/linux/drivers/char目錄下,修改arm/linux/drivers/char/config.in檔案,加上一行:bool'lcd driver support'config_lcd;修改arm/linux/drivers/char/makefile檔案,加上一行:obj-$(config_lcd)+=lcd.o。
這樣,當再進行make xconfig時,就會選擇是否將lcd驅動編譯進核心。同樣的辦法也可用在其他裝置上。
嵌入式系統中LCD驅動的實現原理
結合三星公司arm9系列嵌入式處理器s3c2410,講解如何進行lcd驅動程式模組化程式設計及如何將驅動程式靜態載入進系統核心。lcd 液晶顯示 模組滿足了嵌入式系統日益提高的要求,它可以顯示漢字 字元和圖形,同時還具有低壓 低功耗 體積小 重量輕和超薄等很多優點。隨著嵌入式系統的應用越來越廣泛,功...
嵌入式系統中LCD驅動的實現原理
結合三星公司arm9系列嵌入式處理器s3c2410,講解如何進行lcd驅動程式模組化程式設計及如何將驅動程式靜態載入進系統核心。lcd 液晶顯示 模組滿足了嵌入式系統日益提高的要求,它可以顯示漢字 字元和圖形,同時還具有低壓 低功耗 體積小 重量輕和超薄等很多優點。隨著嵌入式系統的應用越來越廣泛,功...
嵌入式系統中LCD驅動的實現原理
結合三星公司arm9系列嵌入式處理器s3c2410,講解如何進行lcd驅動程式模組化程式設計及如何將驅動程式靜態載入進系統核心。lcd 液晶顯示 模組滿足了嵌入式系統日益提高的要求,它可以顯示漢字 字元和圖形,同時還具有低壓 低功耗 體積小 重量輕和超薄等很多優點。隨著嵌入式系統的應用越來越廣泛,功...