0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

FreeRTOS中如何定位HardFault?

麥克泰技術(shù) ? 來(lái)源:麥克泰技術(shù) ? 作者:麥克泰技術(shù) ? 2022-11-29 14:30 ? 次閱讀

今天繼續(xù)聊聊開發(fā)中常見(jiàn)的 HardFault,這個(gè)問(wèn)題應(yīng)該從學(xué)習(xí) STM32 開發(fā)以來(lái)就一直伴隨著我們,很多人遇到這種問(wèn)題也是不知道該如何定位。

如果只是獨(dú)立開發(fā),遇到這種問(wèn)題,一般都是看代碼、修改代碼等等這些常規(guī)手段,因?yàn)樽约簩懙拇a最熟悉,改動(dòng)一般也不會(huì)太大,容易縮小范圍,也更容易定位。

但現(xiàn)在的產(chǎn)品越來(lái)越復(fù)雜,目前的開發(fā)模式都是合作開發(fā),每個(gè)人負(fù)責(zé)各自的模塊,這樣的項(xiàng)目代碼量大、復(fù)雜度高,也就更難定位問(wèn)題。

而有的時(shí)候,剛?cè)肼氁患?a target="_blank">公司,什么代碼都不熟悉,又出現(xiàn)了 HardFault,更是讓人崩潰,分分鐘有跑路的沖動(dòng)(你和代碼,有一個(gè)能跑就行)。

此時(shí),有一個(gè)能解決這種疑難雜癥的大牛是能大大節(jié)省時(shí)間的,而我在公司也解決不少類似的問(wèn)題,所以經(jīng)驗(yàn)也算豐富,充當(dāng)?shù)囊彩沁@一類角色。

而魚鷹定位 Hardfault 的方法一般是靠 KEIL在線調(diào)試+C語(yǔ)言+權(quán)威指南中的知識(shí)搞定。

目前魚鷹的解 BUG 差不多是這樣的:

1、必現(xiàn),代碼熟悉的情況下,幾個(gè)小時(shí)內(nèi)搞定。

2、偶現(xiàn),根據(jù)出現(xiàn)情況決定解決問(wèn)題的時(shí)間,一般出現(xiàn)個(gè)四五次,基本就能定位。

3、難現(xiàn)。這種一般要掛一個(gè)記錄儀實(shí)時(shí)記錄運(yùn)行情況。

經(jīng)歷了這么多,已經(jīng)很少有能讓魚鷹需要花費(fèi)幾天時(shí)間才能解決的 Hardfault 問(wèn)題了(猶記得剛來(lái)深圳時(shí),因?yàn)閯e人寫的一個(gè) BUG 導(dǎo)致的 Hardfault,不得已加了幾天通宵,要不是偶然機(jī)會(huì)還不一定能搞定)。

這里打個(gè)小廣告,如果難解決,可以有償請(qǐng)魚鷹解決 Hardfault 問(wèn)題哦。

不過(guò)最近工作上因?yàn)橛昧?C++,這個(gè)基礎(chǔ)不是很熟悉,解決 Hardfault 的速度又下降了。而工程編譯優(yōu)化等級(jí) -O2 也加大了不少調(diào)試難度,因此掌握下面的方法是很重要的:

總結(jié) MDK 幾種編譯優(yōu)化設(shè)置的方法

關(guān)于 Hardfault,魚鷹以前也是分享了不少筆記的,不知道有多少人認(rèn)真看過(guò)。

HardFault 之 INVSTAE 錯(cuò)誤定位(一)

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

今天,魚鷹繼續(xù)分享關(guān)于在 FreeRTOS 定位 Hardfault 方法。

這里需要一個(gè)大佬寫的組件 :CmBacktrace(事實(shí)上,如果能在線調(diào)試,魚鷹是不需要借助這個(gè)組件的,但是難復(fù)現(xiàn)的情況下用這個(gè)組件還是比較香的)。

