基于嵌入式Linux 系統(tǒng)的高速設(shè)備驅(qū)動程序?qū)崿F(xiàn)
圖2 改進(jìn)的設(shè)備驅(qū)動流程圖
2.2 驅(qū)動程序的進(jìn)一步改進(jìn)
基于以上幾點,為了能夠在Linux中實現(xiàn)高速設(shè)備的數(shù)據(jù)通信,對驅(qū)動程序結(jié)構(gòu)作出進(jìn)一步改進(jìn)的設(shè)計。
在設(shè)備驅(qū)動程序的實現(xiàn)上,采用生產(chǎn)者-消費者模型與循環(huán)緩存相結(jié)合的結(jié)構(gòu)。將從硬件設(shè)備到核心態(tài)內(nèi)存的DMA傳輸看作生產(chǎn)者,而從核心態(tài)內(nèi)存搬移到用戶態(tài)的數(shù)據(jù)傳輸過程看作消費者;同時為DMA傳輸分配的核心態(tài)內(nèi)存采用循環(huán)鏈的結(jié)構(gòu)。
在驅(qū)動程序中,將read()函數(shù)作為設(shè)備讀操作的主函數(shù),實現(xiàn)消費者的功能。當(dāng)read()每次被調(diào)用時,從DMA緩存鏈中讀取當(dāng)前指針?biāo)傅膬?nèi)存數(shù)據(jù),通過copy_to_user()函數(shù),將數(shù)據(jù)傳出核心態(tài),復(fù)制到用戶態(tài)內(nèi)存,以便后續(xù)的數(shù)據(jù)處理。
而在驅(qū)動程序中,Irq_service()函數(shù)實現(xiàn)生產(chǎn)者的功能,當(dāng)有中斷產(chǎn)生后,系統(tǒng)進(jìn)入Irq_service(),表明一次DMA的傳輸結(jié)束,并且在Irq_service()中,設(shè)置下一次DMA傳輸?shù)膮?shù),包括DMA傳輸?shù)臄?shù)據(jù)大小、DMA傳輸?shù)哪繕?biāo)內(nèi)存。之后,調(diào)用interrupt_sleep_on()函數(shù),使得系統(tǒng)進(jìn)入進(jìn)程調(diào)度,等待下一次DMA的操作完成。一旦完成,就會產(chǎn)生中斷并重復(fù)以上的過程。因此,作為生產(chǎn)者的Irq_service()函數(shù),只要初始化后,就會在中斷的觸發(fā)下不斷被調(diào)用。換句話說,只要有數(shù)據(jù)到達(dá)硬件設(shè)備,就會不斷將其通過DMA的方式讀入到核心態(tài)的循環(huán)緩存中。我們可以將DMA緩存在允許的情況下,開的大一些,因為當(dāng)接收的數(shù)據(jù)呈現(xiàn)一種突發(fā)的狀態(tài)時,較小的緩沖池可能由于不能及時地將數(shù)據(jù)取走而溢出,造成數(shù)據(jù)的丟失。
與此同時,還有個問題必須注意,即當(dāng)read()函數(shù)將緩存池中的數(shù)據(jù)都搬完之后,仍然沒有DMA的輸入。此時,read()繼續(xù)讀取的話,顯然會造成數(shù)據(jù)的錯誤,因此采用信號量是必須的。當(dāng)信號量表明,DMA的緩存已空時,若應(yīng)用程序調(diào)用read()進(jìn)行讀數(shù)據(jù)的話,將不做任何操作,并返回已讀數(shù)據(jù)量為0。當(dāng)信號量表明DMA的緩存為滿時,將DMA讀入的數(shù)據(jù)丟棄,并設(shè)置buff_full = 0。
除此以外,我們還必須對Linux驅(qū)動進(jìn)行以下步驟的操作:設(shè)備的注冊和注銷、設(shè)備的打開和釋放。通過register_chrdev()函數(shù)向系統(tǒng)注冊設(shè)備的設(shè)備號,在設(shè)備使用結(jié)束后,可以使用unregister_chrdev()從內(nèi)核注銷設(shè)備,釋放主設(shè)備號。在設(shè)備注冊之后,由open()函數(shù)打開設(shè)備,close()釋放設(shè)備。在驅(qū)動的初始化中,需要對DMA進(jìn)行首次設(shè)置,以及緩存的分配。我們可以調(diào)用 get_free_pages()函數(shù)進(jìn)行內(nèi)存頁面的分配,它會給DMA分配內(nèi)存中連續(xù)的頁面,這對于DMA是必須的,因為DMA操作的物理地址是連續(xù)的。在內(nèi)存分配之后,我們進(jìn)行中斷的配置,通過調(diào)用函數(shù)request_irq()。接著調(diào)用request_dma() 函數(shù)對DMA進(jìn)行申請注冊。
最后,有一點不得不引起我們的重視,即DMA一致性問題。DMA一致性的問題是指當(dāng)進(jìn)行數(shù)據(jù)DMA方式讀入時,由于沒有經(jīng)過CPU的處理,因此 CPU的CACHE會認(rèn)為該地址的內(nèi)存沒有被重寫過,而實際該內(nèi)存所存儲的數(shù)據(jù)已被改變;當(dāng)CPU需要處理該內(nèi)存的數(shù)據(jù)時,由于認(rèn)為數(shù)據(jù)沒有改變,會直接調(diào)用CACHE內(nèi)的數(shù)據(jù),造成數(shù)據(jù)錯誤,一般表現(xiàn)為數(shù)據(jù)的重復(fù)。在實際操作中,我們可以通過禁用該內(nèi)存的CACHE功能,來避免錯誤。在新版的Linux 內(nèi)核中提供dma_alloc_coherent()和dma_free_coherent()函數(shù)進(jìn)行DMA一致性內(nèi)存的分配。
以上就是我們針對高速設(shè)備驅(qū)動改進(jìn)的程序代碼結(jié)構(gòu)。該驅(qū)動程序結(jié)構(gòu)通過將核心態(tài)的DMA操作與數(shù)據(jù)到拷貝以及用戶態(tài)上數(shù)據(jù)的處理獨立開來,依靠信號量進(jìn)行相互的制約,可以有效的避免高速設(shè)備DMA操作的頻繁性和大數(shù)據(jù)量處理的較長時間之間的矛盾。驅(qū)動程序的流程如圖2所示。
3 應(yīng)用實例
下面我們以視頻會議系統(tǒng)為例,介紹基于以上結(jié)構(gòu)的高速設(shè)備驅(qū)動程序的實現(xiàn)。
在視頻會議系統(tǒng)中,AT91RM9200通過SPI接口與TI DM642 DSP芯片的McBSP接口相連進(jìn)行圖像數(shù)據(jù)的傳輸。由于數(shù)據(jù)吞吐量很大,采用一般結(jié)構(gòu)甚至是一般的DMA結(jié)構(gòu)的驅(qū)動程序都無法滿足數(shù)據(jù)的接收要求,造成數(shù)據(jù)無法實時的數(shù)據(jù)處理。我們針對該系統(tǒng)的特點,對驅(qū)動程序按照以上結(jié)構(gòu)作出改進(jìn),不但大大減輕了ARM處理器的負(fù)荷,同時能夠有效的進(jìn)行大數(shù)據(jù)量的傳輸和處理。
表1 驅(qū)動程序改進(jìn)前后對比表
測得碼率上限 | 性能測試描述 | |
改進(jìn)前 | 1Mbps | 當(dāng)碼率接近1Mbps時,出現(xiàn)數(shù)據(jù)丟失 |
改進(jìn)后 | 10Mbps | 當(dāng)碼率達(dá)到10Mbps時,驅(qū)動仍然能夠正常工作 |
在我們的系統(tǒng)中,由于SPI接口需要傳輸標(biāo)清的視頻壓縮圖像,碼率一般為2Mbps,原結(jié)構(gòu)的驅(qū)動程序在碼率較高的情況下,會出現(xiàn)數(shù)據(jù)的丟失,而數(shù)據(jù)的丟失不但影響了當(dāng)前幀的圖像的質(zhì)量,而且同時會造成后面多幀圖像的質(zhì)量嚴(yán)重下降,因而無法滿足這樣高數(shù)據(jù)率傳輸?shù)男枰?。而?jīng)過改進(jìn)的驅(qū)動程序經(jīng)過測試,至少可以承受10Mbps碼率的數(shù)據(jù)傳輸,驗證證明該結(jié)構(gòu)的驅(qū)動程序可以完全勝任高速設(shè)備的數(shù)據(jù)傳輸且經(jīng)過長時間測試,性能可靠。
4 結(jié)束語
本文的創(chuàng)新點是提出了一種基于ARM芯片的高速數(shù)據(jù)傳輸?shù)脑O(shè)備驅(qū)動實現(xiàn)方案。首先對嵌入式Linux驅(qū)動程序程序的傳統(tǒng)結(jié)構(gòu)框架進(jìn)行了介紹。而在實際的應(yīng)用中,為了能夠適應(yīng)高速率的數(shù)據(jù)傳輸,針對ARM芯片以及Linux操作系統(tǒng)的特點,對設(shè)備驅(qū)動程序進(jìn)行了改進(jìn)。最后,以視頻會議系統(tǒng)為例,對該結(jié)構(gòu)的驅(qū)動程序進(jìn)行實現(xiàn)、測試和驗證,可完全勝任高速設(shè)備的數(shù)據(jù)傳輸且性能可靠。不僅如此,該結(jié)構(gòu)的設(shè)備驅(qū)動程序同樣適合于嵌入式Linux系統(tǒng)的各種高速設(shè)備傳輸?shù)膽?yīng)用。
參考文獻(xiàn)
[1] Alessandro Rubini Linux Device Drivers 0'Reilly Assocoates,Inc. 1998.
[2] Karim Yagbmour Building Embedded Linux System 0'Reilly Media,Inc. 2004.
[3] Linux kernel, version 2.4.30
[4] 雷鋒成 方濱 李慧杰,嵌入式網(wǎng)絡(luò)數(shù)字圖像監(jiān)控系統(tǒng),微計算機信息.2006.9-2
評論