linux-i2c

迷霧綠洲發表於2019-02-22

1 基本概念介紹
1.1 I2C
I²C(Inter-Integrated Circuit)是內部整合電路的稱呼,是一種序列通訊匯流排,使用多主從架構。I²C只使用兩條雙向開放集極(Open Drain)(序列資料(SDA)及序列時鐘(SCL))並利用電阻將電位上拉。I²C允許相當大的工作電壓範圍,但典型的電壓基準位為+3.3V或+5v。I²C的參考設計使用一個7位元長度的位址空間但保留了16個位址,所以在一組匯流排最多可和112個節點通訊。常見的I²C匯流排依傳輸速率的不同而有不同的模式:標準模式(100 Kbit/s)、低速模式(10 Kbit/s),但時脈頻率可被允許下降至零,這代表可以暫停通訊。而新一代的I²C匯流排可以和更多的節點(支援10位元長度的位址空間)以更快的速率通訊:快速模式(400 Kbit/s)、高速模式(3.4 Mbit/s)。

1.2 I2C 協議
I2C匯流排有兩根訊號線,一根為SDA(資料線),一根為SCL(時鐘線)I2C匯流排是由資料線SDA和時鐘SCL構成的序列匯流排,可傳送和接收資料。任何時候時鐘訊號都是由主控器件產生。在CPU與被控IC之間、IC與IC之間進行雙向傳送. 各種被控制電路均並聯在這條匯流排上,所以每個電路和模組都有唯一的地址,在資訊的傳輸過程中,I2C匯流排上並接的每一模組電路既是主控器(或被控器),又是傳送器(或接收器),這取決於它所要完成的功能。CPU發出的控制訊號分為地址碼和控制量兩部分,地址碼用來選址,即接通需要控制的電路,確定控制的種類;控制量決定該調整的類別(如對比度、亮度等)及需要調整的量。這樣,各控制電路雖然掛在同一條匯流排上,卻彼此獨立,互不相關。
1.3 I2C 訊號型別  
如圖1所示I2C匯流排在傳送資料過程中共有三種型別訊號, 它們分別是:開始訊號、結束訊號和應答訊號。

在這裡插入圖片描述

開始訊號:如圖2所示SCL為高電平時,SDA由高電平向低電平跳變,開始傳送資料。

在這裡插入圖片描述
  
  應答訊號:如圖2所示接收資料的IC在接收到8bit資料後,向傳送資料的IC發出特定的低電平脈衝,表示已收到資料。傳送資料IC發出的電平如虛線所示的高電平,在接收到接收IC發出的應答低電平脈衝後電平被拉低為實線的窄電平。CPU向受控單元發出一個訊號後,等待受控單元發出一個應答訊號,CPU接收到應答訊號後,根據實際情況作出是否繼續傳遞訊號的判斷。若未收到應答訊號,由判斷為受控單元出現故障。
結束訊號:如圖3所示SCL為高電平時,SDA由低電平向高電平跳變,結束傳送資料。

在這裡插入圖片描述
這些訊號中,起始訊號是必需的,結束訊號和應答訊號,都可以不要。

1.4 I2C匯流排操作
I2C運用主/從雙向通訊。器件傳送資料到匯流排上,則定義為傳送器,器件接收資料則定義為接收器。主器件和從器件都可以工作於接收和傳送狀態。 匯流排必須由主器件(通常為微控制器)控制,主器件產生序列時鐘(SCL)控制匯流排的傳輸方向,併產生起始和停止條件。SDA線上的資料狀態僅在SCL為低電平的期間才能改變,SCL為高電平的期間,SDA狀態的改變被用來表示起始和停止條件。
  控制位元組
  在起始條件之後,必須是器件的控制位元組,其中高四位為器件型別識別符(不同的晶片型別有不同的定義,EEPROM一般應為1010),接著三位為片選,最後一位為讀寫位,當為1時為讀操作,為0時為寫操作。
  寫操作
  寫操作分為位元組寫和頁面寫兩種操作,對於頁面寫根據晶片的一次裝載的位元組不同有所不同。
  讀操作
  讀操作有三種基本操作:當前地址讀、隨機讀和順序讀。

linux 驅動

上層操作的介面在結構體 struct i2c_adapter *adap 中,呼叫i2c_add_numbered_adapter(adap) 向系統註冊i2c 的操作介面。系統會呼叫操作介面進行傳送。

	struct i2c_adapter *adap;
	adap = &dev->adapter;
	i2c_set_adapdata(adap, dev);
	adap->owner = THIS_MODULE;
	adap->class = I2C_CLASS_HWMON;
	strlcpy(adap->name, "FH I2C adapter",
			sizeof(adap->name));
	adap->algo = &i2c_fh_algo;
	adap->dev.parent = &pdev->dev;
	adap->nr = pdev->id;
	r = i2c_add_numbered_adapter(adap);
	

驅動需要實現的介面:
static sturct i2c_algirithnm i2c_fh_algo ={
.functionality = i2c_fh_func

.master_xfer = i2c_fh_xfer
}

結構體中實現兩個函式,.functionality 向系統說明驅動的能力,是否支援16bit 的讀寫,是否支援restart 塊連續讀寫的,

static u32 i2c_fh_func(struct i2c_adapter *adap)
{
	return	I2C_FUNC_I2C |
		I2C_FUNC_SMBUS_BYTE |
		I2C_FUNC_SMBUS_BYTE_DATA |
		I2C_FUNC_SMBUS_WORD_DATA |
		I2C_FUNC_SMBUS_I2C_BLOCK;
}

.master_xfer 負責收發資料,i2c 應用都是以msgs的方式進行資料封包,上層需要傳送的資訊需要組織成msgs,驅動在下層接受到msgs之後需要對他盡心高解析,具體是收還是發通過mesg裡面的標誌進行區分。

struct i2c_msg{
_u16 addr;//slave addr
_u16 flags; 收發的標誌
_u16 len;//資料長度
_u8 *buf;//資料地址
}

傳送就將buff的len個資料傳送到slave addr 的裝置上去,
收就在slave addr 上收len割資料存到buff地址。
static int
i2c_fh_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num){
解析msgs
傳送msgs 中的buff 地址資料
}