I2C總線是Philips公司推出的一種二線制同步串行總線,它由時(shí)鐘線(SCL)和數(shù)據(jù)線(SDA)兩根傳輸線組成。I2C總線具有接口線少、控制簡(jiǎn)單、器件封裝形式小、兼容性好、通信速率較高等優(yōu)點(diǎn),使它成為很多器件的標(biāo)準(zhǔn)接口和標(biāo)準(zhǔn)功能模塊。它成為近年來(lái)微電子通信控制領(lǐng)域廣泛采用的一種總線標(biāo)準(zhǔn)。I2C總線雖然簡(jiǎn)單,但在實(shí)際使用過(guò)程中出現(xiàn)的問(wèn)題還不少,其中最為常見(jiàn)的問(wèn)題就是I2C總線死鎖。當(dāng)出現(xiàn)I2C總線死鎖時(shí),總線上的設(shè)備無(wú)法正常工作,整個(gè)總線陷入癱瘓狀態(tài),這對(duì)于一些要求高可靠性和高安全性的自動(dòng)控制系統(tǒng)而言,是無(wú)法接受的。
I2C總線的標(biāo)準(zhǔn)數(shù)據(jù)幀由主設(shè)備發(fā)出的開(kāi)始信號(hào)(START)作為起始標(biāo)志,再是包含讀/寫(xiě)操作標(biāo)志位的從地址信號(hào),緊跟其后的是與從地址匹配的從設(shè)備的應(yīng)答信號(hào)(ACK),接著是由從設(shè)備(讀操作)或主設(shè)備(寫(xiě)操作)發(fā)出的數(shù)據(jù)信號(hào),緊跟每一個(gè)字節(jié)數(shù)據(jù)信號(hào)(以8位數(shù)據(jù)為例)之后是接收設(shè)備的應(yīng)答信號(hào)(ACK)。當(dāng)數(shù)據(jù)信號(hào)傳輸完畢后,最后是主設(shè)備發(fā)出的結(jié)束信號(hào)(STOP)作為數(shù)據(jù)幀的結(jié)束標(biāo)志。
I2C總線的特性可概括為:
(1)接入I2C總線的器件,SCL和SDA都必須是雙向開(kāi)漏結(jié)構(gòu)的,通過(guò)總線上的上拉電阻拉到邏輯高電平,這樣的結(jié)構(gòu)可以實(shí)現(xiàn)線與(&)功能;
(2)一般情況下,I2C總線的SDA只有在SCL為低電平的時(shí)候才能改變,SCL為高電平的時(shí)候SDA需要保持;
(3)例外的,由主機(jī)發(fā)出的起始信號(hào)START(SCL為高時(shí),SDA由高變低)和停止信號(hào)STOP(SCL為高時(shí),SDA由低變高);
(4)由于I2C總線的線與結(jié)構(gòu)特性,只要總線上任何一個(gè)器件拉低了SDA或SCL,其他器件都無(wú)法拉高它們。如果有器件不釋放總線,則整個(gè)總線上的通訊都會(huì)被暫停。
根據(jù)I2C總線的特性,SDA或SCL被拉低后,I2C總線將出現(xiàn)死鎖的情況。對(duì)于SCL,一般標(biāo)準(zhǔn)I2C從設(shè)備不會(huì)影響到SCL,只有是MCU作為I2C從設(shè)備時(shí)出現(xiàn)程序錯(cuò)誤,或在多主的情況下出現(xiàn)控制沖突,而導(dǎo)致SCL被拉低,但一般可以通過(guò)程序優(yōu)化或添加防沖突機(jī)制加以避免。因此在此重點(diǎn)討論單主控制下SDA被拉低的情況。
主設(shè)備主動(dòng)拉低SDA不會(huì)導(dǎo)致I2C總線死鎖,因?yàn)榭梢酝ㄟ^(guò)復(fù)位I2C來(lái)重新進(jìn)行I2C總線的控制。而I2C從設(shè)備一般不具備復(fù)位引腳,如果其將SDA拉低,將導(dǎo)致死鎖的發(fā)生,即使主設(shè)備復(fù)位都無(wú)法解除。
根據(jù)I2C總線的工作原理,以下兩種情況會(huì)出現(xiàn)從設(shè)備拉低SD A:
(1)主設(shè)備向從設(shè)備寫(xiě)數(shù)據(jù)或地址時(shí),從設(shè)備如果發(fā)出ACK應(yīng)答,則會(huì)在第9個(gè)CLK的期間拉低SDA;
(2)主設(shè)備讀數(shù)據(jù)的時(shí)候,從設(shè)備會(huì)在數(shù)據(jù)位為0時(shí)對(duì)應(yīng)的CL K期間拉低SDA。
根據(jù)I2C的特性,SCL為高的時(shí)候,SDA的電平應(yīng)保持,而等到SCL變低后,SDA電平才能發(fā)生改變。如果在SCL的前半個(gè)周期變?yōu)楦唠娖胶螅髟O(shè)備因某些原因不再拉低SCL,則從設(shè)備將持續(xù)拉低S DA,I2C總線將一直處于被占用狀態(tài)。
在主設(shè)備進(jìn)行寫(xiě)數(shù)據(jù)或地址操作,當(dāng)從設(shè)備發(fā)出ACK應(yīng)答信號(hào)拉低SDA時(shí),如果主設(shè)備突然復(fù)位,將導(dǎo)致時(shí)鐘信號(hào)不完整,進(jìn)而引起從設(shè)備持續(xù)拉低SDA。復(fù)位后的主設(shè)備也就無(wú)法給出啟動(dòng)信號(hào)或停止信號(hào)來(lái)使從設(shè)備釋放對(duì)總線的占用,這樣就出現(xiàn)了I2C總線死鎖。
在主設(shè)備進(jìn)行讀數(shù)據(jù)操作,當(dāng)從設(shè)備發(fā)出的數(shù)據(jù)位為0而拉低S DA時(shí),如果主設(shè)備突然復(fù)位,類(lèi)似的,因從設(shè)備收不到完整的時(shí)鐘信號(hào),導(dǎo)致持續(xù)拉低SDA,進(jìn)而出現(xiàn)I2C總線死鎖的情況。
在主設(shè)備進(jìn)行讀數(shù)據(jù)操作過(guò)程中,當(dāng)接收完最后一個(gè)數(shù)據(jù)時(shí),正常情況應(yīng)該給出NACK信號(hào)告知從設(shè)備不再讀取新的數(shù)據(jù)。但如果主設(shè)備錯(cuò)誤地設(shè)置了的讀取數(shù)據(jù)長(zhǎng)度寄存器值,或因外部干擾等因素導(dǎo)致錯(cuò)誤地發(fā)出了ACK信號(hào)。于是從設(shè)備將繼續(xù)發(fā)送新數(shù)據(jù),若數(shù)據(jù)的第一位恰巧為0,從設(shè)備將對(duì)應(yīng)地拉低SDA。而對(duì)于主設(shè)備而言,其已完成所有數(shù)據(jù)的接收,準(zhǔn)備給出停止信號(hào)STOP,但由于從設(shè)備拉低了SDA,導(dǎo)致主設(shè)備無(wú)法發(fā)出停止信號(hào),這樣主從設(shè)備相互等待,陷入死鎖的境地。
解決I2C總線死鎖問(wèn)題的方法較多,大致有以下幾種:
(1)選用自帶防止I2C總線死鎖的從設(shè)備;
(2)選用帶復(fù)位輸入的I2C從設(shè)備;
(3)從設(shè)備的電源由主設(shè)備控制;
(4)I2C總線上增加一個(gè)額外的總線恢復(fù)設(shè)備;
(5)在I2C總線上串入一個(gè)具有死鎖恢復(fù)功能的I2C緩沖器;
(6)在I2C主設(shè)備中增加死鎖自恢復(fù)程序。
在這些解決方法中,“增加死鎖自恢復(fù)程序”相對(duì)比較方便和實(shí)用,獲得了較廣泛的現(xiàn)場(chǎng)應(yīng)用。但使用這個(gè)方法的前提條件是,主設(shè)備的SDA和SCL可以配置為普通的GPIO功能。
死鎖自恢復(fù)程序的工作原理為:用GPIO在SCL上模擬時(shí)鐘信號(hào),同時(shí)檢測(cè)SDA的狀態(tài)有沒(méi)有被釋放(變?yōu)楦唠娖剑?,一旦檢測(cè)到SDA被釋放,重新將SDA和SCL配置為I2C功能,發(fā)送停止信號(hào)ST OP,告知從設(shè)備前次被中斷的通信結(jié)束了,至此I2C總線死鎖被解除恢復(fù)。
分析了I2C總線產(chǎn)生死鎖的原因和出現(xiàn)死鎖的不同情況,著重描述了“死鎖自恢復(fù)程序”的實(shí)現(xiàn)原理。設(shè)計(jì)者可根據(jù)上述分析的原因,采取對(duì)應(yīng)的措施加以避免,同時(shí)可采用“死鎖自恢復(fù)方法”有效解決I2C總線死鎖帶來(lái)的影響,使系統(tǒng)的可靠性和安全性得到提高。