1. Cortex-M0 處理器內(nèi)核異常中斷簡介
在Cortex‐M0內(nèi)核上搭載了一個異常響應(yīng)系統(tǒng),支持眾多的系統(tǒng)異常和外部中斷。其中,編號為1-15的對應(yīng)系統(tǒng)異常,大于等于16的則全是外部中斷,優(yōu)先級的數(shù)值越小,則優(yōu)先級越高。除了個別異常的優(yōu)先級被定死外,其它異常的優(yōu)先級都是可編程的。
因為芯片設(shè)計可以修改內(nèi)核的硬件描述源代碼,所以做成芯片后,支持的中斷源數(shù)目常常不到240 個,并且優(yōu)先級的位數(shù)也由芯片廠商最終決定。
類型編號為 1-15 對應(yīng)系統(tǒng)異常,在《ARM Cortex-M0權(quán)威指南》一書中的第12章節(jié)<錯誤處理>章節(jié)中有描述:對于ARM處理器,架構(gòu)采用錯誤異常的機制來檢測問題,當(dāng)一個程序產(chǎn)生了錯誤并且被處理器檢測到時,異常中斷會被觸發(fā),并且核心會跳轉(zhuǎn)到相應(yīng)的異常終端處理函數(shù)執(zhí)行,錯誤異常的中斷有如下:
Reset
在上下電、NRST拉低、看門狗復(fù)位或軟復(fù)位時啟動復(fù)位。當(dāng)復(fù)位產(chǎn)生時,處理器停止一切操作,并將復(fù)位當(dāng)做一種特殊形式的異常來執(zhí)行,進入到對應(yīng)的中斷函數(shù)。當(dāng)復(fù)位撤銷時,從向量表中復(fù)位項提供的地址處重新啟動執(zhí)行,芯片重新開始執(zhí)行。
NMI
不可屏蔽中斷(NMI),可以由外設(shè)產(chǎn)生,也可以由軟件來觸發(fā)。這是除復(fù)位之外優(yōu)先級最高的異常中斷,NMI永遠使能,優(yōu)先級固定為-2,CSS的時鐘安全機制使能判定時鐘失效后就會進入到該中斷。NMI 不能:
1、被屏蔽,它的執(zhí)行也不能被其他任何異常中止;
2、被除復(fù)位之外的任何異常搶占。
HardFault
HardFault 是由于在正常操作過程中或在異常處理過程中出現(xiàn)錯誤而出現(xiàn)的一個異常。HardFault的優(yōu)先級固定為-1,表明它的優(yōu)先級要高于任何優(yōu)先級可配置的異常。
SVCall
管理程序調(diào)用(SVC)異常是一個由SVC指令觸發(fā)的異常。在OS環(huán)境下,應(yīng)用程序可以使用 SVC指令來訪問OS內(nèi)核函數(shù)和器件驅(qū)動。
PendSV
PendSV是一個中斷驅(qū)動的系統(tǒng)級服務(wù)請求。在OS環(huán)境下,當(dāng)沒有其它異常有效時,使用 PendSV 來進行任務(wù)切換。
SysTick
SysTick是一個系統(tǒng)定時器到達零時產(chǎn)生的異常,軟件也可以產(chǎn)生一個SysTick異常。在OS環(huán)境下,處理器可以將這個異常用作系統(tǒng)節(jié)拍。
中斷(IRQ)
中斷(或 IRQ)是外設(shè)發(fā)出的一個異常,或者由軟件請求產(chǎn)生的一個異常。在系統(tǒng)中,外設(shè)使用中斷來與處理器通信,在中斷函數(shù)中可以查詢和清除標(biāo)志操作。
2. HardFault異常
HardFault (硬件錯誤,也有譯為硬錯誤)是在MCU上編寫程序中所產(chǎn)生的錯誤,硬件錯誤處理幾乎是最高優(yōu)先級,它的優(yōu)先級為-1,只有復(fù)位和不可屏蔽中斷(NMI)可以對其進行搶占。當(dāng)它發(fā)生時,表示處理器出現(xiàn)了問題,需要采取緊急修復(fù)措施。
造成HardFault錯誤的可能原因較多,如何在代碼量較大的情況下,快速定位造成的HardFault的問題代碼,就成為比較關(guān)鍵的問題。
本文將以MM32F0130系列MCU為例,Keil-MDK開發(fā)環(huán)境,總結(jié)HardFault的調(diào)試、定位方法。在其它Cortex-M0 (M3,M4)內(nèi)核處理器,和其它開發(fā)環(huán)境下,也可作為參考。
2.1 可能的原因
《ARM Cortex-M0權(quán)威指南》中提到,關(guān)于 Cortex M0內(nèi)核主要有以下幾點引起HardFault的原因:
-
非法存儲器訪問
-
非對齊數(shù)據(jù)訪問
-
從總線返回錯誤
-
異常處理中的棧被破壞
-
程序在某些 C 函數(shù)中崩潰
-
意外地試圖切換至 ARM 狀態(tài)
-
在錯誤的優(yōu)先級上執(zhí)行系統(tǒng)服務(wù)調(diào)用指令(SVC)
-
數(shù)組越界
-
野指針
-
未初始化硬件卻開始操作,或無中斷服務(wù)函數(shù)等
-
任務(wù)堆棧溢出
-
中斷服務(wù)函數(shù)設(shè)置錯誤
-
時鐘異常
2.2 可能出現(xiàn)的異常
如果在執(zhí)行NMI或HardFault處理程序時,或者在一個使用MSP的異常返回時出棧的卻是PSR的時候系統(tǒng)產(chǎn)生一個總線錯誤,處理器進入一個鎖定狀態(tài)。當(dāng)處理器處于鎖定狀態(tài)時,它不執(zhí)行任何指令。處理器保持處于鎖定狀態(tài),直到下面任何一種情況出現(xiàn):
-
出現(xiàn)復(fù)位
-
調(diào)試器將鎖定狀態(tài)終止,出現(xiàn)中止仿真的現(xiàn)象
-
出現(xiàn)一個NMI,以及當(dāng)前的鎖定處于HardFault處理程序中
voidHardFault_Handler(void)
{/*GotoinfiniteloopwhenHardFaultexceptionoccurs*/
while(1)
{
}
}
下面將在MM32F0130上運行的數(shù)組越界代碼為例,具體闡述定位步驟:
voidStackTest(void)
{intdata[3],i;
for(i=0;i<10000;?i++)
????{
????data[i]=1;
????}
}
3. 查找HardFault方法和步驟
實際環(huán)境中,由于測試高壓等產(chǎn)品常常無法連接調(diào)試器,故需要代碼來定位目標(biāo)語句地址,并通過一定手段保存:
在MM32F0130中,需先修改啟動文件startup\_mm32f013x.s:
HardFault_Handler
PROC
IMPORThard_fault_handler_c;函數(shù)聲明
MOVSr0,#4;判斷主棧指針還是進程棧指針
MOVr1,LR
TSTr0,r1
BEQstacking_used_MSP;如果是主棧指針
MRSR0,PSP;否則是進程棧指針,把進程棧指針地址付給R0
Bget_LR_and_branch;跳轉(zhuǎn)到HardFault中斷程序
stacking_used_MSP
MRSR0,MSP;把主棧指針地址賦給R0
get_LR_and_branch
MOVR1,LR
BLhard_fault_handler_c
ENDP
該段代碼會判斷當(dāng)前堆棧使用的是MSP或PSP,然后將堆棧參數(shù)傳遞給hard\_fault\_handler\_c函數(shù),該函數(shù)定義如下:
voidhard_fault_handler_c(unsignedint*hardfault_args,unsignedlr_value)
{unsignedintstacked_r0;//壓棧的r0
unsignedintstacked_r1;//壓棧的r1
unsignedintstacked_r2;//壓棧的r2
unsignedintstacked_r3;//壓棧的r3
unsignedintstacked_r12;//壓棧的r12
unsignedintstacked_lr;//壓棧的lr
unsignedintstacked_pc;//壓棧的pc
unsignedintstacked_psr;//壓棧的psr
stacked_r0=((unsignedint)hardfault_args[0]);
stacked_r1=((unsignedint)hardfault_args[1]);
stacked_r2=((unsignedint)hardfault_args[2]);
stacked_r3=((unsignedint)hardfault_args[3]);
stacked_r12=((unsignedint)hardfault_args[4]);
stacked_lr=((unsignedint)hardfault_args[5]);
stacked_pc=((unsignedint)hardfault_args[6]);
stacked_psr=((unsignedint)hardfault_args[7]);
while(1)
{
printf("[Hardfaulthandler]
");
printf("R0=%x
",stacked_r0);
printf("R1=%x
",stacked_r1);
printf("R2=%x
",stacked_r2);
printf("R3=%x
",stacked_r3);
printf("R12=%x
",stacked_r12);
printf("StackedLR=%x
",stacked_lr);
printf("StackedPC=%x
",stacked_pc);
printf("StackedPSR=%x
",stacked_psr);
printf("SCB_SHCSR=%x
",SCB->SHCSR);
printf("CurrentLR=%x
",lr_value);
}
}
處理器進入到HardFault,將R0~R3、R12、LR、PC信息通過串口打印,根據(jù)寄存器信息排查問題代碼。
當(dāng)處理器處理異常時,除非異常是一個末尾連鎖異?;蜻t來的異常,否則,處理器把信息都壓入到當(dāng)前堆棧中入棧(stacking),8個數(shù)據(jù)字的結(jié)構(gòu)被稱為棧幀(stack frame),棧按照雙字地址對齊方式。
入棧后,堆棧指針立刻指向棧幀的最低地址單元。棧包含返回地址,這是被中止的程序中下條指令的地址。這個值在異常返回時返還給 PC,使被中止的程序恢復(fù)執(zhí)行。
如下圖連接仿真器查看匯編的地址可以找到是程序問題,根據(jù)PC指針地址,在程序生成的.map中查找出問題函數(shù)。
4. 處理建議
根據(jù)上述的定位手段可以查找是哪一種情況造成的異常,在編程過程中需要避免出現(xiàn)上述異常情況,但是在惡劣復(fù)雜的環(huán)境下,可能會小概率觸發(fā)HardFault中斷,可以在函數(shù)中添加復(fù)位或者跳轉(zhuǎn)指令,具體的實現(xiàn)方式需根據(jù)應(yīng)用和使用環(huán)境來評估。
原文標(biāo)題:HardFault定位方法和步驟
文章出處:【微信公眾號:安芯教育科技】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
-
處理器
+關(guān)注
關(guān)注
68文章
19259瀏覽量
229649 -
中斷
+關(guān)注
關(guān)注
5文章
898瀏覽量
41470 -
Cortex-M0
+關(guān)注
關(guān)注
4文章
124瀏覽量
38672
原文標(biāo)題:HardFault定位方法和步驟
文章出處:【微信號:Ithingedu,微信公眾號:安芯教育科技】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論