STM32串口中斷卡死主循環一直進中斷問題分析

在一項目中,使用STM32作爲主控,程序運行一段時間後概率出現主循環卡死現象。


問題分析如下:

1、程序USART2不停接收並處理串口數據,波特率115200;

2、主循環卡死;

3、USART1中斷及TIM2中斷響應函數運行正常;(USART1及TIM2中斷優先級均比USART2高)

4、出現現象後,拔掉USART2的接收數據線,現象不能回覆正常;

5、出現現象後,拔掉後再插入USART2的接收數據線,現象不能回覆正常;

6、並未出現HardFault現象;


基於以上4點,可能原因如下:

1、USART2接收中斷標誌沒有清除;

2、堆棧數據溢出,導致程序異常;

        3、USART2中斷重入導致異常;

4、USART2中斷函數被異常響應;

        5、USART2中斷ERR;

對於以上可能原因一一分析:

1、中斷接收標誌清楚問題:

(1)USART2接收中斷響應函數如下:

void USART2_Istr(void)
    {  
        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
        {   
            USART_ClearFlag(USART2, USART_FLAG_RXNE);
            USART_ClearITPendingBit(USART2, USART_IT_RXNE);
            Data = USART_ReceiveData(USART2);
            //Process Data
        }
    }


(2)出現現象後,通過Usart1中斷獲取到如下信息:

a. USART_GetITStatus(USART2,  USART_IT_RXNE)  == RESET

b. USART_GetFlagStatus(USART2,  USART_FLAG_RXNE)  == RESET

c. 執行USART_ClearFlag(USART2, USART_FLAG_RXNE)及 USART_ClearITPendingBit(USART2, USART_IT_RXNE)後無法恢復正常;

 結論:與USART2 RXNE中斷標誌無關。


2、堆棧數據溢出,導致程序異常;

(1)使用2倍棧空間,問題存在,概率不會降低;

(2)使用0.5倍棧空間,問題存在,概率不會提高;

(3)使用0.25倍棧空間,程序運行進入HardFault;

結論:與堆棧無關。


3、USART2中斷重入導致異常;

(1)使用標誌法,確認出現問題時,中斷響應函數沒有重入;

結論:中斷響應函數沒有重入。


4、USART2中斷函數被異常響應;

(1)USART2中斷函數可以被正常調用,只是不停進入中斷響應函數,卡死主循環;

(2)檢查程序Map,沒發現與中斷響應函數地址相同的函數;

(3)檢查中斷向量表,沒發現異常;

結論:中斷函數沒有被異常調用;


5、USART2中斷ERR;

(1)關閉USART2中斷,主循環恢復正常;

(2)啓動USART2中斷,主循環卡死;

(3)獲取到DR=0x0000;

(4)USART_GetITStatus取到:RXNE=0,PE=0,TXE=0,TC=0,IDLE=0,LBD=0,CTS=0,ERR=0,ORE=0,NE=0,FE=0;

(5)通過USART_ClearITPendingBit清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均無法恢復正常;

(6)通過USART_GetFlagStatus:

  a.第一次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=1,ORE=1,NE=0,FE=0,PE=0

b.第二次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0

c.第三次:CTS=0,LBD=0,TXE=1,TC=1,RXNE=0,IDLE=0,ORE=0,NE=0,FE=0,PE=0

(7)通過USART_ClearFlag清除CTS,LBD,TXE,TC,RXNE,IDLE,ORE,NE,FE,PE均無法恢復正常;

分析:

(1)爲什麼通過USART_GetITStatus獲取了所有中斷標誌,均爲RESET(TC、TXE中斷沒開),還會進中斷?

(2)爲什麼通過USART_ClearITPendingBit清除了所有中斷標誌,還會進入中斷?

(3)爲什麼關閉USART2中斷後再次啓動它還會進入卡死狀態?

(4)爲什麼通過USART_GetFlagStatus第一次和第二次讀的不一樣?而且USART_ClearFlag清掉所有Flag,也沒法恢復正常?


帶着以上幾個疑問,查看了參考手冊,才恍然大悟!如下:

(1)打開RXNEIE,默認會同時打開RXNE和ORE中斷。


(2)必須第一時間清零RXNE,如沒及時清零,下一幀數據過來時就會產生Overrun error!


(3)錯誤就是ORE導致的

出現錯誤時,讀了RXNE=0,出錯應該是上圖打勾的情況,如下


(4)如文檔說明,要清除ORE中斷需要按順序讀取USART_SR和USART_DR寄存器!

那就是說USART_ClearFlag清掉所有Flag後,還必須讀一遍USART_DR寄存器!

      經過測試出現問題後依次讀讀取USART_SR和USART_DR,程序回覆正常!


(5)那還有一個問題,爲什麼USART_GetITStatus讀不到ORE中斷標誌?

讀USART_GetITStatus函數就知道了,只有CR3的EIE置1且SR的ORE置1,讀出來USART_GetITStatus(USART2,  USART_IT_ORE)  纔是 SET。

見CR3的EIE位說明。


解決辦法,出現通過接收時,通過USART_GetFlagStatus讀取ORE,若不爲RESET,則讀取DR數據丟棄。

修改如下:

 

   void USART2_NewIstr(void)
    {  
        if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)
       {
           USART_ReceiveData(USART2);
         USART_ClearFlag(USART2, USART_FLAG_PE);
       }
        
       if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)
       {
           USART_ReceiveData(USART2);
         USART_ClearFlag(USART2, USART_FLAG_ORE);
       }
        
        if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)
       {
           USART_ReceiveData(USART2);
          USART_ClearFlag(USART2, USART_FLAG_FE);
       }
        
        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
        {   
            USART_ClearFlag(USART2, USART_FLAG_RXNE);
            USART_ClearITPendingBit(USART2, USART_IT_RXNE);
            Data = USART_ReceiveData(USART2);
        }
    }


總結:

1、看文檔!看文檔!還是看文檔!(重要的事情要說3遍)

2、庫函數用的時候,也要注意其實現,稍有不慎就可能用錯。

3、注意USART_GetFlagStatus與USART_GetITStatus的區別,還有中斷響應機制。

4、任意時候都要考慮出錯處理。


原文:https://blog.csdn.net/origin333/article/details/49992383

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章