嵌入式Linux中I2C設備驅動(dòng)程序的研究與實(shí)現
摘要: I2C 作為一種目前通用的總線(xiàn)技術(shù),已廣泛應用于EEPROM、實(shí)時(shí)鐘、小型LCD 等設備與CPU 的接口中。分析了嵌入式Linux 中I2C 驅動(dòng)程序的體系結構,I2C 驅動(dòng)程序中一些重要數據結構之間的關(guān)系以及I2C 驅動(dòng)程序的運行機制。最后,結合具體的EEPROM 芯片AT24C08 說(shuō)明了在嵌入式Linux 下開(kāi)發(fā)I2C設備驅動(dòng)程序的一般流程。另外還創(chuàng )新了一般的驅動(dòng)方法,實(shí)現了單設備多驅動(dòng)的驅動(dòng)模式。
本文引用地址:http://dyxdggzs.com/article/149709.htm引言
I2C是“Inter Integrated Circuit Bus”的縮寫(xiě),中文譯成“內部集成電路總線(xiàn)”, 它是Philips 公司于20 世紀80 年代研發(fā)成功的一種具有多端控制功能的雙線(xiàn)雙向串行數據總線(xiàn)標準, 其具有模塊化、電路結構簡(jiǎn)單等優(yōu)點(diǎn)。在嵌入式系統中,I2C總線(xiàn)已經(jīng)成為器件接口的標準之一, 常用于連接RAM、EEPROM 以及LCD 控制器等設備。另外,總線(xiàn)的數據傳輸是以字節為單位的。
目前,標準的I2C的傳輸速率可以達到100kbit/s,能支持128 個(gè)設備,增強型I2C傳輸速率可達400kbit/s,能支持多達1024 個(gè)設備,高速模式下的I2C 傳輸速率更高達3.4Mbit/s。
1 Linux 驅動(dòng)程序
驅動(dòng)程序是指系統內核與系統硬件之間的接口。Linux 中的每一個(gè)外圍物理設備等都有一個(gè)專(zhuān)門(mén)用于控制該設備的設備驅動(dòng)程序。設備驅動(dòng)可以完成初始化、釋放以及檢測硬件設備;差錯和故障處理;負責內核與硬件、應用程序與硬件之間的數據傳輸與通信的一些重要工作。在嵌入式系統中,設備驅動(dòng)為嵌入式操作系統和應用程序訪(fǎng)問(wèn)硬件設備提供統一的接口。通過(guò)它, 操作系統和應用程序就可以輕松地操作和驅動(dòng)硬件架構的分層。
2 Linux 的I2C 體系結構
2.1 Linux 下I2C 體系結構分析
Linux 的I2C 體系結構由3 大部分組成:
(1)I2C框架:I2C.h 和I2C-core.c 為I2C框架的主體,提供了核心數據結構的定義、I2C 適配器驅動(dòng)和設備驅動(dòng)的注冊、注銷(xiāo)方法,I2C 通信方法(algorithm)上層的、與具體適配器無(wú)關(guān)的代碼、以及檢測設備地址的上層代碼等。作為核心的I2C-core.c 還為總線(xiàn)驅動(dòng)設備提供了一些統一的調用接口進(jìn)行讀寫(xiě)和設置操作, 另外它還提供了將各種支持的總線(xiàn)設備驅動(dòng)添加到這個(gè)體系中的方法, 以及當不再使用這些總線(xiàn)驅動(dòng)時(shí)從體系中刪除的方法。
(2)I2C 總線(xiàn)驅動(dòng)I2C總線(xiàn)驅動(dòng)是對I2C 硬件體系結構中適配器端的實(shí)現,I2C 總線(xiàn)驅動(dòng)主要包含了I2C 適配器數據結構I2C_adapter, 以及描述在具體I2C 適配器上的總線(xiàn)通信方法i2c_algorithm 數據結構。
(3)I2C 設備驅動(dòng):I2C 設備驅動(dòng)是對I2C 硬件體系結構中設備端的實(shí)現, 設備一般掛接在受CPU 控制的I2C 適配器上, 通過(guò)I2C 適配器與CPU 交換數據。I2C 設備驅動(dòng)主要包含了數據結構i2c_driver 和i2c_client。
這三部分的關(guān)系如圖1 所示。
圖1Linux 中I2C 體系結構
2.2 I2C驅動(dòng)程序中的重要數據結構
在I2C 框架的i2c.h 這個(gè)頭文件中對4 個(gè)關(guān)鍵的結構體進(jìn)行了定義, 它們分別是i2c_adapter、i2c_algorithm、i2c_driver 和i2c_client。結構體i2c_adapter 是一個(gè)I2C控制器的邏輯抽象,并且作為最核心的數據結構提供了I2C適配器的驅動(dòng)。i2c_algorithm對應一套通信方法, 其封裝了對一個(gè)I2C 控制器的讀寫(xiě)操作, 并且提供的通信函數可以控制適配器上產(chǎn)生特定的訪(fǎng)問(wèn)周期,這套通信方法由驅動(dòng)開(kāi)發(fā)者來(lái)完成。i2c_driver 則是對應于一套驅動(dòng)方法,用于輔助作用的數據結構,不對應任何物理實(shí)體,僅是提供了I2C 設備i2c_client 的驅動(dòng)。而i2c_client 對應于真實(shí)的物理設備,描述具體設備可能的私有數據結構。
2.3I2C驅動(dòng)程序中重要數據結構之間的關(guān)系
對于上述的4 個(gè)結構體來(lái)說(shuō), 其中的i2c_driver 和i2c_client 是與具體I2C 設備相關(guān)的,而i2c_adapter 和i2c_algorithm則共同構成I2C 總線(xiàn)適配器驅動(dòng)。一個(gè)algorithm 可以適用于多個(gè)I2C 總線(xiàn)上的不同adapters, 但具體的每個(gè)adapter 只能對應于一個(gè)algorithm。在i2c_adapter 數據結構中設計了clients指針數組, 用于記錄該總線(xiàn)上每個(gè)設備的i2c_client 數據結構。
另外, 定義內核中全局靜態(tài)指針數組adapters 和drivers 分別記錄已注冊的I2C 適配器驅動(dòng)和I2C 設備驅動(dòng)程序。值得注意的是同一個(gè)i2c_adapter 中的不同的i2c_client 可能使用同一個(gè)i2c_driver,而分屬于不同i2c_adapter 中的兩個(gè)i2c_client 也可能使用同一個(gè)i2c_driver。
3 一個(gè)具體的I2C 設備驅動(dòng)程序的開(kāi)發(fā)
AT24C08 是由ATMEL 公司出品的一款EEPROM 存儲器。
作為一個(gè)標準的I2C 設備AT24C08 有4 個(gè)塊存儲區, 一個(gè)塊有256 個(gè)數據存儲單元,整個(gè)AT24C08 具有1024 個(gè)存儲單元。由于每個(gè)數據存儲單元可存1 字節的數據,所以整塊AT24C08 的存儲能力為1KB。
3.1 I2C 設備驅動(dòng)程序的一般結構及運行流程圖
開(kāi)發(fā)一個(gè)具體的I2C 設備驅動(dòng)需要一個(gè)完整、標準的結構,而該結構的實(shí)現是通過(guò)編寫(xiě)兩個(gè)方面的接口而完成的, 一個(gè)是用以?huà)旖覫2C adapter 層來(lái)實(shí)現對I2C 總線(xiàn)及I2C設備具體的訪(fǎng)問(wèn)方法, 即I2C 核心層的接口, 主要實(shí)現attach_adapter,detach_client,command 等接口函數。另一個(gè)是對用戶(hù)應用層的接口, 提供用戶(hù)程序訪(fǎng)問(wèn)I2C設備的接口, 包括實(shí)現open,release,read,write 以及ioctl 等標準文件操作的接口函數。下面將通過(guò)對核心層接口和應用層接口的分析來(lái)說(shuō)明I2C 設備驅動(dòng)程序的運行機制。圖2 為I2C 設備驅動(dòng)程序運行流程圖(圖中at 代表具體的設備AT24C08):
3.2 I2C 設備驅動(dòng)的I2C 核心層接口分析
如圖2 的用戶(hù)空間在通過(guò)insmod 命令加載設備驅動(dòng)程序時(shí), 設備驅動(dòng)將通過(guò)使用動(dòng)態(tài)模塊的方式加載并指向設備初始化函數at_init(),在初始化函數中使用regiSTer_chrdev()進(jìn)行字符型設備的注冊, 并可以通過(guò)靜態(tài)和動(dòng)態(tài)兩種方法來(lái)申請注冊到系統中的設備號。另外將調用核心i2c -core.c 中提供的i2c_add_driver()函數注冊由at_driver 數據結構描述的驅動(dòng)方法,該數據結構中完成了對驅動(dòng)程序的標示, 并包含了兩個(gè)重要的成員函數at_attach_adapter()和at_detach_client()。
在i2c_add_driver () 注冊at_driver 數據結構后,at_attach_adapter()函數就會(huì )被自動(dòng)調用,其遍歷系統中的每個(gè)i2c 總線(xiàn)驅動(dòng), 探測想要訪(fǎng)問(wèn)的設備, 連接符合i2c driver 特定條件的i2c adapter,并通過(guò)i2c adapter 實(shí)現對I2C 總線(xiàn)及其設備的訪(fǎng)問(wèn)。
而at_attach_adapter()的功能則是依靠調用i2c-core.c 核心中的i2c_probe()函數來(lái)實(shí)現的,通過(guò)i2c_probe()函數可以認領(lǐng)adapter所指向的適配器上的所有合適的設備。設備可能使用的地址由addr_data 數組指出。通過(guò)設備地址每次檢測到新設備后,i2c_probe()將使用它的第三個(gè)參數即回調函數初始化設備的數據結構i2c_client,并用i2c_check_functiONality()確定I2C 適配器所支持的通信方法。另外再使用i2c_attach_client()知會(huì )I2C 核心系統中包含了一個(gè)新的I2C 設備。
通過(guò)rmmod 命令對設備驅動(dòng)進(jìn)行卸載時(shí), 在卸載函數at_exit()中將使用i2c_del_driver(),其調用會(huì )引起與數據結構at_driver 關(guān)聯(lián)的每個(gè)i2c_client 與之解除關(guān)聯(lián), 隨后at_detach_client()函數也將因此而被調用,而at_detach_client()中的i2c_detach_client()又完成與i2c_attach_client()相反的過(guò)程,并使用kfree 釋放由client 所占的內存。另外卸載函數at_exit()中還將使用unregister_chrdev()對字符型設備進(jìn)行注銷(xiāo)。
3.3I2C設備驅動(dòng)用戶(hù)應用層接口分析
在注冊字符型設備時(shí), 設備驅動(dòng)中初始化了一個(gè)structfile_operations 文件操作結構體變量用于鏈接字符設備驅動(dòng)程序和用戶(hù)應用程序,在該結構中定義了一組函數指針。系統就是通過(guò)這組函數指針對AT24C08 進(jìn)行具體的操作,系統首先通過(guò)設備文件的主設備號找到相應的設備驅動(dòng)程序, 然后讀取這個(gè)數據結構相應的函數指針,找到相關(guān)的功能函數,接著(zhù)把控制權交給該函數,從而就在上層屏蔽了設備驅動(dòng)的具體實(shí)現細節,提供給用戶(hù)一個(gè)方便快捷的接口。該結構中的at_open(),對應于用戶(hù)應用層的open()接口函數,其通過(guò)mknod 創(chuàng )建的設備節點(diǎn)對設備文件進(jìn)行打開(kāi)操作。而對應用戶(hù)層release () 接口函數的at_release () 則負責設備文件的釋放操作。file_operations 中的at_ioctl()則主要是為用戶(hù)提供一些控制該AT24C08 的命令。對一塊具體設備進(jìn)行讀寫(xiě)操作是編寫(xiě)驅動(dòng)要達到目的,file_operations結構體中所指向的讀寫(xiě)函數at_read(),at_write()完成了對AT24C08 的寫(xiě)入和讀出操作。
就寫(xiě)函數而言, 在寫(xiě)數據之前必須先輸入測試單元的起始地址, 然后再對寫(xiě)入的數據分配相應內存, 然后使用copy_from_user 命令把從用戶(hù)空間獲得的數據拷貝到內核空間,并構造I2C 消息數據,最終通過(guò)i2c-core.c 的i2c-transfer()函數進(jìn)行I2C消息數組的傳輸,而i2c_transfer()將指向總線(xiàn)驅動(dòng)中的算法i2c_algorithm 所對應的具體適配器的master_xfer()方法,這樣就借助i2c-core.c 作為紐帶連接了設備驅動(dòng)和總線(xiàn)驅動(dòng),并完成了兩者之間的通信,其運行流程如圖2 的內核空間所示。
對于讀函數at_read(),同樣要對數據進(jìn)行內存的分配,構造I2C消息,傳輸I2C 消息以及轉換數據空間等。兩者的主要區別則體現在對I2C 消息的構造上,在讀出數據之前,先要寫(xiě)地址,根據寫(xiě)入的地址來(lái)尋找將要讀出的數據的起始地址, 所以在讀函數中就需要構造兩條I2C 消息,一條用于寫(xiě)地址操作,另一條用于讀數據操作。另外在轉換數據空間時(shí), 讀函數將使用copy_to_user 把內核空間的數據拷貝到用戶(hù)空間。
3.4 AT24C08 的單設備多驅動(dòng)的實(shí)現方式
單設備多驅動(dòng)是本文的一個(gè)創(chuàng )新點(diǎn)。設計中實(shí)現了分3 個(gè)設備驅動(dòng)一對1 塊AT24C08 進(jìn)行操作。設備驅動(dòng)1 對AT24C08的第1 個(gè)塊操作,設備驅動(dòng)2 對第2 個(gè)塊操作,設備驅動(dòng)3 對第3 和第4 個(gè)塊進(jìn)行操作。對塊的分開(kāi)操作體現在對設備地址的探測上,由于保存設備地址信息的是二元數組addr_data,所以在多驅動(dòng)對單一的AT24C08 操作時(shí)就需要在該二元數組中指明每個(gè)設備驅動(dòng)程序所控制的設備地址。對于控制第1 個(gè)塊的設備驅動(dòng)1,通過(guò)數組normal_addr 指出要進(jìn)行操作的設備地址為0x50,如下所示:
static unsigned short normal_addr[]={ 0x50,I2C_CLIENT_END};
再通過(guò)其對數組addr_data 進(jìn)行初始化, 這樣, 設備驅動(dòng)1就能檢測到數組中所指出的AT24C08 的第1 個(gè)塊,而跳過(guò)其他的塊, 達到了只對單一特定塊操作的目的。對于設備驅動(dòng)2 來(lái)說(shuō), 只需把數組normal_addr 中地址改為AT24C08 的第2 個(gè)塊的地址0x51 即可。同理,對設備驅動(dòng)3,只需把normal_addr 中的單一地址改為兩個(gè)地址即可,如下所示:
static unsigned short normal_addr [] = { 0x52,0x53, I2C_CLIENT_END};
這樣就可使設備驅動(dòng)只探測到后兩個(gè)塊,而跳過(guò)其他塊,以達到對單一AT24C08 中多個(gè)塊操作的目的。然后再用insmod命令加載編譯好的三個(gè).ko 驅動(dòng)模塊, 獲得3 個(gè)不同的設備號后,接著(zhù)根據所獲得的設備號使用mknod 命令創(chuàng )建3 個(gè)不同的字符型設備節點(diǎn), 最后通過(guò)用戶(hù)層的3 個(gè)測試程序分別打開(kāi)已創(chuàng )建的這3 個(gè)不同的設備節點(diǎn)就能分別對不同的塊進(jìn)行讀寫(xiě)操作,至此就實(shí)現了單設備多驅動(dòng)的控制方式。
同樣除了分3 個(gè)驅動(dòng)外, 驅動(dòng)開(kāi)發(fā)者也可以編寫(xiě)4 個(gè)設備驅動(dòng)分別對每1 個(gè)塊進(jìn)行操作, 或者就只編寫(xiě)1 個(gè)設備驅動(dòng)對4 個(gè)塊一起操作,也適用于綁定非連續塊進(jìn)行操作,比如用一個(gè)設備驅動(dòng)控制第1 和第3 個(gè)塊??傊寗?dòng)開(kāi)發(fā)人員可以根據不同的需要進(jìn)行不同的組合方式。
3.5 AT24C08 設備驅動(dòng)程序的驗證與測試
設備驅動(dòng)程序的驗證, 需要通過(guò)用戶(hù)層的測試程序來(lái)實(shí)現,測試程序如下:
fd=open(/dev/at, O_RDWR); //打開(kāi)設備文件,獲得設備文件的文件描述符。
scanf(%u, start_address); //輸入測試單元起始地址。
write(fd,buf,sizeof(buf)); //把以頁(yè)寫(xiě)入方式把輸入的16 個(gè)數據寫(xiě)入內核空間。
4 結束語(yǔ)
作為當前最流行的總線(xiàn)技術(shù)之一,I2C 總線(xiàn)具有結構小巧,使用簡(jiǎn)單高效的特點(diǎn),目前在各種設計中已得到廣泛的應用。本文分析了Linux 下I2C 的體系結構,較為詳盡的說(shuō)明了I2C驅動(dòng)程序中的一些重要數據結構以及這些數據結構之間的關(guān)系,并論述了I2C 驅動(dòng)程序體系的運行機制, 最后以一個(gè)EEPROM 芯片AT24C08 為例,詳細的給出了一個(gè)具體設備驅動(dòng)的基本開(kāi)發(fā)過(guò)程, 并說(shuō)明了設備驅動(dòng)中的兩個(gè)重要接口,I2C 核心層接口和用戶(hù)應用層接口。更重要的是本文還提供了一種單設備多驅動(dòng)的實(shí)現方式,這將帶給驅動(dòng)開(kāi)發(fā)人員一定的啟示。另外,本文還進(jìn)行了設備驅動(dòng)程序的測試與驗證工作, 保證了設備驅動(dòng)程序編寫(xiě)的正確性。本文的設備驅動(dòng)設計方法也將對其他相關(guān)I2C設備驅動(dòng)的設計提供良好的借鑒作用。
本文作者創(chuàng )新點(diǎn):實(shí)現單設備多驅動(dòng)的驅動(dòng)模式。
linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)
評論