《電子技術應用》
您所在的位置:首頁 > 模擬設計 > 設計應用 > 嵌入式Linux中I2C設備驅(qū)動程序的研究與實現(xiàn)
嵌入式Linux中I2C設備驅(qū)動程序的研究與實現(xiàn)
摘要: I2C 作為一種目前通用的總線技術,已廣泛應用于EEPROM、實時鐘,、小型LCD 等設備與CPU 的接口中,。分析了嵌入式Linux 中I2C 驅(qū)動程序的體系結(jié)構(gòu),I2C 驅(qū)動程序中一些重要數(shù)據(jù)結(jié)構(gòu)之間的關系以及I2C 驅(qū)動程序的運行機制。最后,結(jié)合具體的EEPROM 芯片AT24C08 說明了在嵌入式Linux 下開發(fā)I2C設備驅(qū)動程序的一般流程,。另外還創(chuàng)新了一般的驅(qū)動方法,實現(xiàn)了單設備多驅(qū)動的驅(qū)動模式,。
Abstract:
Key words :

  引言

  I2C是“Inter Integrated Circuit Bus”的縮寫,中文譯成“內(nèi)部集成電路總線”, 它是Philips 公司于20 世紀80 年代研發(fā)成功的一種具有多端控制功能的雙線雙向串行數(shù)據(jù)總線標準, 其具有模塊化,、電路結(jié)構(gòu)簡單等優(yōu)點。在嵌入式系統(tǒng)中,I2C總線已經(jīng)成為器件接口的標準之一, 常用于連接RAM,、EEPROM 以及LCD 控制器等設備,。另外,總線的數(shù)據(jù)傳輸是以字節(jié)為單位的。

  目前,標準的I2C的傳輸速率可以達到100kbit/s,能支持128 個設備,增強型I2C傳輸速率可達400kbit/s,能支持多達1024 個設備,高速模式下的I2C 傳輸速率更高達3.4Mbit/s,。

  1 Linux 驅(qū)動程序

  驅(qū)動程序是指系統(tǒng)內(nèi)核與系統(tǒng)硬件之間的接口,。Linux 中的每一個外圍物理設備等都有一個專門用于控制該設備的設備驅(qū)動程序" title="設備驅(qū)動程序" target="_blank">設備驅(qū)動程序。設備驅(qū)動可以完成初始化,、釋放以及檢測硬件設備;差錯和故障處理;負責內(nèi)核與硬件,、應用程序與硬件之間的數(shù)據(jù)傳輸與通信的一些重要工作。在嵌入式系統(tǒng)中,設備驅(qū)動為嵌入式操作系統(tǒng)和應用程序訪問硬件設備提供統(tǒng)一的接口,。通過它, 操作系統(tǒng)和應用程序就可以輕松地操作和驅(qū)動硬件架構(gòu)的分層,。

  2 Linux 的I2C 體系結(jié)構(gòu)

  2.1 Linux 下I2C 體系結(jié)構(gòu)分析

  Linux 的I2C 體系結(jié)構(gòu)由3 大部分組成:

  (1)I2C框架:I2C.h 和I2C-core.c 為I2C框架的主體,提供了核心數(shù)據(jù)結(jié)構(gòu)的定義、I2C 適配器驅(qū)動和設備驅(qū)動的注冊,、注銷方法,I2C 通信方法(algorithm)上層的,、與具體適配器無關的代碼、以及檢測設備地址的上層代碼等,。作為核心的I2C-core.c 還為總線驅(qū)動設備提供了一些統(tǒng)一的調(diào)用接口進行讀寫和設置操作, 另外它還提供了將各種支持的總線設備驅(qū)動添加到這個體系中的方法, 以及當不再使用這些總線驅(qū)動時從體系中刪除的方法,。

  (2)I2C 總線驅(qū)動I2C總線驅(qū)動是對I2C 硬件體系結(jié)構(gòu)中適配器端的實現(xiàn),I2C 總線驅(qū)動主要包含了I2C 適配器數(shù)據(jù)結(jié)構(gòu)I2C_adapter, 以及描述在具體I2C 適配器上的總線通信方法i2c_algorithm 數(shù)據(jù)結(jié)構(gòu)。

  (3)I2C 設備驅(qū)動:I2C 設備驅(qū)動是對I2C 硬件體系結(jié)構(gòu)中設備端的實現(xiàn), 設備一般掛接在受CPU 控制的I2C 適配器上, 通過I2C 適配器與CPU 交換數(shù)據(jù),。I2C 設備驅(qū)動主要包含了數(shù)據(jù)結(jié)構(gòu)i2c_driver 和i2c_client,。

  這三部分的關系如圖1 所示。

