1. 程式人生 > >I2C裝置驅動詳述

I2C裝置驅動詳述

         I2C驅動需要把握兩大部分內容,一個是理解linux的I2C裝置驅動模型,另一個是操作I2C控制器的方法,後者還需要理解I2C硬體邏輯。但首先要理解I2C及其在linux中到底是怎麼一回事:

一、I2C是怎麼一回事:

1.1、I2C匯流排協議(物理):


I2C是一種序列匯流排的外設介面,它採用同步方式序列接收或傳送資訊,兩個裝置在同一個時鐘下工作。I2C匯流排只用兩根線:序列資料SDASerial Data)、序列時鐘SCLSerial Clock)。

I2C只有一根資料線,因此其傳送資訊和接收資訊不能同時進行。資訊的傳送和接收只能分時進行。I2C序列匯流排工作時傳輸速率最高可達

400K bit/s

I2C總線上的所有器件的SDA線並接在一起,所有器件的SCL線並接在一起,且SDA線和SCL線必須通過上拉電阻連線到正電源。

I2C匯流排器件沒有片選控制線,所以I2C匯流排資料傳輸的開始必須由主器件產生通訊的開始條件(SCL高電平時,SDA產生下降沿);通訊結束時,由主器件產生通訊的結束條件(SCL高電平時,SDA產生上升沿)

讀寫操作中SDA線上資料傳送狀態標記註釋如下:

Start為啟動訊號(SCL為高電平,SDA產生負跳變),由主機發送。

Stop為結束訊號(SCL為高電平,SDA產生正跳變),由主機發送。

AddreeeByte HAddreeeByte L為地址位元組,指定哪一個片及該片的片內某單元地址,由主機發送。

data為資料位元組,由資料傳送方傳送。

主機寫操作期間,用SCL的上升沿寫入資料;主機讀操作期間,用SCL的下降沿讀出資料

二、I2C驅動模型:

2.1、巨集觀模型圖:

 

上面是從一個整體角度描述了linux的I2C裝置驅動模型,下面從具體程式碼和sysfs角度描述:

首先看下需要驅動編寫者實現的platform匯流排的裝置和驅動,在sysfs中的體現:

2.2、Platform裝置:

Platform裝置在程式碼中的作用是記錄I2C控制器的硬體引數,如下:


在sysfs中體現如下:


2.3、platform驅動:

platform驅動在程式碼中的作用是在其probe方法獲取到platform裝置的引數,初始化I2C控制器硬體引數和軟體機制,並在I2C匯流排下注冊一個I2C介面卡裝置,以被核心預設建立的I2C匯流排驅動dev_driver匹配,如下:


下面是probe方法的最後一步,所有platform驅動實現的probe函式都是如此,呼叫i2c_add_numbered_adapter或函式i2c_add_adapter在I2C匯流排下建立I2C介面卡裝置,等待被核心預設建立的I2C匯流排驅動dev_driver匹配,如下:


在sysfs中體現如下:


2.4、i2c介面卡裝置:

建立i2c介面卡裝置,無論函式i2c_add_numbered_adapter或函式i2c_add_adapter都會呼叫函式i2c_register_adapter,本質就是在i2c匯流排下建立裝置(device_register),然後匹配核心預設建立的I2C匯流排驅動dev_driver,如下:



在sysfs中的體現如下:


可見在i2c匯流排的裝置目錄中建立了I2C介面卡裝置i2c-0,注意它的父裝置是platform下的裝置,但所屬匯流排是i2c匯流排;

2.5、i2c介面卡驅動:

在driver/i2c/i2c-dev.c檔案中,核心會預設建立i2c匯流排驅動dev_driver,在i2c_dev_init函式中加入,如下:


I2c_add_driver函式會呼叫i2c_register_driver,它和i2c_register_adapter類似,在i2c匯流排中加入驅動(呼叫函式driver_register),並且匹配i2c匯流排下的裝置,如下:



在sysfs中體現如下:


2.6、i2c匯流排下裝置和驅動的匹配:

