開發板:mini2440
內核 :linux2.6.32.2
參考 :韋東山畢業班I2C視頻教程
1、i2c協議簡要分析
i2c中線是一種由 PHILIPS 公司開發的串行總線,用于連接微控制器及其外圍設備,它具有以下特點。
1、只有兩條總線線路:一條串行數據線SDA,一條串行時鐘線SCL。
2、每個連接到總線的器件都可以使用軟件根據它的唯一的地址來確定。
3、傳輸數據的設備之間是簡單的主從關系。
4、主機可以用作主機發送器或者主機接收器。
5、它是一個真正的多主機總線,兩個或多個主機同時發起數據傳輸時,可以通過沖突檢測和仲裁來防止數據被破壞。
6、串行的8位雙向傳輸,位速在標準模式下可達 100kbit/s,在快速模式下可達400kbit/s,在高速模式下可待3.4Mbit/s。
7、片上的濾波器可以增加抗干擾能力,保證數據的完整性。
8、連接到同一總線上的IC數量只受到總線的最大電容400Pf的限制。
如上圖所示,啟動一個傳輸時,主機先發送一個S信號,然后發送8位數據。這8位數據的前7位為從機地址,第八位表示傳輸的方向(0表示寫,1表示讀),如果有數據則繼續發送,最后發出P信號停止。
信號類型:
注意:正常數據傳輸時,SDA 在 SCL 為低電平時改變,在 SCL 為高電平時保持穩定。
開始信號 S 信號:
SCL 為高電平時,SDA由高電平向低電平跳變,開始傳送數據。
結束信號 P 信號:
SCL 為高電平時,SDA由低電平向高電平跳變,結束傳送數據。
響應信號 ACK:
接收器在接收到8位數據后,在第9個時鐘周期,拉低 SDA 電平
注意:在第9個時鐘周期,發送器保持SDA為高,如果有ACK,那么第9個時鐘周期SDA為低電平,如果沒有為高電平,發送器根據電平高低分辨是否有ACK信號。
如果使能了IIC中斷,發送完8bit數據后,主機自動進入中斷處理函數,此時SCL被發送器拉低,讓接收器被迫等待。恢復傳輸只需要清除中斷掛起。
2、 s3c2440 讀寫流程
1、設置傳輸模式 IICSTAT[7-6],我們做實驗與AT24C08通信時,2440作為主機,因此只用到主機發模式和主機收模式。
2、寫入從機地址到 IICDS[7-1],此時IICDS[7-1]位表示從機地址,第0位不關心。如 AT24C08 為 0xA0(最低位寫0了,發送到數據線上的7位地址的后邊以為才表示收發,這里雖然寫0但并不是根據這里的0來真正發送的)。
3、寫 0xF0(寫) 或 0xB0(讀)到 IICSTAT 寄存器, 高兩位表示 傳輸模式前邊設置過了,設置IICSTT[5-4] 為 11,使能傳輸,發送S信號。
4、IIC控制器自動將第2步中設置的 IICDS[7-1] 再根據 傳輸模式 補充 IICDS[0]位,發送出去。
5、進入第9個時鐘周期,此時,從機決定是否發出ACK信號,主機進入中斷,判斷是否收到ACK信號,以及是否繼續傳輸。
繼續發送:
1、將數據寫入 IICDS
2、清除中斷掛起,SCL時鐘恢復,IICDS的數據被自動發送到 SDA 線上,回到第5步。
停止發送:
1、寫 0xD0(寫) 和 0x90(讀) 到 IICATAT ,IICATAT[7-6]還是表示的傳輸模式,IICATAT[5-4] == 0 1,發送停止信號
2、清除中斷掛起,SCL時鐘恢復,發出停止信號
3、延時,等待停止信號發出
3、 AT24C08 讀寫分析
1、寫過程
寫過程與2440芯片的里的寫流程相一致,按照流程寫就OK
2、讀過程
讀過程是由2440芯片里的一個寫流程加一個讀流程組合而成,其中寫流程結束沒有發出P信號,而是直接發出了S信號開始讀流程,也就是我為什么加了一道紅線的原因。
附上一份簡單的裸機程序,僅供參考:基于MINI2440
#include #include "s3c2440.h" void Delay(int time); #define WRDATA (1) #define RDDATA (2) typedef struct tI2C { unsigned char *pData; /* 數據緩沖區 */ volatile int DataCount; /* 等待傳輸的數據長度 */ volatile int Status; /* 狀態 */ volatile int Mode; /* 模式:讀/寫 */ volatile int Pt; /* pData中待傳輸數據的位置 */ }tS3C24xx_I2C, *ptS3C24xx_I2C; static tS3C24xx_I2C g_tS3C24xx_I2C; /* * I2C初始化 */ void i2c_init(void) { GPEUP |= 0xc000; // 禁止內部上拉 /* * AT24C08 兩根線 I2CSCL I2CSDA 與 2440芯片相連 * 配置2440 GPECON GPE15 GPE14引腳為I2C功能 */ GPECON |= 0xa0000000; // 選擇引腳功能:GPE15:IICSDA, GPE14:IICSCL /* 開INT_IIC中斷 */ //INTMSK &= ~(BIT_IIC); /* bit[7] = 1, 使能ACK * bit[6] = 0, IICCLK = PCLK/16 * bit[5] = 1, 使能中斷 * bit[3:0] = 0xf, Tx clock = IICCLK/16 * PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz */ IICCON = (1<<7) | (0<<6) | (1<<5) | (0xf); // 0xaf //IICADD = 0x10; // S3C24xx slave address = [7:1] IICSTAT = 0x10; // I2C串行輸出使能(Rx/Tx) } void I_Write(unsigned int slvaddr, unsigned char addr, unsigned char data) { unsigned int ack; // 寫從地址 IICSTAT |= 0x1<<6;//主機寫模式 IICSTAT |= 0x1<<7; IICDS = slvaddr;//0xa0; //write slave address to IICDS IICCON&=~0x10; //clear pending bit IICSTAT = 0xf0; //(M/T start) while((IICCON & 1<<4) == 0);//udelay(10);//ack period and then interrupt is pending // 寫寄存器地址 IICDS = addr; IICCON&=~0x10; //clear pending bit while((IICCON & 1<<4) == 0);//udelay(10);//ack period and then interrupt is pending // 寫數據 IICDS = data; IICCON&=~0x10; //clear pending bit while((IICCON & 1<<4) == 0);//udelay(10);//ack period and then interrupt is pending // 發出停止信號 IICSTAT = 0xD0; //write (M/T stop to IICSTAT) IICCON&=~0x10; //clear pending bit while((IICSTAT & 1<<5) == 1); } unsigned char I_Read(unsigned int slvaddr, unsigned char addr) { unsigned char data = 1; int ack; // 寫從地址 IICSTAT |= 0x1<<6;//主機寫模式 IICSTAT |= 0x1<<7; slvaddr = 0xA0; IICDS = slvaddr;//0xa0; //write slave address to IICDS IICCON&=~0x10; //clear pending bit IICSTAT = 0xf0; //(M/T start) while((IICCON & 1<<4) == 0);//udelay(10);//ack period and then interrupt is pending // 寫寄存器地址 IICDS = addr; IICCON&=~0x10; //clear pending bit while((IICCON & 1<<4) == 0);//udelay(10);//ack period and then interrupt is pending // 寫從地址(讀模式) slvaddr = 0xA1; IICSTAT &= ~(0x1<<6);//主機接受模式 IICSTAT |= 0x1<<7; IICDS = slvaddr; IICCON&=~0x10; //clear pending bit IICSTAT = 0xb0; //(M/R Start) while((IICCON & 1<<4) == 0);//udelay(10);//uart_SendByte('o');//ack period and then interrupt is pending:: // 讀數據 data = IICDS; //IICCON&=~0x10; //clear pending bit IICCON = 0x2f; //清掛起狀態,并設置無應答 while((IICCON & 1<<4) == 0);//udelay(10);//ack period and then interrupt is pending data = IICDS; //IICCON&=~0x10; //clear pending bit IICCON = 0x2f; //清掛起狀態,并設置無應答 while((IICCON & 1<<4) == 0);//udelay(10);//ack period and then interrupt is pending IICSTAT = 0x90; IICCON = 0xaf; //IICCON &= ~0x10; //clear pending bit while((IICSTAT & 1<<5) == 1); return data; } 4、adapter驅動程序 這里,我們主要分析驅動里的發送核心算法,至于注冊中斷,IO內存映射,設置寄存器不在討論。 static int xxx_i2c_xfer(struct i2c_adapter *adpap, struct i2c_msg *msg,int num) 這個算法函數的作用就是將上層封裝好的一些i2c_msg 進行解析,將數據寫入寄存器,發送出去。在設備驅動層,我們使用了類似i2c_smbus_write_byte 等函數,類似的函數有很多,它們的作用就是封裝i2c_msg 結構(比如讀和寫的 msg 肯定不一樣,讀一個字節和讀多個字節也不一樣),然后調用 i2c_smbus_xfer_emulated->i2c_transfer,最終調用到我們的xxx_i2c_xfer函數進行傳輸。通過分析i2c_smbus_xfer_emulated函數,我們可以了解i2c_msg是如何封裝的。下面,我們簡單分析一下,知道最上層想干什么,我們才能知道實現哪些底層的功能不是。 struct i2c_msg { __u16 addr; //從機地址 __u16 flags; __u16 len; // buf 里 有多少個字節 __u8 *buf; // 本 msg 含有的數據,可能是1個字節,可有可能是多個字節 }; 此函數,省略了很多內容,舉例分析而已~,細節請看源碼 static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; int num = read_write == I2C_SMBUS_READ?2:1; // 寫操作兩個Msg 讀操作一個msg 這和我們前面分析AT24c08是一致的 struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, { addr, flags | I2C_M_RD, 0, msgbuf1 } }; msgbuf0[0] = command; // 從機地址右移1位得到的,比如AT24C08 為 0x50 switch(size) { case I2C_SMBUS_BYTE_DATA: // 單字節讀寫 if (read_write == I2C_SMBUS_READ) msg[1].len = 1; /* * 讀: * msgbuf0[0] = command * msg[1].len = 1 ,數據會讀到 msgbuf0[1] 里 */ else { msg[0].len = 2; msgbuf0[1] = data->byte; /* * 寫: * msgbuf0[0] = command * msgbuf0[1] = data->byte */ } break; } status = i2c_transfer(adapter, msg, num); } 上面代碼跟我們分析AT24C08的時候如出一轍,對于一個寫操作,我們只需要一個2440的寫流程對應于這里的一個Msg,然而對于讀操作,我們需要2440的兩個流程,對應于這里的兩個Msg。那么,我們底層控制器驅動需要做的工作就是,取出所有的Msg,將每一個Msg里buf里的數據發送出去,如果有下一個Msg, 那么再將下一個Msg里的buf發送完畢,最后發出P停止信號。還有一點,每發送一個Msg都要先發出S開始信號。 在看adapter程序之前,我們先來簡單思考一下,發出S開始信號之后,可能有以下3中情況: 1、當前msg.len == 0 ,如果有ACK直接發出stop信號。這種情況出現在,控制器枚舉設備的時候,因為它只發送S信號以及設備地址,不發送數據。 2、根據msg->flags 為 I2C_M_RD 等信息判斷讀寫,msg->flags 最低位為1表示讀,最低位為0表示寫。 #define I2C_M_TEN0x0010 /* this is a ten bit chip address */ #define I2C_M_RD0x0001 /* read data, from slave to master */
上一篇:i2c驅動程序全面分析,從adapter驅動程序到設備驅動程序
下一篇:Linux ARMv7中斷向量表搬移(2)
推薦閱讀最新更新時間:2025-06-13 23:03

設計資源 培訓 開發板 精華推薦
- LT8330HS6 8V 至 40V 輸入、±15V 轉換器的典型應用電路
- EVAL-ADUM3481EBZ,用于評估 iCoupler ADuM3481 四通道數字隔離器的評估板
- 具有可充電電池備份和浪涌電流限制的 LTC3106EFE 5V 至 2.2V 轉換器的典型應用電路
- 2.9寸/1.54寸桌面墨水屏擺件
- 使用 Analog Devices 的 LT6206 的參考設計
- 時間控制板 帶均衡
- LTC6990CS6#TRMPBF 正交正弦波振蕩器的典型應用。壓控頻率范圍為 5Hz 至 20kHz,具有 1VP-P 恒定輸出幅度
- Vision FPGA SoM:具有集成視覺、音頻和運動感應功能的基于FPGA的SoM
- RDR-313 - 30 W單路輸出反激式轉換器
- 使用 Analog Devices 的 LT1117CM-2.85 的參考設計