|
近日在做項目的時候,遇到了一個問題讓我百思不得其解。為了盡可能復(fù)現(xiàn)問題,我說的盡量詳細(xì)一些,并附上一些嘗試。
IIC協(xié)議是一種很常用的通信協(xié)議,一般分為硬件IIC和軟件IIC兩種實現(xiàn)方式。在實際使用過程中可能會出現(xiàn)IIC鎖死[1]的問題。其具體表現(xiàn)為:SCL始終為高,SDA始終為低。但這種現(xiàn)象往往出現(xiàn)在硬件IIC,軟件IIC并不會出現(xiàn)。但我在使用過程中卻意外發(fā)現(xiàn)了,軟件IIC也會出現(xiàn)IIC死鎖的現(xiàn)象。
我使用的板子是STM32F103RCT6。資源配置如下:
NVIC分組為2bits搶占2bits響應(yīng)
串口:①USART1用于紅外,串口波特率為9600,使用DMA接受數(shù)據(jù)。②USART2用于語音芯片,波特率9600,使用DMA發(fā)送數(shù)據(jù)。③USART3用于陀螺儀模塊,波特率為57600,陀螺儀的采樣率為50Hz,采用中斷處理數(shù)據(jù),搶占2,響應(yīng)0。④UART4、UART5用于兩個激光測距模塊,波特率為115200,采樣率100Hz,采用中斷處理數(shù)據(jù),搶占2響應(yīng)2.
定時器:①TIM4,CH1-CH4均用于PWM輸出驅(qū)動電機。②TIM2、TIM3采用了編碼器模式,用于采集電機編碼器的值 ③TIM6為搶占0響應(yīng)1的10ms中斷,用于處理當(dāng)前電機的編碼器的值通過PID運算得出PWM輸出值作用于TIM4 ④TIM7為搶占1響應(yīng)0的中斷,用于刷新處理陀螺儀的數(shù)據(jù)。
主函數(shù):①硬件初始化,初始化OLED以及上述定時器串口。OLED采用軟件IIC,運用延時函數(shù)delay_us處理IIC時序。 ②死循環(huán)里是:
- LED1 = ~LED1;
-
- OLED_ShowNum(0,18,flag_water_cd,8,12);
- OLED_FloatShow(0,36,speed_L,12);
- OLED_FloatShow(0,52,speed_R,12);
- OLED_Refresh_Gram();
復(fù)制代碼 即跑馬燈和OLED數(shù)據(jù)更新。由于OLED刷新需要一定時間,雖然沒有delay但可以看到燈是在閃的。
問題描述:當(dāng)系統(tǒng)運行一段時間后,會出現(xiàn)OLED數(shù)據(jù)不更新,燈不再閃爍,SCL為高,SDA為低的現(xiàn)象。可以判定為是IIC死鎖的問題。但經(jīng)過查閱資料,IIC死鎖只會在硬件IIC出現(xiàn),軟件IIC不出現(xiàn)。
一些嘗試:
①注釋掉UART4, UART5初始化后運行五分鐘,測試三次均未出現(xiàn)死鎖問題。 ②注釋掉定時器6的初始化,運行五分鐘,三次測試均不出現(xiàn)死鎖。 ③不注釋任何代碼,系統(tǒng)運行7s后IIC死鎖,燈不再閃爍,OLED不更新。 ④注釋掉UART4,UART5后,修改與陀螺儀的波特率為115200,運行數(shù)十秒后死鎖。⑤注釋掉陀螺儀的初始化代碼,運行約3min后出現(xiàn)死鎖問題。
猜測:高波特率的中斷會打斷IIC時序使主機不能收到IIC的Ack信號。
想過的解決方案:
①采用輸入捕獲和定時器對SCL進(jìn)行檢測,當(dāng)長時間為高電平時再給SCL一個脈沖。實測可以解決但在此系統(tǒng)不能實裝。因為TIM6要進(jìn)行PID運算,如果有比他優(yōu)先級更高的中斷會導(dǎo)致PID更新不穩(wěn)定,電機轉(zhuǎn)動不順暢。②目前臨時辦法是不使用OLED,或者不使用激光測距模塊。不知道論壇的大神有沒有遇到過類似的問題,希望能有所指點。
[1] I2C死鎖原因及解決方法_fengel_cs的專欄-CSDN博客_i2c死鎖
|
|