gitee 倉(cāng)庫(kù)https://gitee.com/Armink/CmBacktrace

這個(gè)組件估計(jì)很多道友都聽說(shuō)過(guò),也用過(guò),但魚鷹想說(shuō)的是,有些道友在用的組件可能比較老,沒(méi)有下面這種追蹤功能,建議大家更新一下。

61daf8a8-6fa0-11ed-8abf-dac502259ad0.png

上面可以看到出錯(cuò)時(shí),函數(shù)的調(diào)用棧(有時(shí)可能是錯(cuò)誤的,需要實(shí)際分析,僅做參考)

_call_main ->  main -> fult_test_by_div0

相當(dāng)實(shí)用。

同時(shí),本篇筆記不僅適用于在 FreeRTOS 定位 Hardfault,實(shí)際上uCOSrt-thread 等其它 RTOS 照樣可以修改后使用(裸機(jī)更不用說(shuō)了)。

倉(cāng)庫(kù)例子支持的平臺(tái):裸機(jī)、rt-thread、ucoss-ii、freertos。

這里重點(diǎn)在如何移植這個(gè)組件到freertos 中(實(shí)際上,倉(cāng)庫(kù)的說(shuō)明文檔也非常詳細(xì),可以參考)。由于freertos 也是不斷更新中,所以這個(gè)組件的例子不能完全適用于新版本,而魚鷹剛好移植好了,在此記錄一下,方便大家移植。

1、將倉(cāng)庫(kù)中的 cm_backtrace(源碼文件)整個(gè)文件夾拷貝到自己的工程文件夾下。

61fddfee-6fa0-11ed-8abf-dac502259ad0.png

2、在自己的工程中添加這些文件(我們可以打開 demos -> os -> freertos 工程查看)

62210834-6fa0-11ed-8abf-dac502259ad0.png

只有兩個(gè)文件,相當(dāng)簡(jiǎn)單。

一個(gè)是核心源碼,另外一個(gè)則是匯編代碼,代碼執(zhí)行入口。

注意,根據(jù) IDE 不同,選擇的匯編文件也不同:

623a3d72-6fa0-11ed-8abf-dac502259ad0.png

其實(shí)就是將 startup_stm32f10x_hd.s 中的hardfault 默認(rèn)處理函數(shù)重定位到 cmb_fault.S 中了。

62595ff4-6fa0-11ed-8abf-dac502259ad0.png

注意這里有一個(gè)weak,這樣鏈接的時(shí)候就不會(huì)鏈接這個(gè),而是cmb_fault.S這個(gè):

62736502-6fa0-11ed-8abf-dac502259ad0.png

為了更方便的定位問(wèn)題,我們后面還需要修改一下這個(gè)代碼才行。

注意,如果你的啟動(dòng)文件內(nèi)的 hardfault 代碼被修改了,而你不懂匯編,建議恢復(fù)成上面那種,不然可能運(yùn)行不正常。

3、主函數(shù)中初始化代碼。

62941478-6fa0-11ed-8abf-dac502259ad0.png

這里的字符串需要和這個(gè)一樣(根據(jù)自己的工程名修改):

62a71672-6fa0-11ed-8abf-dac502259ad0.png

所以建議用英文建工程。這個(gè)在輸出錯(cuò)誤信息的時(shí)候用的上,否則每次查看調(diào)用棧都需要修改一下,比較麻煩。

如果開啟了內(nèi)部看門狗,建議關(guān)閉一下:

//HAL 庫(kù)
__HAL_DBGMCU_FREEZE_IWDG1();
//標(biāo)準(zhǔn)庫(kù)
DBGMCU_Config(DBGMCU_IWDG_STOP, ENABLE);

在斷言失敗的位置添加該函數(shù) cm_backtrace_assert:

62bb7928-6fa0-11ed-8abf-dac502259ad0.png

這樣斷言失敗了也能看到調(diào)用棧了。

4、FreeROTS內(nèi)核文件修改(內(nèi)核版本 V10.2.1)

