1. 程式人生 > >大戰STM32奇怪的hardfault,各種無厘頭的真凶!

大戰STM32奇怪的hardfault,各種無厘頭的真凶!

題目起的非常的傻,可能是這幾天為了把這個問題調出來把人都給調廢了吧。。。反正現在找到了問題就特別的開心。

有時候我們在使用STM32進行開發的時候,有時會莫名其妙的進入hardfault,而有時又會出現明明暫存器配置完全一模一樣,程式原來都是好好的能跑的,可是自己改了一點其他無關緊要的東西的時候,整個程式的執行邏輯就不一樣的問題。。。當出現這種問題的時候,一般就屬於C語言和嵌入式結合所帶來的很難排查的問題了:

  1. 指標指飛了
  2. 棧空間堆爆了
  3. 堆空間堆爆了
  4. SRAM爆了

而我這次的除錯經理就遇到了這其中最不常見的一條:SRAM爆掉。。

SRAM爆掉可能會有很多種非常莫名其妙的情況,在不同的工程上可能也會有不同的狀況。在我使用的工程中,需要使用兩個CAN外設:CAN1和CAN2介面來收發資料。這些資料的處理介面都是使用的非常成熟的庫來管理,之前從來沒有出現什麼問題。然而某一天我在給自己的程式碼新增功能的時候,除錯突然發現有一個CAN埠再也接收不到資料了,可是除錯發現一切函式都在正常的執行,就算直接查暫存器也是完全的一模一樣,可是CAN就是死活接收不到資料,把新加入的程式碼刪了吧,就可以正常執行,可是新加入的程式碼和CAN真的是一毛錢關係都沒有。

幸好我在幹活的時候用上了GIT,使用GIT進行二分定位,找到了第一個引入問題的版本,可是查了一下第一個問題版本所做的修改,也是基本和CAN沒有關係。在查了很久的BUG無果之後,我最終向BUG妥協,丟棄了新的改動,回退到了最後一個沒有問題的版本繼續開發。然而開發沒過多久就再一次出現了同樣的問題。再一次進行問題定位,引入問題的版本的修改僅僅修改了一個檔案,加了幾個函式和變數而已。這回問題範圍大大縮小了,我試圖把所有新加的函式都註釋掉,無果。但是當我把所有的變數都取消之後問題就解決了!!然後繼續縮小範圍,最終的導火線竟然是一個float型別的全域性變數的宣告!如果變數聲明瞭,CAN就借不到資料,如果變數沒有宣告,則CAN就能成功的接收到資料!確認了問題的產生的源頭,再通過不斷的實驗,我發現,當出問題的時候,Keil編譯器編譯成功後的ZI-data永遠保留在一個值,此時無論再宣告多少全域性變數,ZI-data都不再變化了。Keil的ZI-data是全域性變數的大小,在執行的時候是佔用SRAM的。作為全域性變數,怎麼可能這個時候申請多少float都不會增加ZI-data呢?這時候一個很合理的推理就出現了:SRAM不夠用了

。因為記憶體不夠用了,所以全域性變數就佔不了ZI-data的位置了,同時還有記憶體之間混亂的問題,因此就不能保證在哪個莫名其妙的地方你的資料被莫名其妙的改掉了。。。。因此如果看到ZI-data佔用的空間很大的時候而且不再隨變數的增加而增加的時候,那基本就是爆SRAM沒跑了。 不過我遇到的這個CAN2無法接收的這個問題是我的整個作業系統中一個比較小的位置。我覺得還有很多時候,SRAM已經爆掉了,但是系統還可以正常執行,這可能只是僥倖降臨,但是你也不知道它會在什麼時候,改掉你的什麼資料,也許這些資料帶來的損失是不可挽回的。。。。。。

本部落格就當做一個日記的方式記錄了。。因為這個問題能出現的情況很多,但是出現的原因又不一定是這個,可能也就只有我能遇到這種情況了,就算其他人遇到了這種情況,也不一定能找到這篇文章把。。。關鍵字如果能想到的話問題就很好解決了,關鍵字不知道的話根本無法形容這種問題