大戰STM32奇怪的hardfault,各種無厘頭的真凶!
題目起的非常的傻,可能是這幾天為了把這個問題調出來把人都給調廢了吧。。。反正現在找到了問題就特別的開心。
有時候我們在使用STM32進行開發的時候,有時會莫名其妙的進入hardfault,而有時又會出現明明暫存器配置完全一模一樣,程式原來都是好好的能跑的,可是自己改了一點其他無關緊要的東西的時候,整個程式的執行邏輯就不一樣的問題。。。當出現這種問題的時候,一般就屬於C語言和嵌入式結合所帶來的很難排查的問題了:
- 指標指飛了
- 棧空間堆爆了
- 堆空間堆爆了
- 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不夠用了
本部落格就當做一個日記的方式記錄了。。因為這個問題能出現的情況很多,但是出現的原因又不一定是這個,可能也就只有我能遇到這種情況了,就算其他人遇到了這種情況,也不一定能找到這篇文章把。。。關鍵字如果能想到的話問題就很好解決了,關鍵字不知道的話根本無法形容這種問題