I2C七宗罪之第一罪(七宗罪第一罪是什么)
七宗罪,七個(gè)天主教的罪過(guò),簡(jiǎn)稱七宗罪。宗為來(lái)源、根源的意思。
天主教教義中提出“按若望格西安和教宗格里高利一世分辨出教徒常遇到的重大惡行”。“重大”在這里的意思在于這些惡行會(huì)引發(fā)其他罪行的發(fā)生,罪行按嚴(yán)重程度遞增依次為傲慢、嫉妒、憤怒、懶惰、貪婪、淫欲和暴食。
I2C第一罪
有些工程師聊起I2C的時(shí)候,會(huì)有不屑一顧的感覺(jué), “切,不就是兩根線嗎,一個(gè)時(shí)鐘,一個(gè)數(shù)據(jù)”!每每碰到這些人,就會(huì)有一種感覺(jué),兄dei,你真是坑沒(méi)有踩夠??!
下面是我按照本人工作時(shí)間先后順序,列出碰到過(guò)的I2C的問(wèn)題。有一點(diǎn)我要強(qiáng)調(diào)一下,我所列出的問(wèn)題,不是從書(shū)上看來(lái)或者從哪里杜撰來(lái)的,每一個(gè)問(wèn)題都是來(lái)自于不同的公司以及不同的項(xiàng)目,由本人親歷并且解決好的問(wèn)題,希望對(duì)年輕的工程師有所幫助!
2005年, 在L公司(想想當(dāng)年的L公司,那可是風(fēng)光的很。)的光網(wǎng)絡(luò)系統(tǒng)上有一塊叫LKAXXX的線卡上出現(xiàn)了一個(gè)怪事,說(shuō)到這里,肯定有人一看到MPC860, 就忍不住笑了, 一看就是上了年紀(jì)的大叔,哎,歲月不饒人吶 ^_^,我剛剛從學(xué)校里畢業(yè)的時(shí)候就是MPC860差不多誕生的時(shí)候。
先來(lái)描述一下問(wèn)題:
1. 經(jīng)常當(dāng)有人按下Reset button后發(fā)現(xiàn)系統(tǒng)起不來(lái)了,UART console打印了一半就死在那里;
2. 再次按下復(fù)位后,癥狀一樣, 不管怎么按復(fù)位按鈕系統(tǒng)都死,UART打印一點(diǎn)點(diǎn)信息掛在那里;
3. 多次按復(fù)位按鈕無(wú)效后,斷電重啟后OK;
4. 大部分情況,同一塊板子按復(fù)位按鈕后是OK的,但是少數(shù)情況是Fail的。
這時(shí)候很多就會(huì)說(shuō),這不是很簡(jiǎn)單,讓軟件用調(diào)試器加斷點(diǎn)跟蹤啊,說(shuō)對(duì)了,我們firmware工程師還是很牛逼的,很快就告訴我們問(wèn)題出在I2C上, 我們用示波器測(cè)量在死機(jī)情況下的I2C信號(hào),發(fā)現(xiàn)SDA數(shù)據(jù)信號(hào)一直是低電平,怎么復(fù)位都沒(méi)有用,一直是低,只有斷電重啟后,SDA才變高。那么原因初步定位了,正式因?yàn)镮2C-SDA被強(qiáng)行拉低,才導(dǎo)致系統(tǒng)起不來(lái),而斷電后SDA被釋放了,系統(tǒng)也就正常了。
我們知道I2C是open drain的,肯定是被什么芯片給拉了啊,這個(gè)很容易想到,不應(yīng)該是CPU, 因?yàn)镃PU已經(jīng)被復(fù)位了啊, 那么懷疑的對(duì)象就到了和CPU相連的Device上, 乍一看下面的原理圖, 我Kao,這是連連看么?還能有比這個(gè)更加簡(jiǎn)單的事情嗎?
那么究竟是什么原因?qū)е耂DA被EEPROM拉低了呢?
我們?cè)賮?lái)看一張圖:
我們看到這里對(duì)EEPROM的處理比較特殊, 在絕大部分的原理圖里面,我從來(lái)都看不到,就是把EEPROM的電源加一個(gè)開(kāi)關(guān):
1. 當(dāng)復(fù)位為低電平時(shí),EEPROM的VDD連到低,斷電;
2. 當(dāng)復(fù)位為高電平時(shí),EEPROM的VDD重新連到外部的VDD,恢復(fù)供電。
這時(shí)候聰明的小伙伴們已經(jīng)悟出來(lái), Kao!剛剛上面的LKAXXX的板子,如果我們每次按下復(fù)位按鈕復(fù)位CPU的時(shí)候,通過(guò)按鈕產(chǎn)生的復(fù)位信號(hào)High-Low-High由這里的開(kāi)關(guān)電路把EEPROM的電源斷開(kāi)一會(huì)兒,是不是EEPROM就不會(huì)去把SDA拉低了啊,Bingo, 對(duì)了。
可是又有人說(shuō)了,這不是增加成本嘛,還有啊,也沒(méi)有看見(jiàn)有人這么干過(guò)啊,哈哈,對(duì)了,只有日本人才會(huì)這么用一根筋的設(shè)計(jì)方法,我們中國(guó)人永遠(yuǎn)找到更好的解決辦法,我們繼續(xù)往下走。
請(qǐng)看下面這張圖,有沒(méi)有很熟悉?
這是一個(gè)I2C的讀操作,順序如下:
1. Master發(fā)出start;
2. Master發(fā)出地址和讀命令;
3. Slave給出ACK然后發(fā)出數(shù)據(jù)data7-0,這一共8拍由slave來(lái)驅(qū)動(dòng)I2C SDA,(這里要記住SCL一直是由master來(lái)驅(qū)動(dòng)的,當(dāng)然后面也有特殊情況,這個(gè)我們留在后面的七宗罪里面詳述),8拍的時(shí)間(假設(shè)100K的速率,周期為10us)是80us。
停停停停停, 搞笑的事情來(lái)了,如果在這80us的時(shí)間里面,有人按下了復(fù)位按鈕, 會(huì)怎樣 ?
舉個(gè)“栗子”
假設(shè)四個(gè)人打麻將,我的上家把牌打出來(lái)后,就該輪到我出牌了,可是這時(shí)候來(lái)了個(gè)電話,我去接電話了, 等我回到牌桌后,我忘記了剛剛輪到我出牌,我以為上一把結(jié)束了,直接把麻將推倒洗牌了,這時(shí)候等著我的下家可就不干了,人家等著我出牌好胡呢。然后我這重來(lái)的舉動(dòng)惹惱了人家,道歉也好,賠不是也罷,人家不接受,不玩了!得嘞,這局麻將是玩不下去了。
類比上面I2C的情況,想象一下:
1. 80us的時(shí)候 EEPROM Slave正在配合CPU輸出讀的數(shù)據(jù),人家玩得正high呢;
2. 這時(shí)候CPU收到一個(gè)復(fù)位指令,而且是強(qiáng)行復(fù)位,類似于接電話;
3. 等到CPU復(fù)位完了,完全忘記了剛剛EEPROM正在drive數(shù)據(jù),甚至有可能EERPROM已經(jīng)傳完8bit數(shù)據(jù),正在CPU的NAK(看上圖),這事擱誰(shuí)身上能受得了;
4. 這種情況CPU看起來(lái)也是沒(méi)有辦法,誰(shuí)叫我們按下了復(fù)位按鈕了呢。還有一種情況就是CPU自己不厚道,比如去執(zhí)行優(yōu)先級(jí)中斷程序后,回來(lái)也忘記了別人(EEPROM)正在等待自己繼續(xù)剛才的工作。
這里肯定會(huì)有人問(wèn),不是復(fù)位了嗎? 請(qǐng)仔細(xì)看上面的原理圖, EEPROM是沒(méi)有復(fù)位管腳的,也就是說(shuō), 我們按下復(fù)位按鈕時(shí), CPU復(fù)位了,但是EEPROM沒(méi)有復(fù)位,它的狀態(tài)機(jī)還在等待輸出數(shù)據(jù)給CPU或者等待CPU的NAK指令以便結(jié)束當(dāng)前的這筆操作,這和上面打麻將的例子是一回事。
那么請(qǐng)問(wèn)剛剛的SDA被拉低是怎么回事呢?很簡(jiǎn)單, 上圖的ACK就是低電平,或者Slave drive的data bit7-0其中有高有低啊。
那么除了上面給EEPROM的電源加開(kāi)關(guān)的方式,我們還有上面辦法來(lái)解決這個(gè)問(wèn)題呢?
我們繼續(xù)看圖:
先來(lái)想想剛剛打麻將的事情,如果我打完麻將回來(lái)后,直接牌友每個(gè)人100塊錢(qián),別人肯定是樂(lè)意繼續(xù)陪你玩的,很簡(jiǎn)單的辦法解決了問(wèn)題。如上圖, 我們讓軟件工程師在代碼里面做了下修改:
1. 當(dāng)檢測(cè)到SDA被拉低后;
2. 軟件就持續(xù)發(fā)送9個(gè)時(shí)鐘;
3. 在發(fā)9個(gè)clock的過(guò)程中SDA會(huì)變高變低;
4. 當(dāng)Device發(fā)完所有數(shù)據(jù)后,SDA被釋放;
5. 此時(shí)狀態(tài)機(jī)到達(dá)NAK的phase時(shí),SDA釋放變高,產(chǎn)生了一個(gè)NAK;
6. 注意此時(shí)9個(gè)時(shí)鐘不一定用完,EEPROM就把到達(dá)NAK phase把SDA釋放了,但是CPU是不知道的,他會(huì)一直發(fā)完9個(gè)時(shí)鐘;
7. 最后CPU再發(fā)送一個(gè)stop把整個(gè)讀操作結(jié)束掉;
The 9 clock pulses make the hanging device’s state machine move to the next state after each clock pulse while the SDA released (not pulled down) which will cause a NACK when the state machine will move to the ACK phase. The NACK will force the device to go to idle mode(意思和我上面的步驟一樣)。
1. Master tries to assert a logic 1 on the SDA line;
2. Master still see a logic 0 and then generate a clock pulse on SCL;
3. When device come to NAK phase, then master will generate SDA high which;is a NAK, but master does not know, until master send all the 9 clocks;
4. Master Generate a stop condition。
上面講的是I2C讀操作被中斷導(dǎo)致死機(jī)的情況,下面聊聊I2C寫(xiě)操作被中斷的情況,解決辦法“簡(jiǎn)單粗暴”一些, 大家想想為什么。
這里一樣還是只發(fā)9個(gè)時(shí)鐘,在9個(gè)時(shí)鐘的過(guò)程中,device就可能發(fā)出一個(gè)ack,CPU看到ACK后,再發(fā)一個(gè)stop結(jié)束本次操作:
1. Master tries to assert a logic 1 on the SDA line;
2. Master still see a logic 0 and then generate 9 clock pulse on SCL;
3. Generate a stop condition。
這里要注意,寫(xiě)操作被中斷時(shí),發(fā)出的9個(gè)clock一定是等到最后一個(gè)時(shí)鐘發(fā)完, device才被釋放。而讀操作則不一定,有可能發(fā)了第一個(gè)時(shí)鐘時(shí)device就被釋放了只是CPU不知道,到第9個(gè)時(shí)鐘時(shí)stop。
文章結(jié)束,給大家留一個(gè)思考題,為什么這里一定是9個(gè)時(shí)鐘呢?歡迎評(píng)論區(qū)留言,想明白了,這篇文章你就看懂了。