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