為了分析出錯(cuò)的代碼,必須知道每個(gè)任務(wù)的棧信息,而 FreeRTOS 可能沒(méi)有這些信息,因此,我們需要添加進(jìn)去。

task.c

62db59be-6fa0-11ed-8abf-dac502259ad0.png

FreeRTOS.h

6303c084-6fa0-11ed-8abf-dac502259ad0.png

注意,老版本freertos 是只要修改一處的,但新版本需要修改兩處,否則會(huì)斷言失敗,運(yùn)行不下去。

建議把注釋也一起添加進(jìn)去。

UBaseType_t     uxSizeOfStack;      /*< Support For CmBacktrace >*/

相關(guān)函數(shù)修改 task.c prvInitialiseNewTask():

63324f08-6fa0-11ed-8abf-dac502259ad0.png

task.c 文件最后添加如下代碼用于獲取棧地址、大小、名字:

63585766-6fa0-11ed-8abf-dac502259ad0.png

為方便復(fù)制,在此貼代碼

/*-----------------------------------------------------------*/
/*< Support For CmBacktrace >*/
uint32_t * vTaskStackAddr()
{
    return pxCurrentTCB->pxStack;
}


uint32_t vTaskStackSize()
{
    #if ( portSTACK_GROWTH > 0 )
    
    return (pxNewTCB->pxEndOfStack - pxNewTCB->pxStack + 1);
    
    #else /* ( portSTACK_GROWTH > 0 )*/
    
    return pxCurrentTCB->uxSizeOfStack;
    
    #endif /* ( portSTACK_GROWTH > 0 )*/
}


char * vTaskName()
{
    return pxCurrentTCB->pcTaskName;
}
/*-----------------------------------------------------------*/

5、根據(jù)所屬 RTOS 平臺(tái)和芯片內(nèi)核修改組件配置信息

cmb_cfg.h

6378da40-6fa0-11ed-8abf-dac502259ad0.png

1)需要定義打印輸出函數(shù),一般用 printf 打印,也可以用你自定義的一些打印函數(shù),功能和 printf 類似即可。

#define cmb_println(...)               printf(__VA_ARGS__);printf("
")

2)使能 RTOS 支持

#define CMB_USING_OS_PLATFORM

3)具體 RTOS 選擇FreeRTOS

#define CMB_OS_PLATFORM_TYPE           CMB_OS_PLATFORM_FREERTOS

4)芯片內(nèi)核根據(jù)實(shí)際選擇,目前支持 M0、M3、M4、M7。

#define CMB_CPU_PLATFORM_TYPE          CMB_CPU_ARM_CORTEX_M3

5)打印虛擬棧,可以將出錯(cuò)時(shí)的原始棧信息打印出來(lái),可能對(duì)分析有些幫助

#define CMB_USING_DUMP_STACK_INFO

6)語(yǔ)言支持:英語(yǔ)。實(shí)際也支持中文,但建議使用英語(yǔ)(不配置,默認(rèn)就是英語(yǔ))

#define CMB_PRINT_LANGUAGE             CMB_PRINT_LANGUAGE_ENGLISH

7)如果是 C++ 編譯的,有可能出錯(cuò),可以在開頭定義這個(gè):

#define__CLANG_ARM

7、根據(jù)需要修改組件,方便使用(這些看看能不能有機(jī)會(huì)合并到大佬的分支里面)

1)因?yàn)楣δ苌婕胺秶?,因此可以將相關(guān)頭文件包含形式改成這種,這樣就不需要改頭文件路徑了,移植更方便:

#include 
-->>
#include"./cm_backtrace.h"


#include 
-->>
#include "./cmb_cfg.h"


#include "cmb_def.h"
-->>
#include "./cmb_def.h"

main 中也不需要包含頭文件,而是在需要位置直接聲明這個(gè)函數(shù)即可,因?yàn)橥獠恐恍枰{(diào)用這個(gè)函數(shù)

#include 
-->
void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver);

