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