不論是驅動匹配裝置還是裝置匹配驅動,都是呼叫函式i2cdev_attach_adapter,如下:


函式get_free_i2c_dev最大的作用是把這個i2c介面卡裝置掛在i2c_dev,再把i2c_dev記錄在系統中,確切的說是掛在連結串列i2c_dev_list中,注意這裡的重點是每個i2c_dev對應一個i2c介面卡裝置,如下:



這樣以後某個使用者程序訪問時,可以把所需訪問的i2c介面卡裝置,細節如下:

2.7、使用者程序訪問:

在driver/i2c/i2c-dev.c檔案中,module_init函式i2c_dev_init會在devfs中建立字元裝置i2c,使用者程序操作i2c介面卡裝置的也是通過訪問該字元裝置實現,如下:


當用戶程序對該裝置進行open操作時,即“open("/dev/i2c-0",O_RDWR))”時,該字元裝置的open方法將根據i2c-%d的%d是多少,確定是訪問哪個i2c_dev也就是哪個i2c介面卡裝置,並記錄在該程序中,如下:

首先由%d確定是哪個i2c_dev即哪個i2c介面卡裝置:



進而記錄在該程序中,標識該使用者程序的訪問情況,這樣這個使用者程序再做read、write、ioctl操作時,就知道是訪問的是這個i2c介面卡裝置,如下:


比如read操作,vfs會給i2c-0字元裝置的read方法傳入上次記錄好的client,它裡邊記錄了在open操作中記錄的i2c介面卡(見上圖),呼叫函式i2c_master_recv,函式i2c_master_recv中會由client解析出它記錄的i2c介面卡裝置,再呼叫函式i2c_transfer,進而再呼叫“i2c演算法”的master_xfer成員,如下:



對於write/ioctl操作,道理和read一樣。

三、i2c介面卡操作細節:

這部分描述的是本文第一部分的具體實現細節,以一個已經穩定的實際使用的示例描述,所有的i2c操作的原理都是一樣的,看懂一個其他都能看懂:

3.1、使用者程序open時一般都幹什麼:

使用者程序呼叫如下:

if ((i2cdevfd = open("/dev/i2c-0", O_RDWR)) < 0)

{

printf("i2c_init: open i2c device error!\r\n");

return   RES_ERR;

}

Vfs會呼叫核心預設建立的i2c匯流排驅動dev_driver的open方法i2cdev_open,根據i2c-%d的%d(如i2c-0,則為0)確定是哪個i2c_dev即哪個i2c介面卡裝置,並記錄在該程序中(2.7已描述);

3.2、使用者程序然後有可能做什麼:

使用者程序然後一般都是呼叫如下:

if (ioctl(i2cdevfd,I2C_TENBIT,0)< 0)

{

printf("i2c_init: ioctl I2C_TENBITerror!\r\n");

return   RES_ERR;

}

對應核心的操作如下:

case I2C_TENBIT:

if (arg)

                  client->flags|= I2C_M_TEN;

         else

                  client->flags &= ~I2C_M_TEN;

         return 0;

即在該程序中去除I2C_M_TEN標誌位,它決定是否考慮片內偏移地址,只作用於某些驅動軟體實現(i2c介面卡具體操作),不要特別關注;

3.3、使用者程序讀操作:

3.3.1、主機片選:

首先需要進行片選,I2C匯流排在物理上只有兩根線,並沒有片選線,所有i2c從裝置都是掛在匯流排的兩根線上,片選需要i2c匯流排主機發送地址,使用者程序呼叫如下:


對應核心實現如下:


可見並未訪問硬體,而是記錄在該程序中

3.3.2、主機寫入片內偏移地址:

使用者程序呼叫write,將要訪問的片內偏移地址發出,如下:


核心態的write方法的呼叫流程為i2c_master_send-à i2c_transfer-ài2c介面卡裝置的“演算法”的master_xfer,驅動編寫者須區分讀寫操作(讀寫標誌由核心在i2c_transfer函式中設定),進而依次進行:1、令i2c控制器產生起始條件訊號;2、寫入片選地址,即3.3.1中僅記錄在使用者程序中尚未寫入硬體的片選地址;3、寫入片內偏移地址;

