I2C總線簡介
I2C是兩線式串行總線,用于連接微控制器及其外圍設備。
I2C總線最主要的優點是其簡單性和有效性。由于接口直接在組件之上,因此I2C總線占用的空間非常小,減少了電路板的空間和芯片管腳的數量,降低了互聯成本。總線的長度可高達25英尺,并且能夠以10Kbps的最大傳輸速率支持40個組件。I2C總線的另一個優點是,它支持多主控(multimastering), 其中任何能夠進行發送和接收的設備都可以成為主總線。一個主控能夠控制信號的傳輸和時鐘頻率。當然,在任何時間點上只能有一個主控。
單片機的通訊模塊常用的有UART、SPI、I2C、CAN等等,當然還有無線模塊這里不討論。UART大多用于單片機與PC的通信,CAN總線常用于單片機與單片機通信,而SPI和I2C則用于單片機和外圍設備、外圍設備和其它外圍設備的通信,根據自己的需要來設計通訊方式。
相比較SPI而言,I2C需要更少的接線,僅由數據線SDA和時鐘SCL構成 。而SPI則需要四根引線,它們是SDI(數據輸入),SDO(數據輸出),SCLK(時鐘),CS(片選)。但是常常因為I2C的通訊協議較為復雜,不容易在程序中實現而導致數據丟失、無應答、“死等”等問題。
I2C通信、讀寫數據過程
在通信之初,主從機必須根據自己的要求約定好通信規則:command的定義和位置、address的位數和位置。
以讀寫從機寄存器數據為例:
假設從機寄存器地址為8位、從機寄存器也位8位(被讀取數據為8位);
約定讀command為0x01,寫command位0x02;
約定主機發起通信后,第一個slave address字節收到ack后,緊跟的一個字節為command,再下面一個字節為address。
1. 讀寄存器數據步驟:
1.1 主機先發起一次通信,將讀command(0x01)和需要讀取的寄存器地址address寫入從機;(主機發出寫操作)
1.2 從機firmware的處理:
1.2.1 將command和address分別提取出來;
1.2.2 判斷command的含義(本例中,是讀指令還是寫指令);
1.2.3 根據收到的的address,將對應寄存器的的數據放入從機I2C輸出buffer;(這個步驟可以使用指針)
1.3 主機再次發起一次通信,讀取從機的數據;(主機發出讀操作)
2. 寫操作步驟:
2.1 主機發起通信,按約定依次寫入command、要寫入的從機寄存器地址address和要寫入的數據data;
2.2 從機firmware要做的處理:
2.2.1 分別提取command、address和data;
2.2.2 根據command做出判斷(本例中則判斷是寫入還是讀取);
2.2.3 將data寫入與接收到的address對應的寄存器。(這個步驟可以使用指針)。
4、主機發送數據流程
(1)主機在檢測到總線為“空閑狀態”(即 SDA、SCL 線均為高電平)時,發送一個啟動信號“S”,開始一次通信的開始
(2)主機接著發送一個命令字節。該字節由 7 位的外圍器件地址和 1 位讀寫控制位 R/W組成(此時 R/W=0)
(3)相對應的從機收到命令字節后向主機回饋應答信號 ACK(ACK=0)
(4)主機收到從機的應答信號后開始發送第一個字節的數據
(5)從機收到數據后返回一個應答信號 ACK
(6)主機收到應答信號后再發送下一個數據字節
(7)當主機發送最后一個數據字節并收到從機的 ACK 后,通過向從機發送一個停止信號P結束本次通信并釋放總線。從機收到P信號后也退出與主機之間的通信
注意:①主機通過發送地址碼與對應的從機建立了通信關系,而掛接在總線上的其它從機雖然同時也收到了地址碼,但因為與其自身的地址不相符合,因此提前退出與主機的通信;②主機的一次發送通信,其發送的數據數量不受限制。主機是通過 P 信號通知發送的結束,從機收到 P 信號后退出本次通信;③主機的每一次發送后都是通過從機的 ACK 信號了解從機的接收狀況,如果應答錯誤則重發。
5、主機接收數據流程
(1)主機發送啟動信號后,接著發送命令字節(其中 R/W=1)
(2)對應的從機收到地址字節后,返回一個應答信號并向主機發送數據
(3)主機收到數據后向從機反饋一個應答信號
(4)從機收到應答信號后再向主機發送下一個數據
(5)當主機完成接收數據后,向從機發送一個“非應答信號(ACK=1)”,從機收到ASK=1 的非應答信號后便停止發送
(6)主機發送非應答信號后,再發送一個停止信號,釋放總線結束通信
注意:主機所接收數據的數量是由主機自身決定,當發送“非應答信號/A”時從機便結束傳送并釋放總線(非應答信號的兩個作用:前一個數據接收成功,停止從機的再次發送)。
6、總線死鎖原因分析
I2C總線寫操作過程中,主機在產生啟動信號后控制SCL產生8個時鐘脈沖,然后拉低SCL信號為低電平,在這個時候,從機輸出應答信號,將SDA信號拉為低電平。如果這個時候主機異常復位,SCL就會被釋放為高電平。此時,如果從機沒有復位,就會繼續I2C的應答,將SDA一直拉為低電平,直到SCL變為低電平,才會結束應答信號。而對于主機來說,復位后檢測SCL和SDA信號,如果發現SDA信號為低電平,則會認為I2C總線被占用,會一直等待SCL和SDA信號變為高電平。這樣,主機等待從機釋放SDA信號,而同時從機又在等待主機將SCL信號拉低以釋放應答信號,兩者相互等待,I2C總線進人一種死鎖狀態。同樣,當I2C進行讀操作時,從機應答后輸出數據,如果在這個時刻主機異常復位而此時從機輸出的數據位正好為0,也會導致I2C總線進入死鎖狀態。
解決方案通常有如下幾種:
(1)將從機的電源設計為可控,當發生總線死鎖的時將從機復位
(2)可以在從機的程序中加入監測功能,如果總線長時間被拉低則釋放對總線的控制
(3)在主機中增加I2C總線恢復程序。每次主機復位后,如果檢測到SDA被拉低,則控制SCL產生《=9個時鐘脈沖(針對8位數據的情況),每發送一個時鐘脈沖就檢測SDA是否被釋放,如果SDA已經被釋放就再模擬產生一個停止信號,這樣從機就可以完成被掛起的讀寫操作,從死鎖狀態中恢復過來。這種方法有一定的局限性,因為大部分主機的I2C模塊由內置的硬件電路來實現,軟件并不能夠直接控制SCL信號模擬產生需要時鐘脈沖。
掛在I2C總線上的EEPROM設備
EEPROM稱為電擦除式只讀存儲器,一般容量很小、用于保存產品的固化參數,此次跟我狹路相逢的是一款來自ATMEL公司的AT24C512B,總容量為64K,支持以頁的方式寫入數據,頁大小128字節,以下是這款設備的相關信息和操作方法(其他型號類同):
硬件連接。在AT24C512B硬件連接中,跟軟件編程相關的引腳有三個,除了連接在I2C總線上的時鐘線(SCL)、數據線(SDA)引腳之外,還有一個寫保護引腳(WP)連接在GPIO上。
尋址方式。EEPROM可以讓你精確地訪問到每一字節,AT24C512B采用16位的尋址方式共計可以訪問65536字節的地址空間。
讀寫時序。AT24C512B支持的寫操作有單字節寫入、按頁寫入,支持的讀操作有隨機單字節或連接讀取、當前位置單字節或連續讀取,EEPROM一般在電路中做從設備,我此次面對的也是,以下是主設備對EEPROM進行各種操作的操作方法:
單字節寫入:START -》 發送從設備地址(寫控制碼) -》 處理Ack -》 發送字節地址 -》 處理Ack [-》 發送1字節數據 -》 處理Ack] -》 STOP。
按頁寫入:將單字節寫入的[ ]中的操作重復進行128次即可實現。
隨機單字節讀取:START -》 發送從設備地址(寫控制碼) -》 處理Ack -》 發送字節地址 -》 處理Ack -》 START -》 發送器件地址(讀控制碼) -》 處理Ack -》 接收1字節數據 -》 STOP。
隨機連續讀取:在隨機單字節讀取操作的STOP信號發送之前,加入若干個 [-》 發送Ack -》 接收1字節數據] 即可實現。
當前位置單字節讀取:START -》 發送從設備地址(讀控制碼) -》 處理Ack -》 發送字節地址 -》 處理Ack -》 接收1字節數據 -》 STOP。當前指的是之前進行過讀取操作但是沒有發送STOP信號,EEPROM芯片內部指針所在的位置即為當前位置。
當前位置連續讀取:在當前位置單節讀取操作的STOP信號發送之前,加入若干個 [-》 發送Ack -》 接收1字節數據] 即可實現。
關于EEPROM的按頁寫入。為提高數據寫入效率,有的EEPROM設備用一個內部的RAM來提供按頁寫入的功能,進行寫操作的時候,先記錄下要寫入的首地址,然后將接收到的數據都緩存在RAM中,在接收到STOP信號時再把緩存數據一次性保存到先前記錄的地址處。
有兩個需要注意的問題:(a)、如果寫入的數據超過一頁的長度,將發生回卷,即從RAM的0地址處進行數據覆蓋。(b)、如果頁大小為128字節,即0-127字節為第一頁、128-255為第二頁,即頁的邊界位置是絕對的,而不是從寫入數據的起始位置開始計算。
在進行數據讀取操作沒有頁的問題,可以從任意位置開始讀取任意大小的數據,超過EEPROM總容量時發生回卷。
評論