這樣一來(lái),就不需要添加頭文件的路徑了。

或者使用相對(duì)路徑的方式添加頭文件:

#include "../../driver/cm_backtrace/cm_backtrace.h"

另外,我們可以讓程序進(jìn)入 Hardfault 前,讓代碼自動(dòng)停止,這樣我們能更好的利用在線調(diào)試代碼,《傳說(shuō)中的軟件斷點(diǎn)到底是什么?。

HardFault_Handler    PROC
    LDR     r0, =0xE000EDF0; DEMCR
    LDR     r0,[r0,#0x00]
    AND     r0,r0,#0x00000001
    CBZ     r0,not_in_debug
    BKPT    0
not_in_debug
    MOV     r0, lr                  ; get lr
    MOV     r1, sp                  ; get stack pointer (current is MSP)
    BL      cm_backtrace_fault

因?yàn)閯傔M(jìn)入 Hardfault 時(shí)的信息最全,又不想每次打斷點(diǎn),上面的代碼很好的實(shí)現(xiàn)了功能,同時(shí)也不會(huì)影響程序的正常運(yùn)行(會(huì)自動(dòng)判斷是否處于調(diào)試模式)。

8、實(shí)驗(yàn)。

上面都搞定了,就可以驗(yàn)證一下效果了。這里我們我們可以模擬仿真看看情況。(修改工程配置,這些內(nèi)容魚鷹以前分享過(guò),不多說(shuō))

639ec7f0-6fa0-11ed-8abf-dac502259ad0.png

運(yùn)行倉(cāng)庫(kù)例子后,應(yīng)該能打印下面的信息,告訴我們出現(xiàn)了 div 0 錯(cuò)誤

63cb7908-6fa0-11ed-8abf-dac502259ad0.png

而你移植好的工程也應(yīng)該打印類似的信息(加入測(cè)試代碼 :fault_test_by_div0();)如果打印不出來(lái),有兩種可能:

1、打印函數(shù)沒(méi)初始化好就進(jìn)入了Hardfault

2、打印函數(shù)有問(wèn)題。

63e46c9c-6fa0-11ed-8abf-dac502259ad0.png

之后我們復(fù)制最后一行,然后運(yùn)行倉(cāng)庫(kù) tools 里面的 add2line 工具看看調(diào)用棧信息:

63fc89ee-6fa0-11ed-8abf-dac502259ad0.png

在 git bash 中可能會(huì)執(zhí)行失敗,可以加入程序路徑,當(dāng)然也可以將該工具路徑加入到Windows 環(huán)境變量中。有可能提示找不到 axf 文件,把這個(gè)文件拷貝到工具下即可。

正確的做法是,將該工具放到 C 盤目錄下,同時(shí)添加環(huán)境變量,之后就可以在 axf 目錄下打開 gitbash 或者 cmd 窗口執(zhí)行命令即可。

這里只作為演示,就不多介紹這些了。

最后再簡(jiǎn)單介紹一下這個(gè)組件的實(shí)現(xiàn)原理:

如果出現(xiàn)hardfault, 首先進(jìn)入?yún)R編文件的 HardFault_Handler處理,這里會(huì)得到當(dāng)前的棧指針和 LR,并且根據(jù) LR 確定出錯(cuò)的棧是哪個(gè)《STM32 兩個(gè)棧,你用哪一個(gè)?》(這里是 PSP 棧)

