博客專欄

EEPW首頁(yè) > 博客 > 見鬼,過(guò)年回來(lái)后板子就 hardfault 了?

見鬼,過(guò)年回來(lái)后板子就 hardfault 了?

發(fā)布人:魚鷹談單片機(jī) 時(shí)間:2022-03-19 來(lái)源:工程師 發(fā)布文章

快一個(gè)月沒有更新了,回家之前給自己安排了很多任務(wù),然后回到家之后電腦就沒有打開過(guò),啥也沒干,不知道有多少人回家后的狀態(tài)和魚鷹是一樣的~~


回來(lái)之后,準(zhǔn)備搞個(gè)腳本,自動(dòng)讀取芯片 ID、修改頭文件 ID、自動(dòng)編譯、下載。


折騰了一晚上,讀取 ID 是搞定了,但是發(fā)現(xiàn)有個(gè)板子讀取 ID 后下載進(jìn)去發(fā)現(xiàn)直接 hardfault 了,可自己年前的時(shí)候明明代碼沒動(dòng)、板子沒動(dòng),年前都是沒問題的啊。


想不通,反正還有其他板子,直接換一塊,下載進(jìn)去,完全運(yùn)行正常。因?yàn)樘砹?,就暫時(shí)不管它。


第二天晚上,還是沒想明白,本想不管的,想想反正沒事情,不如深入研究一下,萬(wàn)一下次遇到這種問題,那不是很快就能定位了嘛。


第一步,打開錯(cuò)誤窗口(怎么打開的,自己看往期系列文章吧):

圖片

可以看出,總線錯(cuò)誤,IMPRECISERR 、STKERR 置位(下面的是 BKPT 是人為給出, FORCED 是因?yàn)楸緛?lái)是總線錯(cuò)誤,但因?yàn)闆]有開啟該中斷,直接上訪成了 Hardfault,所以真正來(lái)說(shuō),這次異常應(yīng)該由總線異常中斷處理的)。


突然想起年前好像也發(fā)生類似的事情,因?yàn)楫?dāng)時(shí)程序能正常運(yùn)行,換板子后不能運(yùn)行,立馬就想到了是芯片差異導(dǎo)致,改了代碼就好了;而現(xiàn)在時(shí)間過(guò)去太久,把這事情忘記了,就鬧了這一出(當(dāng)時(shí)解決問題太快,也沒深入研究,就沒有多少印象了)。


其實(shí)這種事情很多工程師估計(jì)都遇到過(guò),本來(lái)一個(gè)程序需要內(nèi)存 RAM 40 K,在一塊板子運(yùn)行的好好的,換一塊就不行,然后發(fā)現(xiàn)芯片實(shí)際只有 20K。


一般建工程選芯片型號(hào)的時(shí)候,就會(huì)規(guī)定好 ROM、RAM大小,只要能正常編譯通過(guò),問題都不大,但萬(wàn)一搞錯(cuò)了,就可能遇到魚鷹的情況了。

圖片


工程選擇 STM32F103RET6,實(shí)際芯片 STM32F103RCT6,內(nèi)存一個(gè) 64 K,一個(gè) 48K,偏偏我這個(gè)工程內(nèi)存用量接近滿了(如果 RAM 在 48  K 以內(nèi)即使下載了也是沒有問題的),程序也能正常下載,但運(yùn)行之后立刻 Hardfault 伺候。


很多人遇到這個(gè)錯(cuò)誤,束手無(wú)策,實(shí)際上掌握方法,并不是很難的事情。今天魚鷹教大家一步步排查定位這個(gè)錯(cuò)誤,大家遇到了其他錯(cuò)誤,也可以按魚鷹的思路解決。

首先,《權(quán)威指南》肯定要有,然后就是在線調(diào)試了。


從前面的錯(cuò)誤信息可以了解到這是一個(gè)總線錯(cuò)誤,但是我們看到地址這一欄,發(fā)現(xiàn)并不像有效地址(是否有效可以看 BFARVALID 是否置位),所以先不管它:

圖片


就看那兩個(gè)打鉤的位置啥意思了。看看《Cortex-M3 權(quán)威指南》咋說(shuō)的:

圖片


了解這些就差不多了。


此時(shí),我們就要通過(guò)在線調(diào)試的方式定位錯(cuò)誤代碼的位置了,畢竟上面的內(nèi)容只是給我們一個(gè)排查方向,但具體怎么解決還看代碼情況。


通過(guò)單步運(yùn)行(代碼量大的話,可以用二分法排查),并且追蹤到匯編級(jí)別的代碼發(fā)現(xiàn),在即將運(yùn)行下面代碼時(shí) LDR,[pc, #76],直接跳轉(zhuǎn)到了 Hardfault:



PUSH {r4,lr}   // 執(zhí)行完成LDR,[pc, #76]  // 未執(zhí)行

執(zhí)行 PUSH {r4,lr}  前,未報(bào)錯(cuò)(黃色光標(biāo)位置代表即將執(zhí)行但未執(zhí)行的代碼

圖片


執(zhí)行后報(bào)錯(cuò),但是還沒有運(yùn)行到 hard fault (單步調(diào)試,芯片可能還沒反應(yīng)過(guò)來(lái) -_-):

圖片


當(dāng)想單步執(zhí)行 LDR,[pc, #76] 時(shí),直接進(jìn)入了 Hardfault 中斷:

圖片


這樣問題就很明確了,PUSH {r4,lr}  執(zhí)行有問題,這個(gè)和前面從權(quán)威指南中得到的信息是一致的。


那么為什么壓棧操作會(huì)導(dǎo)致問題?


此時(shí)我們可以看左邊的寄存器,壓棧前 0x2000F338 ,壓棧后 0x2000F330。


如果對(duì)這個(gè)數(shù)據(jù)不敏感,可能不知道這個(gè)值超出了 48 K (49152,0xC000)范圍,沒那么快定位。


沒關(guān)系,我們可以繼續(xù)看右邊魚鷹給出的內(nèi)存窗口,壓榨后 0x2000F330 和 0x2000F334 的值應(yīng)該和 R4、LR 值一一對(duì)應(yīng),實(shí)際上并沒有(先減 4,再賦值,圖片打開后很清晰,認(rèn)真分析)。


于是很容易可以得出壓棧失敗的結(jié)論,進(jìn)而得出內(nèi)存訪問問題,從而發(fā)現(xiàn)芯片型號(hào)不對(duì)導(dǎo)致。


后面魚鷹又查了英文版《Cortex M3與M4權(quán)威指南.pdf》,更詳細(xì)了一些:

圖片

IMPRECISERR   bit 解釋了:訪問無(wú)效內(nèi)存空間。

圖片


如此一來(lái),hardfault 問題就順利解決了 ^_^ ^_^


工作時(shí)間久了,這種問題很容易遇到,那么我們的代碼是否能自動(dòng)根據(jù)某個(gè)寄存器來(lái)識(shí)別芯片型號(hào),從而確定大小,繼而拒絕運(yùn)行呢?


魚鷹發(fā)現(xiàn)在用 MDK 更新  ST-LINK 固件的時(shí)候,它居然知道我芯片型號(hào)的準(zhǔn)確容量大小(RAM 不行),從而拒絕下載,ST-LINK Utility 也是,就不知道它是通過(guò)讀取哪個(gè)寄存器得到這些信息的了,有知道的道友不如留言分享一下。


圖片


*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。

萬(wàn)能遙控器相關(guān)文章:萬(wàn)能遙控器代碼


波段開關(guān)相關(guān)文章:波段開關(guān)原理


電容式接近開關(guān)相關(guān)文章:電容式接近開關(guān)原理
電機(jī)保護(hù)器相關(guān)文章:電機(jī)保護(hù)器原理
接近開關(guān)相關(guān)文章:接近開關(guān)原理


關(guān)鍵詞: 單片機(jī)

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