對於不同的i2c控制器,上面依次進行的三個操作的實現不一樣,這依賴於具體i2c晶片實現,列出程式碼無意義,但道理都是一樣的,必須理解。

3.3.3、主機讀取資料:

在經過必要延時後(事實上往往不需要使用者程序延時,而應是通過訪問i2c晶片暫存器),主機從i2c匯流排讀取資料,使用者態如下:


核心態的read方法的呼叫流程為i2c_master_recv-à i2c_transfer-ài2c介面卡裝置的“演算法”的master_xfer,進而進行讀取相關資料暫存器,注意往往是一位元組一位元組的讀取;全部讀取完成後,寫入停止訊號。

3.4、使用者程序寫操作:

3.4.1、主機片選:

同3.3.1;

3.4.2、主機寫入偏移地址、傳送長度、傳送內容:

使用者程序把偏移地址、傳送長度作為整個傳送buffer的前兩個位元組,後面是實際傳送的內容,告訴驅動的傳送長度要包括髮送長度這個位元組,比如實際傳送內容的長度為a個位元組,那麼告訴驅動的傳送長度就是a+1個位元組,即下面程式碼中write系統呼叫中之所以長度引數為num + 1,如下:


可見,第一位元組是片內偏移地址,第二位元組是傳送長度(要包括長度這個位元組本身所以要num + 1),後面是實際傳送的內容;

對於核心的實現,依次進行產生起始條件、寫入片選地址、寫入偏移地址、寫入長度、逐位元組寫入實際傳送內容,全部寫入後,寫入停止訊號。

4、操作細節簡述:

雖然不同i2c晶片的驅動介面卡具體實現不同,但i2c訪問方式是共同的,如下:

1、             令i2c控制器傳送起始條件後,i2c控制器的狀態暫存器應為0x08或0x10意為起始條件已傳送或再次起始條件已傳送;返回0x00、0x70、0x90為出錯;

2、             寫操作時,寫入片選地址後,i2c控制器的狀態暫存器應為0x18或0x20,意為片選地址傳送成功(區別只是是否收到i2c器件的回覆);

3、             寫操作時,寫入每位元組的資料後,i2c控制器的狀態暫存器應為0x28或0x30,意為該位元組傳送成功(區別只是是否收到i2c器件的回覆),收到0x38或其他值為出錯;

4、             讀操作時,寫入片選地址後,i2c控制器的狀態暫存器應為0x48或0x40,意為片選地址傳送成功(區別只是是否收到i2c器件的回覆);

5、             讀操作時,每讀取一個位元組後,i2c控制器的狀態暫存器應為 0x50或0x58,意為該位元組讀取成功(區別只是是否收到i2c器件的回覆),返回0x38或其他值為出錯;

6、             傳送停止訊號後,i2c控制器的狀態暫存器應為 0xf8,意為停止訊號傳送成功,返回其他值為失敗;

具體的i2c狀態碼可參加下表:

0x08          Startcondition transmitted.

0x10          Repeatedstart condition transmitted.

0x18          Address+ write bit transmitted, acknowledge received.

0x20           Address+ write bit transmitted, acknowledge not received.

0x28          Mastertransmitted data byte, acknowledge received.

0x30          Mastertransmitted data byte, acknowledge not received.

0x38          Master lost arbitration during addressor data transfer.

0x40        Address + read bit transmitted,acknowledge received.

0x48          Address+ read bit transmitted, acknowledge not received.

0x50          Masterreceived read data, acknowledge transmitted.

0x58          Masterreceived read data, acknowledge not transmitted.

0x60          Slave received slave address,acknowledge transmitted.

0x68          Master lost arbitration during addresstransmit, address is targeted to the slave

(write access), acknowledge transmitted.

0x70          General call received, acknowledge transmitted.

