I2C接口進(jìn)入busy狀態(tài)不能退出
問題:該問題發(fā)生在 STM32F103VDT6 器件上。在其產(chǎn)品設(shè)計中,使用了 STM32 的一個 I2C 接口與一個 EEPROM 通信。在系統(tǒng)靠性測試中發(fā)現(xiàn),經(jīng)過長時間運(yùn)行后,STM32 會出現(xiàn)不能讀寫 EEPROM 的現(xiàn)象。通過 NRST 管腳對 STM32 進(jìn)行復(fù)位,復(fù)位后該現(xiàn)象依舊存在。關(guān)掉電源,然后重新上電,現(xiàn)象消失。通過進(jìn)一步測試發(fā)現(xiàn),如果對 STM32反復(fù)做復(fù)位操作,會很容易復(fù)現(xiàn) 這一現(xiàn)象。
本文引用地址:http://www.ex-cimer.com/article/201612/329277.htm調(diào)研:修改軟件,通過打印監(jiān)控 I2C 通信程序的流程,及 I2C 接口的各個寄存器的狀態(tài)。當(dāng)出現(xiàn)上述現(xiàn)象時,I2C接口的狀態(tài)寄存器 SR2中的 Busy 位置‘1’,狀態(tài)寄存器 SR1 中的 ARLO 位置‘1’。用示波器觀察 I2C 總線,發(fā)現(xiàn)其 SCL 為高電平,SDA 為低電平。將 STM32 的復(fù)位腳拉到地,SCL 及 SDA 的狀態(tài)不變。檢查原理圖,確認(rèn) I2C 總線上只有 STM32 和 EEPROM 兩顆器件。
結(jié)論:EEPROM 驅(qū)動 I2C 總線進(jìn)入了非空閑狀態(tài),使得 STM32 在接管總線時發(fā)生總線仲裁失敗,進(jìn)而失去對總 線的控制,無法啟動數(shù)據(jù)的傳輸。EEPROM 的這種狀態(tài)可能是通信被意外中斷造成的。通過對 STM32 進(jìn)行復(fù)位而重現(xiàn)這一現(xiàn)象,在一定程度上吻合了這種猜測。但沒有實驗和理論依據(jù)證實一定是該原因 導(dǎo)致了這一問題,是否還有其它原因在起作用,不得而知。
處理:修改軟件,加入對 I2C 總線修復(fù)的功能。在每次發(fā)送起始條件之前首先檢測 SR2 中 Busy 位,如果為 ‘1’,則說明總線上有異常。此時,可由 GPIO 的 OD 模式代替 I2C 通信口接管 SCL 及 SDA 兩個管 腳。通過翻轉(zhuǎn) GPIO,向 SCL 信號線上發(fā)高電平脈沖,脈沖寬度及間隔勻為 10uS。每發(fā)出一個脈沖之 后,檢測 SDA 信號是否為高電平。若 SDA 信號為已高電平,則將 SCL 拉高,然后向 SDA 信號線發(fā) 出一個 10uS 寬的低電平脈沖。然后將 SCL 及 SDA 兩個管腳交還給 I2C 接口,并通過將 CR1 中的 SWRST 位置‘1’后再清‘0’來復(fù)位 I2C 接口,使其退出 Busy 狀態(tài)。如圖(一)所示:
A. 將 SCL 和 SDA 切換成 GPIO 的 OD 模式;
B. 發(fā)送時鐘脈沖并等待 SDA 跳變到高電平;
C. 在 SDA 上發(fā)出一個低電平脈沖;
D. 在 SDA 拉高后,將 SCL 的 SDA 切換回 I2C 接口;
E. 通過 CR1 中的 SWRST 位復(fù)位 I2C 接口;
建議:STM32 中的 I2C 接口被設(shè)計成為主從自適應(yīng)接口,并充許多個主機(jī)共享一條 I2C 總線。I2C 接口在被使 能之后,會不斷的檢測 SCL 及 SDA 的電平與跳變。當(dāng)發(fā)現(xiàn)有低脈沖出現(xiàn)在 SCL 或 SDA 上時,則認(rèn) 為總線進(jìn)入了 Busy 狀態(tài),其 Busy 標(biāo)志會置‘1’,直到在總線上檢測到一個符合要的停止條件之 后,才認(rèn)為總線回到了空閑狀態(tài),這時由硬件清除 Busy 標(biāo)志。當(dāng) I2C 接口認(rèn)為總處于 Busy 狀態(tài)且不 是由自己占用時,會拒絕向總線上發(fā)送信號,因為它認(rèn)為此刻 I2C 總線正在被其它的主機(jī)所使用。這時 向 I2C 接口發(fā)命令,要求產(chǎn)生起始條件,會導(dǎo)致總線仲裁失敗。要從這種狀態(tài)退出,首先要保證總線是 處于空閑狀態(tài),即 SCL 和 SDA 都為高電平。然后,通過將 CR1 的 SWRST 置‘1’然后清‘0’來復(fù) 位 I2C 接口,以達(dá)到清除 Busy 標(biāo)志回到空閑狀態(tài)目的。
評論