1. 程式人生 > >i2c- sda掛死分析

i2c- sda掛死分析


I2C是由Philips公司發明的一種序列資料通訊協議,僅使用兩根訊號線:SerialClock(簡稱SCL)和SerialData(簡稱SDA)。I2C是匯流排結構,1個Master,1個或多個Slave,各Slave裝置以7位地址區分,地址後面再跟1位讀寫位,表示讀(=1)或者寫(=0),所以我們有時也可看到8位形式的裝置地址,此時每個裝置有讀、寫兩個地址,高7位地址其實是相同的。
I2C資料格式如下:
無資料:SCL=1,SDA=1;
開始位(Start):當SCL=1時,SDA由1向0跳變;
停止位(Stop):當SCL=1時,SDA由0向1跳變;
資料位:當SCL由0向1跳變時,由傳送方控制SDA,此時SDA為有效資料,不可隨意改變SDA;

當SCL保持為0時,SDA上的資料可隨意改變;
地址位:定義同資料位,但只由Master發給Slave;
應答位(ACK):當傳送方傳送完8位時,傳送方釋放SDA,由接收方控制SDA,且SDA=0;
否應答位(NACK):當傳送方傳送完8位時,傳送方釋放SDA,由接收方控制SDA,且SDA=1。
當資料為單位元組傳送時,格式為:
開始位,8位地址位(含1位讀寫位),應答,8位資料,應答,停止位。
當資料為一串位元組傳送時,格式為:
開始位,8位地址位(含1位讀寫位),應答,8位資料,應答,8位資料,應答,……,8位資料,應答,停止位。
需要注意的是:
1,SCL一直由Master控制,SDA依照資料傳送的方向,讀資料時由Slave控制SDA,寫資料時由Master控制SDA。當8位資料傳送完畢之後,應答位或者否應答位的SDA控制權與資料位傳送時相反。

2,開始位“Start”和停止位“Stop”,只能由Master來發出。
3,地址的8位傳送完畢後,成功配置地址的Slave裝置必須傳送“ACK”。否則否則一定時間之後Master視為超時,將放棄資料傳送,傳送“Stop”。
4,當寫資料的時候,Master每傳送完8個數據位,Slave裝置如果還有空間接受下一個位元組應該回答“ACK”,Slave裝置如果沒有空間接受更多的位元組應該回答“NACK”,Master當收到“NACK”或者一定時間之後沒收到任何資料將視為超時,此時Master放棄資料傳送,傳送“Stop”。
5,當讀資料的時候,Slave裝置每傳送完8個數據位,如果Master希望繼續讀下一個位元組,Master應該回答“ACK”以提示Slave準備下一個數據,如果Master不希望讀取更多位元組,Master應該回答“NACK”以提示Slave裝置準備接收Stop訊號。

6,當Master速度過快Slave端來不及處理時,Slave裝置可以拉低SCL不放(SCL=0將發生“線與”)以阻止Master傳送更多的資料。此時Master將視情況減慢或結束資料傳送。
在實際應用中,並沒有強制規定資料接收方必須對於傳送的8位資料做出迴應,尤其是在Master和Slave端都是用GPIO軟體模擬的方法來實現的情況下,程式設計者可以事先約定資料傳送的長度,slave不檢查NACK,有時可以起到減少系統開銷的效果。但是如果slave方是硬體i2c要求一定要標準的NACK,master方是GPIO軟體模擬i2c並沒有正確的傳送NACK,就會出現“slave收不到stop”導致i2c掛死。

在正常情況下,I2C匯流排協議能夠保證匯流排正常的讀寫操作。但是,當I2C主裝置異常復位時(看門狗動作,板上電源異常導致復位晶片動作,手動按鈕復位等等)有可能導致I2C匯流排死鎖產生。下面詳細說明一下匯流排死鎖產生的原因。 
    在I2C主裝置進行讀寫操作的過程中.主裝置在開始訊號後控制SCL產生8個時鐘脈衝,然後拉低SCL訊號為低電平,在這個時候,從裝置輸出應答訊號,將SDA訊號拉為低電平。如果這個時候主裝置異常復位,SCL就會被釋放為高電平。此時,如果從裝置沒有復位,就會繼續I2C的應答,將SDA一直拉為低電平,直到SCL變為低電平,才會結束應答訊號。而對於I2C主裝置來說.復位後檢測SCL和SDA訊號,如果發現SDA訊號為低電平,則會認為I2C匯流排被佔用,會一直等待SCL和SDA訊號變為高電平。這樣,I2C主裝置等待從裝置釋放SDA訊號,而同時I2C從裝置又在等待主裝置將SCL訊號拉低以釋放應答訊號,兩者相互等待,I2C匯流排進人一種死鎖狀態。同樣,當I2C進行讀操作,I2C從裝置應答後輸出資料,如果在這個時刻I2C主裝置異常復位而此時I2C從裝置輸出的資料位正好為0,也會導致I2C匯流排進入死鎖狀態。

方法

    (1)儘量選用帶復位輸人的I2C從器件。

    (2)將所有的從I2C裝置的電源連線在一起,通過MOS管連線到主電源,而MOS管的導通關斷由I2C主裝置來實現。
    (3)在I2C從裝置設計看門狗的功能。

    (4)在I2C主裝置中增加I2C匯流排恢復程式。

        每次I2C主裝置復位後,如果檢測到SDA資料線被拉低,則控制I2C中的SCL時鐘線產生9個時鐘脈衝(針對8位資料的情況,“9個clk可以啟用”的方法來自NXP的文件,NXP(Philips)作為I2C匯流排的鼻祖,這樣的說法是可信的),這樣I2C從裝置就可以完成被掛起的讀操作,從死鎖狀態中恢復過來。



        這種方法有很大的侷限性,因為大部分主裝置的I2C模組由內建的硬體電路來實現,軟體並不能夠直接控制SCL訊號模擬產生需要時鐘脈衝。

        或者,傳送I2C_Stop條件也能讓從裝置釋放匯流排。


        如果是GPIO模擬I2C匯流排實現,那麼在I2C操作之前,加入I2C匯流排狀態檢測 I2C_Probe ,如果匯流排被佔用,則可嘗試恢復匯流排,待匯流排釋放後,再進行操作。要保證I2C操作最小單元的完整性,不被其他事件(中斷、高優先順序執行緒,等)打斷。


  (5)在I2C總線上增加一個額外的匯流排恢復裝置。這個裝置監視I2C匯流排。當裝置檢測到SDA訊號被拉低超過指定時間時,就在SCL總線上產生9個時鐘脈衝,使I2C從裝置完成讀操作,從死鎖狀態上恢復出來。匯流排恢復裝置需要有具有程式設計功能,一般可以用微控制器或CPLD實現這一功能。

  (6)在I2C上串人一個具有死鎖恢復的I2C緩衝器,如Linear公司的LTC4307是一個雙向的I2C匯流排緩衝器,並且具有I2C匯流排死鎖恢復的功能。LTC4307匯流排輸入側連線主裝置,匯流排輸出側連線所有從裝置。當LTC4307檢測到輸出側SDA或SCL訊號被拉低30ms時,就自動斷開I2C匯流排輸入側與輸出側的連線.並且在輸出側SCL訊號上產生16個時鐘脈衝來釋放匯流排。當匯流排成功恢復後,LTC4307會再次連線輸入輸出側,使匯流排能夠正常工作。