0x78          Master lost arbitration during address transmit, generalcall address received,

acknowledge transmitted.

0x80          Slave received write data after receiving slave address,acknowledge transmitted.

0x88          Slave received write data after receiving slave address,acknowledge not transmitted.

0x90          Slave received write data after receiving general call,acknowledge transmitted.

0x98          Slave received write data after receiving general call,acknowledge not transmitted.

0xA0         Slave received stop or repeatedstart condition.

0xA8          Slave received address + read bit, acknowledge transmitted.

0xB0          Master lost arbitration during address transmit, address istargeted to the slave (read

access), acknowledge transmitted.

0xB8          Slave transmitted read data, acknowledge received.

0xC0         Slave transmitted read data, acknowledge not received.

0xC8         Slave transmitted last read byte, acknowledge received.

0xD0         Second address + write bit transmitted, acknowledge received.

0xD8         Second address + write bit transmitted, acknowledge notreceived.

0xE0          Second address + read bit transmitted, acknowledge received.

0xE8         Second address + readbit transmitted, acknowledge not received.

0xF8 No relevantstatus. Interrupt flag is kept 0.

相關推薦

I2C裝置驅動詳述

         I2C驅動需要把握兩大部分內容,一個是理解linux的I2C裝置驅動模型,另一個是操作I2C控制器的方法,後者還需要理解I2C硬體邏輯。但首先要理解I2C及其在linux中到底是怎麼一回事: 一、I2C是怎麼一回事: 1.1、I2C匯流排協議(物理):

i2c裝置驅動

跟所有的 bus-dev-drv模型一樣,當我們拿到一個模組我們需要做的就是dev_drv即裝置驅動程式 一、裝置(device) 方法一、自己寫一個i2c_device.c #include <linux/kernel.h> #include &l

i2c裝置驅動probe函式中platform_data

i2c裝置驅動一般在probe函式的開頭都會先獲取platform_data資料。 1、在沒有使用dts的kernel 驅動中, 要麼直接賦值:client->dev.platform_data = pdata;  要麼使用介面設定:platform_device_

Linux 裝置驅動篇之-------I2c裝置驅動(待續)

Linux 裝置驅動篇之-------I2c裝置驅動 雖然I2C硬體體系結構和協議都很容易理解,但是Linux I2C驅動體系結構卻有相當的複雜度,它主要由3部分組成,即I2C裝置驅動、I2C匯流

Linux I2C裝置驅動編寫(一)

在Linux驅動中I2C系統中主要包含以下幾個成員: I2C adapter 即I2C介面卡 I2C driver 某個I2C裝置的裝置驅動,可以以driver理解。 I2C client 某個I2C裝置的裝置宣告,可以以device理解。 I2C adapter 是

Linux系統I2C裝置驅動編寫方法

硬體平臺:飛思卡爾IMX6 核心版本:kernel3.0.35 Linux的I2C子系統分為三層,I2C核心層,I2C匯流排驅動層和I2C裝置驅動層。I2C核心層由核心開發者提供,I2C匯流排驅動層有晶片廠商提供,而I2C裝置驅動層由於裝置的差異性,就只能是具體的開發需求

linux I2C 裝置驅動學習筆記

一:I2C 概述           I2C是philips提出的外設匯流排.使用SCL時鐘線,SDA序列資料線這兩根訊號線就實現了裝置之間的資料互動,被非常廣泛地應用在CPU與EEPROM,實時鐘,小型LCD等裝置通訊中。  二:在linux下的驅動思路     linu

