嵌入式 HardFault原因定位

2021-10-24 05:39:22 字數 2578 閱讀 5688

4.hardfault除錯總結

在linux下出現程式跑飛時,如段錯誤(segment fault),往往可以借助coredump結合gdb快速定位引起段錯誤的程式。而在微控制器除錯時,發生類似段錯誤時會進入硬體錯誤hardfault,引發hardfault異常中斷,以stm32f4系列為例,當發生hardfault異常時會進入如下中斷服務函式,在除錯階段失能看門狗的情形下,將會進入死迴圈。

void hardfault_handler(void)

}

hardfault的主要誘因與段錯誤非常相似,總結大致如以下幾點:

1.陣列越界,記憶體溢位;

2.指標使用錯誤,如使用、釋放未申請的空間;

3.堆疊空間不足,在微控制器裡也就是可用ram空間不足;

明白了以上幾個誘因後,一方面在寫程式時要盡量避免以上錯誤。但常在河邊走哪有不濕鞋,一旦發生了hardfault,如何快速定位就顯得極為重要了。

某專案驗證階段,驅動spi時使用的官方hal庫函式,發現當程式執行1到2個小時後,會莫名進入hardfault中斷服務函式。

可以在其中斷服務函式中的while(1)上打斷點,當發生hardfault後,觀察call stack(函式呼叫棧)來觀察程式是如何一步步跑到hardfault裡的。一般情況下,通過觀察call stack就能夠定位到引發hardfault的程式語句了。以我的程式為例,發現進入hardfault前,上一條語句如下:

/* check if the spi is already enabled */

if((hspi->instance->cr1 & spi_cr1_spe) != spi_cr1_spe)

是hal_spi_transmitreceive函式裡的一句,看到這裡,基本就可以猜出是指標使用錯誤導致的了,問題一定在hspi->instance->cr1這句上,那麼hspi、instance、cr1,一定有乙個出了問題,此時需要慢慢排查。

通過觀察這幾個指標後,發現instance存在問題,instance為spi初始化時的spi裝置,如下所示:

void mx_spi1_init(void)

在初始化spi1時, hspi1.instance應為0x40013000,而發生hardfault時,其值變成了乙個亂七八糟的值。作為在ram中存放的hspi1結構體全域性變數,他裡邊的值instance發生了莫名其妙的改變,大概率發生了ram衝記憶體的現象。

一般情況下,在eeprom、flash中發生衝記憶體時,有可能是寫的時候長度越界,也有可能是寫位址錯誤。而在全域性ram中發生衝記憶體,十有**是操作存在hspi1前邊的全域性變數時發生了越界,導致把hspi1的記憶體給衝了。那麼如何知道ram中存在hspi1前邊的變數是什麼呢?這時就要map檔案出場了。

開啟編譯生成的map檔案,觀察各全域性變數在ram中的存放,以發現hspi1變數前存的是什麼,定位如下:

clrirq                  0x800'195f    0x12  code  gb  comm_exit_irq.o [1]

hspi1 0x2000'62fc 0x58 data gb spi.o [1]

hspi2 0x2000'6354 0x58 data gb spi.o [1]

hspi3 0x2000'63ac 0x58 data gb spi.o [1]

發現hspi1的前邊是名為errcheck的變數,存放位址為0x2000623c,占用長度為0xcc。那就去程式中檢查errcheck的相關操作,這次問題一眼看出來了——陣列越界。導致操作errcheck時一不留神操作到hspi1所在的記憶體區域了,導致instance指標存了個亂值,指向一片未申請的記憶體,那麼使用instance時必然會導致hardfault。

可以看到,除錯hardfault時主要步驟如下:

1.在hardfault中斷函式中打斷點;

2.檢視call stack定位跑飛前的語句;

3.分析有無陣列越界、記憶體溢位、指標誤操作的情況,並借助map檔案對記憶體進行分析,揪出真兇。

然而,存在一種情況,那就是跑到hardfault中斷函式裡的斷點時,檢視call stack時一片空白,這時如何定位跑飛前的語句呢?

這時就要用到cpu的sp暫存器,根據異常壓棧流程反推出lr暫存器,那麼lr對應的彙編指令就是跑飛前的程式。

以stm32f4為例,其基於cortex-m4核心。進入到hardfault中斷時,檢視堆疊指標sp,然後根據《cortex-m3/m4權威指南》,得出異常壓棧順序為r0、r1、r2、r3、r12、lr。此時sp暫存器中存的位址指向棧頂r0,那麼將sp暫存器中的位址加5*4=20,即為lr暫存器的位址,在memory視窗中檢視此位址存的值,即為hardfault前的語句位址0x8000282,到彙編視窗中即可檢視相應的彙編指令,以及對應的c語言語句。

初識嵌入式 嵌入式開發概述

1 什麼是嵌入式技術 1 嵌入式軟體與非嵌入式軟體的區別?答 嵌入式軟體是結合作業系統之上做的開發 非嵌入式軟體是做的裸機開發。裸機 沒有作業系統 2 嵌入式開發與微控制器開發的區別?答 區別 是否有作業系統。拓展 答 優點 解決了軟體的移植性 解決了開發人員的能力的劃分問題。提供了豐富的網路協議 ...

嵌入式開發 程式跑飛原因總結

在嵌入式軟體開發中,程式跑飛是乙個比較棘手的問題。為什麼說棘手,那是因為當程式跑飛時,往往沒有任何錯誤資訊報出來,log停止的地方通常也不是出現問題的地方,因此這讓我們很難定位問題。基於以上原因,我將嵌入式開發中一些常見的程式跑飛原因以及相關解決方案記錄在這篇部落格下。1.棧溢位 說明 這可能是最常...

如何學習嵌入式 嵌入式如何入門?

學習嵌入式,該學習什麼基本的知識呢?嵌入式如何入門?其次,應該對作業系統有所了解,這對你對硬體和軟體的理解,絕對有很大的幫助。應該把系統的管理理解一下,比如程序 執行緒,系統如何來分配資源的,系統如何來管理硬體的,當然,不是看書就能把這些理解透,如果不是一時能理解,沒關係,多看看,結合以後的專案經驗...