根據(jù)錯(cuò)誤寄存器信息,確定哪種錯(cuò)誤(這里為除 0 錯(cuò)誤

然后對(duì)棧信息 和 LR 、PC 進(jìn)行 FLASH 上的匯編代碼分析,找出可能的跳轉(zhuǎn)指令,這里找到的兩個(gè)跳轉(zhuǎn)地址為 0x08001f96 0x08000368,進(jìn)而得到調(diào)用棧。

因此,要能準(zhǔn)確的得到調(diào)用棧,有兩點(diǎn)重要前提條件(建議優(yōu)化等級(jí) -O0):

1、棧未被破壞

2、芯片運(yùn)行代碼和 axf 文件保持一致。

即使如此,你也不能保證找出的調(diào)用棧就是正確的,比如你使用 fault_test_by_unalign() 測(cè)試,得到的結(jié)果如下:

641fe20e-6fa0-11ed-8abf-dac502259ad0.png

中間多了一個(gè) fputc。

因此,這些打印信息只能作為參考使用。

但在線調(diào)試不同,它更專業(yè),不容易出現(xiàn)錯(cuò)誤調(diào)用關(guān)系。

6440fd2c-6fa0-11ed-8abf-dac502259ad0.png

魚鷹想分享的內(nèi)容到此就結(jié)束了,下期再見(jiàn)!

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7614

    瀏覽量

    137505
  • FreeRTOS
    +關(guān)注

    關(guān)注

    12

    文章

    484

    瀏覽量

    62343

原文標(biāo)題:FreeRTOS 中如何定位 HardFault?

文章出處:【微信號(hào):麥克泰技術(shù),微信公眾號(hào):麥克泰技術(shù)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    freertos最多支持多少個(gè)任務(wù)

    FreeRTOS是一個(gè)輕量級(jí)的實(shí)時(shí)操作系統(tǒng)(RTOS),其設(shè)計(jì)初衷就是為了提供簡(jiǎn)單、可靠且高效的實(shí)時(shí)任務(wù)管理。關(guān)于FreeRTOS最多支持多少個(gè)任務(wù)的問(wèn)題,實(shí)際上并沒(méi)有一個(gè)固定的上限,這主要取決于
    的頭像 發(fā)表于 09-02 14:21 ?1152次閱讀

    STM32U5退出stop2模式后進(jìn)入HardFault_Hand的原因?

    HardFault_Handler,但是連接stlink開啟調(diào)試下,程序能連續(xù)進(jìn)入和退出stop2模式,有無(wú)大佬了解該問(wèn)題或者該如何定位問(wèn)題?
    發(fā)表于 07-24 06:25

    使用rt_thread_mdelay函數(shù)后出現(xiàn)hardfault的原因?

    問(wèn)題:在一個(gè)線程中共有前后2部分使用rt_thread_mdelay()進(jìn)行延時(shí)等待,前面部分延時(shí)是正常的,后面部分進(jìn)入rt_thread_mdelay()函數(shù)后立馬打印hardfault錯(cuò)誤,定位
    發(fā)表于 07-16 07:07

    HPM SDK 1.6.0 FreeRTOS LTS更改及適配指南

    1、HPM_SDKFreeRTOSLTS特性總覽HPMSDKV1.6.0FreeRTOS升級(jí)前后特性支持對(duì)比:特性V10.4.4LTS202210.01斷搶占√√RISCV浮點(diǎn)擴(kuò)展支持
    的頭像 發(fā)表于 07-06 08:17 ?3985次閱讀
    HPM SDK 1.6.0 <b class='flag-5'>FreeRTOS</b> LTS更改及適配指南

    STM32H743怎么在FreeRTOS移植canopen?

    STM32H743怎么在FreeRTOS移植canopen?
    發(fā)表于 07-03 06:32

    STM32H743IIT6在SystemInit跳轉(zhuǎn)到HardFault_Handler函數(shù)里面,為什么?

    每當(dāng)運(yùn)行到這個(gè)地方就會(huì)跳轉(zhuǎn)到HardFault_Handler函數(shù)里面 這個(gè)是調(diào)試的界面
    發(fā)表于 05-23 07:32

    運(yùn)行ble_hello_sensor時(shí)出現(xiàn)了HardFault_Handler,為什么?

    當(dāng)我運(yùn)行 ble_hello_sensor 時(shí),出現(xiàn)了 HardFault_Handler。 我認(rèn)為 cy_rtos_create_thread(cybt_platform_task.c) 用于
    發(fā)表于 05-21 07:35

    FOC 4.2調(diào)試進(jìn)入HardFault_Handler(void)的原因?

    ( PWMnCurrFdbkParamsM2,R3_DDParamsM2); 這條命令死掉,強(qiáng)迫停止后,發(fā)現(xiàn)進(jìn)入了HardFault_Handler(void)命令段。感覺(jué)似乎硬件配置方面有問(wèn)題,大神們給解釋下,有配置成功的嗎
    發(fā)表于 05-11 06:25

    淺析FreeRTOS任務(wù)調(diào)度器的三種調(diào)度算法和應(yīng)用

    FreeRTOS在MCU領(lǐng)域應(yīng)用非常廣泛,今天就給大家講解一下FreeRTOS調(diào)度器的三種調(diào)度算法,以及在瑞薩RZ/T2L MPU的應(yīng)用。
    的頭像 發(fā)表于 05-10 14:02 ?7791次閱讀
    淺析<b class='flag-5'>FreeRTOS</b>任務(wù)調(diào)度器的三種調(diào)度算法和應(yīng)用

    STM32程序運(yùn)行時(shí)會(huì)莫名的進(jìn)入HardFault硬件中斷,為什么?

    程序運(yùn)行時(shí)會(huì)莫名的進(jìn)入HardFault硬件中斷,嘗試了一周的時(shí)間,試過(guò)以下方法始終不能找到問(wèn)題出在哪里,希望有人能指導(dǎo)下: 1.換硬件,依然出現(xiàn),可以排除硬件自身原因; 2.在代碼中加入nop
    發(fā)表于 04-10 06:29

    STM32H750+STEMWIN+FreeRTOS調(diào)用繪圖函數(shù)繪制位圖進(jìn)入HardFault的原因?

    如題,在工程需要調(diào)用GUI_DrawBitmap()、GUI_DrawBitmapEx()等函數(shù)繪制圖片,當(dāng)位圖尺寸小的時(shí)候可以正常顯示,但是位圖尺寸超過(guò)一定尺寸就進(jìn)入HardFault故障(這里
    發(fā)表于 04-10 06:29

    h750+STEMWIN+FreeRTOS調(diào)用繪圖函數(shù)繪制位圖進(jìn)入HardFault的原因?

    如題,在工程需要調(diào)用GUI_DrawBitmap()、GUI_DrawBitmapEx()等函數(shù)繪制圖片,當(dāng)位圖尺寸小的時(shí)候可以正常顯示,但是位圖尺寸超過(guò)一定尺寸就進(jìn)入HardFault故障(這里
    發(fā)表于 04-09 07:09

    STM32F7使用FreeRTOS,程序運(yùn)行一段時(shí)間后進(jìn)入HardFault_Handler的原因?

    大家好,最近學(xué)習(xí)在STM32F7上使用FreeRTOS,程序運(yùn)行一段時(shí)間后進(jìn)入HardFault_Handler,該時(shí)間不定。故障分析器給的報(bào)錯(cuò)信息為“總線,存儲(chǔ)器管理或使用失?。‵ORCED
    發(fā)表于 04-08 07:23

    CUBEMX為什么找不到FreeRTOS的選項(xiàng)?

    請(qǐng)教大神,CUBEMX 怎么找不到 FreeRTOS的選項(xiàng),需要怎么安裝
    發(fā)表于 03-25 06:23

    使用CUBEMX6.9.2,LWIP 2.1.2配置LWEIP,使用FREERTOS后,一開始運(yùn)行任務(wù)就進(jìn)入了HardFault異常的原因?

    使用CUBEMX6.9.2,LWIP 2.1.2配置LWEIP,裸機(jī)運(yùn)行正常 使用FREERTOS后,一開始運(yùn)行任務(wù)就進(jìn)入了HardFault異常 請(qǐng)問(wèn)有遇到類似問(wèn)題的同學(xué)嗎?謝謝
    發(fā)表于 03-12 06:26