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