圖1Linux 中I2C 體系結(jié)構(gòu)

  2.2 I2C驅(qū)動程序中的重要數(shù)據(jù)結(jié)構(gòu)

  在I2C 框架的i2c.h 這個頭文件中對4 個關鍵的結(jié)構(gòu)體進行了定義, 它們分別是i2c_adapter,、i2c_algorithm,、i2c_driver 和i2c_client。結(jié)構(gòu)體i2c_adapter 是一個I2C控制器的邏輯抽象,并且作為最核心的數(shù)據(jù)結(jié)構(gòu)提供了I2C適配器的驅(qū)動,。i2c_algorithm對應一套通信方法, 其封裝了對一個I2C 控制器的讀寫操作, 并且提供的通信函數(shù)可以控制適配器上產(chǎn)生特定的訪問周期,這套通信方法由驅(qū)動開發(fā)者來完成,。i2c_driver 則是對應于一套驅(qū)動方法,用于輔助作用的數(shù)據(jù)結(jié)構(gòu),不對應任何物理實體,僅是提供了I2C 設備i2c_client 的驅(qū)動。而i2c_client 對應于真實的物理設備,描述具體設備可能的私有數(shù)據(jù)結(jié)構(gòu),。

  2.3I2C驅(qū)動程序中重要數(shù)據(jù)結(jié)構(gòu)之間的關系

  對于上述的4 個結(jié)構(gòu)體來說, 其中的i2c_driver 和i2c_client 是與具體I2C 設備相關的,而i2c_adapter 和i2c_algorithm則共同構(gòu)成I2C 總線適配器驅(qū)動,。一個algorithm 可以適用于多個I2C 總線上的不同adapters, 但具體的每個adapter 只能對應于一個algorithm。在i2c_adapter 數(shù)據(jù)結(jié)構(gòu)中設計了clients指針數(shù)組, 用于記錄該總線上每個設備的i2c_client 數(shù)據(jù)結(jié)構(gòu),。

  另外, 定義內(nèi)核中全局靜態(tài)指針數(shù)組adapters 和drivers 分別記錄已注冊的I2C 適配器驅(qū)動和I2C 設備驅(qū)動程序。值得注意的是同一個i2c_adapter 中的不同的i2c_client 可能使用同一個i2c_driver,而分屬于不同i2c_adapter 中的兩個i2c_client 也可能使用同一個i2c_driver,。

  3 一個具體的I2C 設備驅(qū)動程序的開發(fā)

  AT24C08 是由ATMEL 公司出品的一款EEPROM 存儲器,。

  作為一個標準的I2C 設備AT24C08 有4 個塊存儲區(qū), 一個塊有256 個數(shù)據(jù)存儲單元,整個AT24C08 具有1024 個存儲單元。由于每個數(shù)據(jù)存儲單元可存1 字節(jié)的數(shù)據(jù),所以整塊AT24C08 的存儲能力為1KB,。

  3.1 I2C 設備驅(qū)動程序的一般結(jié)構(gòu)及運行流程圖

  開發(fā)一個具體的I2C 設備驅(qū)動需要一個完整,、標準的結(jié)構(gòu),而該結(jié)構(gòu)的實現(xiàn)是通過編寫兩個方面的接口而完成的, 一個是用以掛接I2C adapter 層來實現(xiàn)對I2C 總線及I2C設備具體的訪問方法, 即I2C 核心層的接口, 主要實現(xiàn)attach_adapter,detach_client,command 等接口函數(shù)。另一個是對用戶應用層的接口, 提供用戶程序訪問I2C設備的接口, 包括實現(xiàn)open,release,read,write 以及ioctl 等標準文件操作的接口函數(shù)。下面將通過對核心層接口和應用層接口的分析來說明I2C 設備驅(qū)動程序的運行機制,。圖2 為I2C 設備驅(qū)動程序運行流程圖(圖中at 代表具體的設備AT24C08):

  3.2 I2C 設備驅(qū)動的I2C 核心層接口分析

  如圖2 的用戶空間在通過insmod 命令加載設備驅(qū)動程序時, 設備驅(qū)動將通過使用動態(tài)模塊的方式加載并指向設備初始化函數(shù)at_init(),在初始化函數(shù)中使用register_chrdev()進行字符型設備的注冊, 并可以通過靜態(tài)和動態(tài)兩種方法來申請注冊到系統(tǒng)中的設備號,。另外將調(diào)用核心i2c -core.c 中提供的i2c_add_driver()函數(shù)注冊由at_driver 數(shù)據(jù)結(jié)構(gòu)描述的驅(qū)動方法,該數(shù)據(jù)結(jié)構(gòu)中完成了對驅(qū)動程序的標示, 并包含了兩個重要的成員函數(shù)at_attach_adapter()和at_detach_client()。

  在i2c_add_driver () 注冊at_driver 數(shù)據(jù)結(jié)構(gòu)后,at_attach_adapter()函數(shù)就會被自動調(diào)用,其遍歷系統(tǒng)中的每個i2c 總線驅(qū)動, 探測想要訪問的設備, 連接符合i2c driver 特定條件的i2c adapter,并通過i2c adapter 實現(xiàn)對I2C 總線及其設備的訪問,。

  而at_attach_adapter()的功能則是依靠調(diào)用i2c-core.c 核心中的i2c_probe()函數(shù)來實現(xiàn)的,通過i2c_probe()函數(shù)可以認領adapter所指向的適配器上的所有合適的設備,。設備可能使用的地址由addr_data 數(shù)組指出。通過設備地址每次檢測到新設備后,i2c_probe()將使用它的第三個參數(shù)即回調(diào)函數(shù)初始化設備的數(shù)據(jù)結(jié)構(gòu)i2c_client,并用i2c_check_functionality()確定I2C 適配器所支持的通信方法,。另外再使用i2c_attach_client()知會I2C 核心系統(tǒng)中包含了一個新的I2C 設備,。

  通過rmmod 命令對設備驅(qū)動進行卸載時, 在卸載函數(shù)at_exit()中將使用i2c_del_driver(),其調(diào)用會引起與數(shù)據(jù)結(jié)構(gòu)at_driver 關聯(lián)的每個i2c_client 與之解除關聯(lián), 隨后at_detach_client()函數(shù)也將因此而被調(diào)用,而at_detach_client()中的i2c_detach_client()又完成與i2c_attach_client()相反的過程,并使用kfree 釋放由client 所占的內(nèi)存。另外卸載函數(shù)at_exit()中還將使用unregister_chrdev()對字符型設備進行注銷,。

  3.3I2C設備驅(qū)動用戶應用層接口分析

  在注冊字符型設備時, 設備驅(qū)動中初始化了一個structfile_operations 文件操作結(jié)構(gòu)體變量用于鏈接字符設備驅(qū)動程序和用戶應用程序,在該結(jié)構(gòu)中定義了一組函數(shù)指針,。系統(tǒng)就是通過這組函數(shù)指針對AT24C08 進行具體的操作,系統(tǒng)首先通過設備文件的主設備號找到相應的設備驅(qū)動程序, 然后讀取這個數(shù)據(jù)結(jié)構(gòu)相應的函數(shù)指針,找到相關的功能函數(shù),接著把控制權交給該函數(shù),從而就在上層屏蔽了設備驅(qū)動的具體實現(xiàn)細節(jié),提供給用戶一個方便快捷的接口。該結(jié)構(gòu)中的at_open(),對應于用戶應用層的open()接口函數(shù),其通過mknod 創(chuàng)建的設備節(jié)點對設備文件進行打開操作,。而對應用戶層release () 接口函數(shù)的at_release () 則負責設備文件的釋放操作,。file_operations 中的at_ioctl()則主要是為用戶提供一些控制該AT24C08 的命令。對一塊具體設備進行讀寫操作是編寫驅(qū)動要達到目的,file_operations結(jié)構(gòu)體中所指向的讀寫函數(shù)at_read(),at_write()完成了對AT24C08 的寫入和讀出操作,。

  就寫函數(shù)而言, 在寫數(shù)據(jù)之前必須先輸入測試單元的起始地址, 然后再對寫入的數(shù)據(jù)分配相應內(nèi)存, 然后使用copy_from_user 命令把從用戶空間獲得的數(shù)據(jù)拷貝到內(nèi)核空間,并構(gòu)造I2C 消息數(shù)據(jù),最終通過i2c-core.c 的i2c-transfer()函數(shù)進行I2C消息數(shù)組的傳輸,而i2c_transfer()將指向總線驅(qū)動中的算法i2c_algorithm 所對應的具體適配器的master_xfer()方法,這樣就借助i2c-core.c 作為紐帶連接了設備驅(qū)動和總線驅(qū)動,并完成了兩者之間的通信,其運行流程如圖2 的內(nèi)核空間所示,。

  對于讀函數(shù)at_read(),同樣要對數(shù)據(jù)進行內(nèi)存的分配,構(gòu)造I2C消息,傳輸I2C 消息以及轉(zhuǎn)換數(shù)據(jù)空間等。兩者的主要區(qū)別則體現(xiàn)在對I2C 消息的構(gòu)造上,在讀出數(shù)據(jù)之前,先要寫地址,根據(jù)寫入的地址來尋找將要讀出的數(shù)據(jù)的起始地址, 所以在讀函數(shù)中就需要構(gòu)造兩條I2C 消息,一條用于寫地址操作,另一條用于讀數(shù)據(jù)操作,。另外在轉(zhuǎn)換數(shù)據(jù)空間時, 讀函數(shù)將使用copy_to_user 把內(nèi)核空間的數(shù)據(jù)拷貝到用戶空間,。

  3.4 AT24C08 的單設備多驅(qū)動的實現(xiàn)方式

  單設備多驅(qū)動是本文的一個創(chuàng)新點。設計中實現(xiàn)了分3 個設備驅(qū)動一對1 塊AT24C08 進行操作,。設備驅(qū)動1 對AT24C08的第1 個塊操作,設備驅(qū)動2 對第2 個塊操作,設備驅(qū)動3 對第3 和第4 個塊進行操作,。對塊的分開操作體現(xiàn)在對設備地址的探測上,由于保存設備地址信息的是二元數(shù)組addr_data,所以在多驅(qū)動對單一的AT24C08 操作時就需要在該二元數(shù)組中指明每個設備驅(qū)動程序所控制的設備地址。對于控制第1 個塊的設備驅(qū)動1,通過數(shù)組normal_addr 指出要進行操作的設備地址為0x50,如下所示:

  static unsigned short normal_addr[]={ 0x50,I2C_CLIENT_END};

  再通過其對數(shù)組addr_data 進行初始化, 這樣, 設備驅(qū)動1就能檢測到數(shù)組中所指出的AT24C08 的第1 個塊,而跳過其他的塊, 達到了只對單一特定塊操作的目的,。對于設備驅(qū)動2 來說, 只需把數(shù)組normal_addr 中地址改為AT24C08 的第2 個塊的地址0x51 即可,。同理,對設備驅(qū)動3,只需把normal_addr 中的單一地址改為兩個地址即可,如下所示:

  static unsigned short normal_addr [] = { 0x52,0x53, I2C_CLIENT_END};

  這樣就可使設備驅(qū)動只探測到后兩個塊,而跳過其他塊,以達到對單一AT24C08 中多個塊操作的目的。然后再用insmod命令加載編譯好的三個.ko 驅(qū)動模塊, 獲得3 個不同的設備號后,接著根據(jù)所獲得的設備號使用mknod 命令創(chuàng)建3 個不同的字符型設備節(jié)點, 最后通過用戶層的3 個測試程序分別打開已創(chuàng)建的這3 個不同的設備節(jié)點就能分別對不同的塊進行讀寫操作,至此就實現(xiàn)了單設備多驅(qū)動的控制方式,。

  同樣除了分3 個驅(qū)動外, 驅(qū)動開發(fā)者也可以編寫4 個設備驅(qū)動分別對每1 個塊進行操作, 或者就只編寫1 個設備驅(qū)動對4 個塊一起操作,也適用于綁定非連續(xù)塊進行操作,比如用一個設備驅(qū)動控制第1 和第3 個塊,。總之驅(qū)動開發(fā)人員可以根據(jù)不同的需要進行不同的組合方式,。

  3.5 AT24C08 設備驅(qū)動程序的驗證與測試

  設備驅(qū)動程序的驗證, 需要通過用戶層的測試程序來實現(xiàn),測試程序如下:

  fd=open("/dev/at", O_RDWR); //打開設備文件,獲得設備文件的文件描述符,。

  scanf("%u", &start_address); //輸入測試單元起始地址。

  write(fd,buf,sizeof(buf)); //把以頁寫入方式把輸入的16 個數(shù)據(jù)寫入內(nèi)核空間,。

  4 結(jié)束語

  作為當前最流行的總線技術之一,I2C 總線具有結(jié)構(gòu)小巧,使用簡單高效的特點,目前在各種設計中已得到廣泛的應用,。本文分析了Linux 下I2C 的體系結(jié)構(gòu),較為詳盡的說明了I2C驅(qū)動程序中的一些重要數(shù)據(jù)結(jié)構(gòu)以及這些數(shù)據(jù)結(jié)構(gòu)之間的關系,并論述了I2C 驅(qū)動程序體系的運行機制, 最后以一個EEPROM 芯片AT24C08 為例,詳細的給出了一個具體設備驅(qū)動的基本開發(fā)過程, 并說明了設備驅(qū)動中的兩個重要接口,I2C 核心層接口和用戶應用層接口。更重要的是本文還提供了一種單設備多驅(qū)動的實現(xiàn)方式,這將帶給驅(qū)動開發(fā)人員一定的啟示,。另外,本文還進行了設備驅(qū)動程序的測試與驗證工作, 保證了設備驅(qū)動程序編寫的正確性,。本文的設備驅(qū)動設計方法也將對其他相關I2C設備驅(qū)動的設計提供良好的借鑒作用,。

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權禁止轉(zhuǎn)載,。