簡單i2c裝置驅動例項

  相關文章: 平臺: msm8916 OS:安卓5.1 usb4604在裝置上作用是切換裝置為主從模式。 裝置樹檔案如下: [email protected] { compatible = "microchip,usb4604

I2C裝置驅動之字元裝置簡寫

最近有機會需要寫一個 掛載在I2C匯流排的I2C裝置驅動,外設晶片是MCP23017 IO擴充套件晶片,測試是否可以通訊成功,以下是部分程式碼以及除錯的一些注意項: #include <linux/kernel.h> #include <linux/init.h>

Linux 裝置驅動篇之I2c裝置驅動

Linux 裝置驅動篇之I2c裝置驅動fulinux一、I2C驅動體系雖然I2C硬體體系結構和協議都很容易理解,但是Linux I2C驅動體系結構卻有相當的複雜度,它主要由3部分組成,即I2C裝置驅動、

Linux裝置驅動篇——[I2C裝置驅動-1]

i2c-dev.c中提供i2cdev_read()、i2cdev_write()函式來對應使用者空間要使用的read()和write()檔案操作介面,這兩個函式分別呼叫I2C核心的i2c_master_recv()和i2c_master_send()函式來構造一條I2C訊息並引發介面卡algorithm通訊函

Linux I2C裝置驅動編寫(三)-例項分析AM3359

TI-AM3359 I2C介面卡例項分析 I2C Spec簡述 特性: 相容飛利浦I2C 2.1版本規格支援標準模式(100K bits/s)和快速模式(400K bits/s)多路接收、傳送模式支援7bit、10bit裝置地址模式32位元組FIFO緩衝區可程式設計時鐘發生

Linux I2C裝置驅動編寫(二)

在(一)中簡述了Linux I2C子系統的三個主要成員i2c_adapter、i2c_driver、i2c_client。三者的關係也在上一節進行了描述。應該已經算是對Linux I2C子系統有了初步的瞭解。下面再對他們之間的關係進行程式碼層的深入分析,我認為對他們的關係

S5PV210 I2C裝置驅動

對於一個i2c裝置來說,其裝置檔案是最簡單也是最複雜的,說它簡單是因為很裝置廠商會提供linux下的程式碼,這樣就簡單了;但是也有很多廠商它不提供或不完整提供linux下的程式碼,這樣的話當然就複雜了。那麼這個我現在這裡就不說了,下面說說做了幾個I2C裝置(以ISA1200

Linux裝置驅動入門----I2C裝置驅動

/* * I2C驅動的一些模板: * (1)、I2C匯流排驅動的的模組載入和解除安裝函式模板 * (2)、I2C匯流排通訊方法 * (3)、I2C裝置驅動模組的載入和解除安裝 * (4)、I2C裝置驅動的檔案操作介面 * (與普通驅動的檔案操作一致,

i2c裝置驅動的四種構造方法

i2c裝置驅動屬於字元裝置驅動,其構造自然是跟字元裝置的結構一樣了,字元裝置:1、 分配字元裝置號(主次裝置號),設定為0,表示自動分配裝置號  2、構造file_operatios 3、註冊裝置,register_chrdev(1,2,3),三個引數分別是裝置號,名稱(不

21 使用裝置樹的i2c裝置驅動

在核心裡表示i2c裝置驅動的結構體有點小變化: struct i2c_driver { int (*probe)(struct i2c_client *, const struct i2c

手把手教你寫Linux I2C裝置驅動2

轉載文章,原文地址 http://ticktick.blog.51cto.com/823160/760020/ 要想在Linux下讀寫晶片的I2C暫存器,一般需要在Linux編寫一份該晶片的I2C驅動,關於Linux下如何編寫I2C驅動,前一篇文章《手把手教你寫Lin

x4412 i2c裝置驅動開發例項(mpu6050)

        MPU6050 包括陀螺儀和加速度感測器功能,陀螺儀和加速度感測器分別用三個 16bit 的資料表示,量程和精度都是可程式設計的,可按需求設定,具體 MPU6050 引數參照晶片手冊。Exynos4412 共有八組 I2C 控制器,我們使用x4412引出的i2

Linux I2C裝置驅動編寫

在Linux驅動中I2C系統中主要包含以下幾個成員: I2C adapter 即I2C介面卡 I2C driver 某個I2C裝置的裝置驅動,可以以driver理解。 I2C client 某個I2C裝置的裝置宣告,可以以device理解。 I2C adapter 是