01
前言
在嵌入式軟件開發(fā)中,因為代碼質(zhì)量不佳、線程沖突、棧溢出等問題,會造成Arm的HardFault。這種異常通常存在偶發(fā)性、不確定性、復現(xiàn)困難的特點,同時復現(xiàn)后軟件已經(jīng)跑飛,程序在何處異常、異常時的臨時變量環(huán)境等都不好查找。在開發(fā)中出現(xiàn)此問題后往往意味著長時間的復現(xiàn)問題并debug,常常陷入毫無頭緒的排查,耗費了不少程序員的頭發(fā)?,F(xiàn)總結了一些處理這類問題的經(jīng)驗以共享。
02
串口打印跟蹤
在代碼中插入串口打印,看死機時輸出的最后一個串口信息在哪里。但是從代碼里串口輸出到硬件打印出數(shù)據(jù),有一定延遲。出錯的代碼在最后輸出的串口后邊,無法確切定位。找到大概出錯范圍后根據(jù)經(jīng)驗驗證代碼,看有沒有明顯錯誤的地方。
03
仿真器追蹤
在串口查找死機耗時大于兩個小時的時候有必要使用仿真器追蹤。
在代碼中插入一個全局變量,每一個段給全局變量賦值。在中斷的void HardFault_Handler(void)函數(shù)中設置斷點。死機時進入斷點查看全局變量的數(shù)值確定死機位置。
另外死機是可以view->call stack 中看到出錯時調(diào)用的函數(shù),以及函數(shù)中局部變量的值,通過這些信息推斷出錯原因。
04
通過堆棧查找最后一條語句
在中斷HardFault_Handler中打上斷點,程序跑飛后會停在此處:
在Registers里面找到R14(LR)的值。
在memory里面查找MSP的值:0x20008828,然后在對應的行里面找到地址:
在Disassembly里面右鍵選擇Show Code at Address。搜索剛才得到的地址,就能找相對應的代碼。這里的代碼就是在進入循環(huán)中斷之前的時候的情況,仔細查看這部分函數(shù)被調(diào)用或者數(shù)組內(nèi)存使用情況。
05
避免問題
除零。
例如:
N = 0;Sum = 0;a;i < b;i ++) = { Sum += x[i]; N ++;}Sum /= N;
當a>b的時候,N為0,出錯。
建議:在每個除法前都判斷被除數(shù)是否為0。
if(N > 0){ Sum /= N;}
數(shù)據(jù)越界。
例如:
U8 x[100];N = 0;Sum = 0;和b由上文計算得出 非常量 a;i < b;i ++) = { Sum += x[i]; N ++;}
當b > 100時,數(shù)組越界。
建議:在調(diào)用數(shù)組前判斷是否在數(shù)組范圍內(nèi)。
for(i = a;i < b;i ++){ if(b < 100) { Sum += x[i]; N ++; }}
被減數(shù)小于減數(shù)導致的越界。
U16 a,b,c;U8 x[100];a = b - c;//調(diào)用x[a]。當b
建議: 1. 減法判斷減數(shù)與被減數(shù)大小
2. 在調(diào)用數(shù)組前判斷是否在數(shù)組范圍內(nèi)。
棧溢出。
函數(shù)中的局部變量數(shù)組太大,超過了棧的大小。
建議:在大的局部變量前增加Static或者把局部變量改為全局變量。
中斷與循環(huán)沖突。
中斷與循環(huán)中同時寫一個變量。程序設計時避免此寫法。
任務沖突。
多個任務同時寫入同一個變量 沖突。程序設計時避免此寫法。
免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!