在進(jìn)行CortexM系列MCU開(kāi)發(fā)時(shí),大家應(yīng)該都或多或少觸發(fā)過(guò)不可屏蔽中斷,例如人見(jiàn)人愛(ài)的Hardfault。
對(duì)于嵌入式工程師來(lái)說(shuō),能夠穩(wěn)定復(fù)現(xiàn)的Bug最好解決,再不濟(jì)挨個(gè)打斷點(diǎn)也能定位到問(wèn)題代碼位置。
可是異常如果是不定時(shí),無(wú)規(guī)律的發(fā)生在日常的運(yùn)行中,那打斷點(diǎn)的方式無(wú)異于守株待兔。
本篇將提供小技巧簡(jiǎn)述CortexM的異常壓棧機(jī)制,教大家如何寫出一個(gè)現(xiàn)場(chǎng)保存函數(shù)以及如何調(diào)用該函數(shù)。
如下圖所示,觸發(fā)中斷的時(shí)候,CortexM?系列芯片會(huì)按照該排列將相關(guān)現(xiàn)場(chǎng)數(shù)據(jù)進(jìn)行地址偏移壓棧,N即此時(shí)的SP數(shù)值,通過(guò)SP中存放的地址,我們可以獲取到如圖所示的數(shù)據(jù)。
而要知道觸發(fā)異常的地址則需要關(guān)注LR(Link Register)的數(shù)值,它存放著異常觸發(fā)點(diǎn)的函數(shù)地址。
那么按照壓棧的排列,我們可以編寫一個(gè)結(jié)構(gòu)體以及相關(guān)的記錄現(xiàn)場(chǎng)函數(shù),如下圖所示,結(jié)構(gòu)體的成員完全是按照上圖的壓棧順序排列,那下一步就是在哪里調(diào)用這個(gè)接口來(lái)獲取到案發(fā)時(shí)的第一手資料
?要想獲得第一手?jǐn)?shù)據(jù),就要去中斷函數(shù)的執(zhí)行處,很多廠商的SDK都會(huì)在名為XXX_it.c文件里為開(kāi)發(fā)者們寫好各個(gè)中斷的Handler,由于S文件中都是弱定義(弱定義即在C文件中有同名的函數(shù),則以C文件中的函數(shù)優(yōu)先編譯,則可能造成觸發(fā)中斷時(shí)并不會(huì)運(yùn)行S文件處的函數(shù))所以建議可以將其屏蔽或者自己重新編寫一個(gè)新的函數(shù)名。
由下圖可見(jiàn),通過(guò)IMPORT的形式調(diào)用外部現(xiàn)場(chǎng)保存函數(shù),將SP寄存器賦值給R0寄存器是因?yàn)镽0通常時(shí)作為函數(shù)的第一個(gè)參數(shù)進(jìn)行調(diào)用的,可看作是將SP數(shù)值作為參數(shù)傳入StackSave函數(shù),BL的意思是帶返回的跳轉(zhuǎn),即使跳轉(zhuǎn)運(yùn)行完成StackSave函數(shù)后還返回此處。
完成上述函數(shù)編寫以及調(diào)用后,即可進(jìn)行測(cè)試了。本次范例通過(guò)SPI初始化時(shí)傳入錯(cuò)誤的外設(shè)寄存器地址來(lái)觸發(fā)HardFault中斷,由下圖可看出,此時(shí)記錄到的LR數(shù)值為0x8000e83
?查詢后可知,0x8000e83的位置為SPI初始化函數(shù)中,符合預(yù)設(shè)的異常觸發(fā)位置。在非仿真環(huán)境下可通過(guò)map文件找到大致的函數(shù)地址。
綜上,我們就知道了如何獲取到觸發(fā)異常中斷時(shí)的程序運(yùn)行地址,通過(guò)將獲取到的信息存入到片上Flash指定地址的形式將此時(shí)的現(xiàn)場(chǎng)信息進(jìn)行保存,并通過(guò)固件和map一一對(duì)應(yīng)管控。
這樣在漫長(zhǎng)運(yùn)行過(guò)程中,如果不慎觸發(fā)異常異常中斷,通過(guò)對(duì)應(yīng)的map文件即可迅速定位BUG所在大致位置?
-
寄存器
+關(guān)注
關(guān)注
31文章
5290瀏覽量
119786 -
仿真器
+關(guān)注
關(guān)注
14文章
1012瀏覽量
83586 -
串口中斷
+關(guān)注
關(guān)注
0文章
64瀏覽量
13845 -
Flash單片機(jī)
+關(guān)注
關(guān)注
0文章
111瀏覽量
9377 -
MCU芯片
+關(guān)注
關(guān)注
3文章
246瀏覽量
11348
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論