應(yīng)對(duì)STMCortexMHardFault異常_第1頁(yè)
應(yīng)對(duì)STMCortexMHardFault異常_第2頁(yè)
應(yīng)對(duì)STMCortexMHardFault異常_第3頁(yè)
應(yīng)對(duì)STMCortexMHardFault異常_第4頁(yè)
應(yīng)對(duì)STMCortexMHardFault異常_第5頁(yè)
已閱讀5頁(yè),還剩3頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、STM32 Cortex-M3 Hard FaultHard fault (硬錯(cuò)誤,也有譯為硬件錯(cuò)誤的)是在STM32(如無特別說明,這里的STM32指的是Cortex-M3的核)上編寫程序中所產(chǎn)生的錯(cuò)誤,造成Hard Fault錯(cuò)誤的原因也是最為紛繁復(fù)雜的。由于能導(dǎo)致該錯(cuò)誤的原因很多,所以一但出現(xiàn),比較難找到其原因。網(wǎng)上有很多類似的這種方法,現(xiàn)在我將其稍加整理,并結(jié)合我曾經(jīng)遇到過的問題,詳細(xì)說明。硬fault 是總線fault、存儲(chǔ)器管理fault 以及用法fault 上訪的結(jié)果。如果這些fault 的服務(wù)例程無法執(zhí)行,它們就會(huì)成為“硬傷”上訪(escalation)成硬fault。另外,在

2、取向量(異常處理是對(duì)異常向量表的讀?。r(shí)產(chǎn)生的總線fault,也按硬fault 處理。在NVIC 中有一個(gè)硬fault 狀態(tài)寄存器(HFSR),它指出產(chǎn)生硬fault 的原因。如果不是由于取向量造成的,則硬fault 服務(wù)例程必須檢查其它的fault 狀態(tài)寄存器,以最終決定是誰上訪的。1 寄存器描述首先查看硬故障寄存器,判別原因。對(duì)于調(diào)試故障,有個(gè)調(diào)試故障寄存器,在0xE000ED30處,有詳細(xì)介紹,不做探討;對(duì)于取中斷發(fā)生的,有兩類原因,一是在取向量過程中發(fā)生總線 fault,二是向量表偏移量設(shè)置有誤。本文重點(diǎn)介紹位30所示的,上訪類錯(cuò)誤。這樣Fault類異常有了三類,用法錯(cuò)誤,存儲(chǔ)管理錯(cuò)誤

3、,總線錯(cuò)誤。對(duì)于這些寄存器詳盡的描述,見權(quán)威指南。2 確定發(fā)生錯(cuò)誤的地方2.1 查找出錯(cuò)原因Cortex-M3有雙堆棧功能,在帶有操作系統(tǒng)時(shí),一般都會(huì)使用。在Keil軟件使用JTAG調(diào)試為例,系統(tǒng)的啟動(dòng)文件中,將斷點(diǎn)打在下面4個(gè)地方。HardFaultException B HardFaultExceptionMemManageException B MemManageExceptionBusFaultException B BusFaultExceptionUsageFaultException B UsageFaultException程序跑飛以后,就會(huì)停在上面的4個(gè)斷點(diǎn)的一個(gè)地方??梢酝?/p>

4、過兩種方式查找原因。第一種,在KEIL軟件下,利用軟件提供的功能查找故障原因。在點(diǎn)出的窗口中,可以大體確定是哪個(gè)寄存器、什么原因造成了Hard Fault。第二種,通過在內(nèi)存觀察窗口,直接輸入上面那些寄存器的值來確定,通過觀看寄存器那個(gè)位被置1了,確定出錯(cuò)原因。2.2 確定出錯(cuò)地方然后查看左側(cè)寄存器欄中Banked確定現(xiàn)在使用的是那個(gè)堆棧,MSP或者是PSP,確定以后,在內(nèi)存查看窗口,輸入堆棧的地址,以這個(gè)地址開始的8個(gè)32位數(shù)值,應(yīng)該依次是R0,R1,R2,R3,R12,R14,R15,XPSR的數(shù)值,據(jù)此判定你的堆棧地址是不是對(duì)的(有時(shí)需要考慮堆棧的增長(zhǎng)方向)。R14,R15的地址就是我們

5、出錯(cuò)的代碼所在的地址,需要在這個(gè)地址基礎(chǔ)上,首先偶數(shù)對(duì)齊,然后向上減去8個(gè)字節(jié)。需要考慮的是,在使用MSP的時(shí)候,有出錯(cuò)的地方并不一定在R14,R15處,而是在XPSR往后的第二個(gè)地址處,在這個(gè)附近查找,排除故障。3 兩個(gè)例子下面就我之前碰到過的,舉例說明,這兩個(gè)例子分析出結(jié)果后,會(huì)覺得很簡(jiǎn)單,但是查找原因的過程有點(diǎn)費(fèi)勁。3.1 memcpy內(nèi)存拷貝函數(shù)引發(fā)總線故障寄存器中IMPERCISERR位,標(biāo)示不精確的數(shù)據(jù)總線訪問錯(cuò)誤,權(quán)威指南中對(duì)此有詳盡的說明,“或者傳送的數(shù)據(jù)單位尺寸不能為設(shè)備所接受,此時(shí)有可能是LDM/STM指令造成的”。Memcpy函數(shù)的原因是這樣的void *memcpy(v

6、oid *dest, const void *src, size_t n),其中src是源地址,dest是目的地址,n是要拷貝的字節(jié)長(zhǎng)度。KEIL自帶的函數(shù)中并不檢查這三個(gè)參數(shù)是否有效,我所開發(fā)的程序中,源地址和目的地址都在外存(外部擴(kuò)展的內(nèi)存,本次大小是4M)中,假設(shè)size的大小是0xFFFF FFFF,這樣的數(shù)值非常的大,單純的拷貝都需要10多秒。程序中定義了很多的變量都在外存,這個(gè)拷貝函數(shù)所在的任務(wù)優(yōu)先級(jí)比較低,可能被中斷或者其它的任務(wù)打斷。我調(diào)試程序的時(shí)候,首先是發(fā)生在了中斷的地方,外存數(shù)組地址到了0x21FF 2200,原來定義在6802 1000,加起來立刻超出了外存大小。修改中

7、斷,最終確定是傳入的參數(shù)n太大了,直接是0xFFFF FFFF,這樣memcpy函數(shù)會(huì)在這里陷入死循環(huán),一直到外存耗盡,地址再增加,找不到外存地址了,然后觸發(fā)Hard Fault。3.2 濫用臨界區(qū)程序中的一些關(guān)鍵代碼,有時(shí)候需要在臨界區(qū)中執(zhí)行,但是臨界區(qū)若使用不當(dāng),則也會(huì)造成錯(cuò)誤。OS_ENTER_CRITICAL();。OS_EXIT_CRITICAL();#define OS_ENTER_CRITICAL() cpu_sr = OS_CPU_SR_Save();OS_CPU_SR_SaveMRS R0, PRIMASK ;保存全局中斷標(biāo)志 ; CPSID I ;關(guān)中斷 BX LR將全局中

8、斷標(biāo)志保存到R0中,此時(shí)R0是0,CPSID I則執(zhí)行關(guān)中斷命令,此時(shí)PRIMASK是1。#define OS_EXIT_CRITICAL() OS_CPU_SR_Restore(cpu_sr);OS_CPU_SR_Restore MSR PRIMASK, R0 ;恢復(fù)全局中斷標(biāo)志 BX LR將R0放入全部中斷寄存器中,則允許所有中斷了。程序中如何保護(hù)R0的,細(xì)看匯編發(fā)現(xiàn),實(shí)際上在執(zhí)行關(guān)中斷后,將R0保存到了sp+8處,開中斷時(shí)再取出來,這樣才保證了不會(huì)被修改。STR r0,sp,#0x08tPendTimes = 0;同時(shí),開中斷, LDR r0,sp,#0x08,則從sp+8處取出來,保存

9、到R0中。 臨界區(qū)中的代碼完成如下內(nèi)容:netconn_write(tradeconn,g_u8TcpSendBuf,l_u32CodeSendLen,NETCONN_COPY);調(diào)用TCPIP_APIMSG(&msg);,sys_mbox_post(mbox, &msg);OSQPost(mbox->hMBox, msg)發(fā)送消息,OS_EventTaskRdy函數(shù)修改線程的狀態(tài),使OSTCBStatPend變?yōu)榈却戤叄淮藭r(shí)若協(xié)議棧線程優(yōu)先級(jí)高于當(dāng)前任務(wù),則會(huì)觸發(fā)任務(wù)調(diào)度,懸起OSPendSV,但是由于關(guān)閉了中斷,即使在調(diào)用OS_ENTER_CRITICAL()后,也

10、無法打開中斷,故不能執(zhí)行中斷,任務(wù)無法切換。同理,調(diào)用sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0);,也無法阻塞自身,執(zhí)行任務(wù)調(diào)度,程序在臨界區(qū)里面變成了單線程在跑。一直等待代碼執(zhí)行完畢開中斷后,懸起的軟中才能執(zhí)行,本來應(yīng)該在發(fā)送消息和等待消息處執(zhí)行任務(wù)切換的,現(xiàn)在只能等待臨界區(qū)執(zhí)行完畢后,才能執(zhí)行任務(wù)切換中斷。此刻的PSP是0x2000DFAC,臨界區(qū)的那段代碼我們也有壓棧操作,即是0x2000 DFAC后面的內(nèi)容也是我們需要的,如下圖所示。原來的內(nèi)容是這樣的,如下圖所示:此時(shí)在OSPendSV中,執(zhí)行如下語句MRS R

11、0, PSP ; PSP is process stack pointerCBZ R0, OSPendSV_nosave ; SUBS R0, R0, #0x20 ; save remaining regs r4-11 on process stack STM R0, R4-R11從PSP-32個(gè)字節(jié)處開始,保存R4到R11這8個(gè)寄存器32個(gè)字節(jié),則原來的內(nèi)容都被覆蓋了,而這些內(nèi)容正好是我們需要的。被修改后的截圖如所示,原來的內(nèi)容被改成R4到R11這幾個(gè)寄存器的值。其中從0801556D變成了68130000,協(xié)議棧線程如下執(zhí)行。msg->msg.apimsg->function(

12、&(msg->msg.apimsg->msg);函數(shù)的地址變成了6813 0000,而6813 0000,是我們的外存,在這里執(zhí)行代碼0x68130006 F63A07E1 DCD 0xF63A07E1 ; ? Undefined最終是這句話,觸發(fā)了Hard fault。3.3 運(yùn)行中記錄出錯(cuò)位置以3.2為例子,進(jìn)行簡(jiǎn)單的反推。啟動(dòng)文件中的Hard中斷處理一般如下所示,即讓程序陷入這個(gè)死循環(huán)。HardFaultException; B HardFaultException現(xiàn)在我們要在記錄重要數(shù)據(jù),即此刻系統(tǒng)的運(yùn)行情況,主要包括:此刻堆棧情況、以及R0等8個(gè)寄存器的值、相關(guān)H

13、ard硬件寄存器的值,若是任務(wù)引發(fā)的,還要記錄任務(wù)的ID號(hào),因此修改這個(gè)異常處理函數(shù)。HardFaultExceptionTST LR, #4 ;將LR的值與4按位相與ITE EQ /若為0則是MSP,否則是PSPMRSEQ R0, MSP MRSNE R0, PSP B hard_fault_handler_c/這個(gè)是C語言編寫的函數(shù)void hard_fault_handler_c(unsigned int * hardfault_args) unsigned int stacked_r0,stacked_r1,stacked_r2,stacked_r3; unsigned int sta

14、cked_r12,stacked_lr, stacked_pc, stacked_psr; stacked_r0 = (unsigned long) hardfault_args0); stacked_r1 = (unsigned long) hardfault_args1); stacked_r2 = (unsigned long) hardfault_args2); stacked_r3 = (unsigned long) hardfault_args3); stacked_r12 = (unsigned long) hardfault_args4); stacked_lr = (unsi

15、gned long) hardfault_args5); stacked_pc = (unsigned long) hardfault_args6); stacked_psr = (unsigned long) hardfault_args7); sprintf(char*)g_cDataBuf,"Hard fault handlern"); Usart232SendStr(g_cDataBuf);sprintf(char*)g_cDataBuf,"The task pri id = 0x%0.8xn", OSPrioCur); /任務(wù)ID號(hào)Usart2

16、32SendStr(g_cDataBuf);sprintf(char*)g_cDataBuf,"SP = 0x%0.8xn", hardfault_args); /堆棧地址Usart232SendStr(g_cDataBuf);sprintf(char*)g_cDataBuf,"R0 = 0x%0.8xn", stacked_r0); Usart232SendStr(g_cDataBuf);sprintf(char*)g_cDataBuf,"R1 = 0x%0.8xn", stacked_r1);Usart232SendStr(g_c

17、DataBuf); sprintf(char*)g_cDataBuf,"R2 = 0x%0.8xn", stacked_r2); Usart232SendStr(g_cDataBuf);sprintf(char*)g_cDataBuf,"R3 = 0x%0.8xn", stacked_r3);Usart232SendStr(g_cDataBuf); sprintf(char*)g_cDataBuf,"R12 = 0x%0.8xn", stacked_r12); Usart232SendStr(g_cDataBuf);sprintf(c

18、har*)g_cDataBuf,"LR = 0x%0.8xn", stacked_lr);Usart232SendStr(g_cDataBuf); sprintf(char*)g_cDataBuf,"PC = 0x%0.8xn", stacked_pc); Usart232SendStr(g_cDataBuf);sprintf(char*)g_cDataBuf,"PSR = 0x%0.8xn", stacked_psr);Usart232SendStr(g_cDataBuf); exit(0); / terminate return;

19、 以3.2為例,發(fā)生異常后,串口的輸出入下所示:Hard fault handlerThe task pri id = 0x00000014/任務(wù)優(yōu)先級(jí)是20SP = 0x200077d8/當(dāng)前任務(wù)的堆棧地址是0x2000 77D8R0 = 0x2000dfa0R1 = 0x68130000R2 = 0x2000df9cR3 = 0x20002100R12 = 0x00000001LR = 0x0801c7fb/分析得出,這個(gè)地址就是出錯(cuò)的地方PC = 0x68130000PSR = 0x00000000此時(shí)需要借助map文件分析,map文件中得出對(duì)應(yīng)的代碼和數(shù)據(jù)位置。 tcpip_threa

20、d 0x0801c7ad Thumb Code 190 tcpip.o(i.tcpip_thread)i.tcpsvr_accept_20 0x0801c874 Section 64 ftpmanage.o(i.tcpsvr_accept_20)0x0801 c7fb應(yīng)該在tcpip文件中的tciip_thread函數(shù)里。T_LWIP_THREAD_STK 0x20007000 Data 2048 sys_arch.o(.bss) rsuPib 0x20007800 Data 32 para.o(.bss)堆??臻g是0x2000 77D8,是在T_LWIP_THREAD_STK這個(gè)??臻g里,這

21、也是協(xié)議棧任務(wù)的堆棧空間,證明判斷的任務(wù)優(yōu)先級(jí)為20是正確的。從0x0801 C7AD處開始的16進(jìn)制文件如下圖所示,再將匯編文件列出(需要KeiL生成)。tcpip_thread PROC;232 static void;233 tcpip_thread(void *arg)000000 b508 PUSH r3,lr/開始;234 ;235 struct tcpip_msg *msg;236 LWIP_UNUSED_ARG(arg);237 ;238 #if IP_REASSEMBLY;239 sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NUL

22、L);240 #endif /* IP_REASSEMBLY */;241 #if LWIP_ARP;242 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);000002 2200 MOVS r2,#0000004 492e LDR r1,|L11.192|000006 f2413088 MOV r0,#0x138800000a f7fffffe BL sys_timeout;243 #endif /* LWIP_ARP */;244 #if LWIP_DHCP;245 sys_timeout(DHCP_COARSE_TIMER_MSECS, dh

23、cp_timer_coarse, NULL);246 sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);247 #endif /* LWIP_DHCP */;248 #if LWIP_AUTOIP;249 sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);250 #endif /* LWIP_AUTOIP */;251 #if LWIP_IGMP;252 sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);253 #endif

24、/* LWIP_IGMP */;254 #if LWIP_DNS;255 sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);256 #endif /* LWIP_DNS */;257 ;258 if (tcpip_init_done != NULL) 00000e 482d LDR r0,|L11.196|000010 6800 LDR r0,r0,#0 ; tcpip_init_done000012 b128 CBZ r0,|L11.32|;259 tcpip_init_done(tcpip_init_done_arg);000014 482b L

25、DR r0,|L11.196|000016 1d00 ADDS r0,r0,#4000018 6800 LDR r0,r0,#0 ; tcpip_init_done_arg00001a 492a LDR r1,|L11.196|00001c 6809 LDR r1,r1,#0 ; tcpip_init_done00001e 4788 BLX r1 |L11.32|;260 ;261 ;262 LOCK_TCPIP_CORE();263 while (1) /* MAIN Loop */000020 e04c B |L11.188| |L11.34|;264 sys_mbox_fetch(mbo

26、x, (void *)&msg);000022 4669 MOV r1,sp000024 4827 LDR r0,|L11.196|000026 1f00 SUBS r0,r0,#4000028 6800 LDR r0,r0,#0 ; mbox00002a f7fffffe BL sys_mbox_fetch;265 switch (msg->type) 00002e 9800 LDR r0,sp,#0000030 7800 LDRB r0,r0,#0000032 2805 CMP r0,#5000034 d240 BCS |L11.184|000036 e8dff000 TBB

27、 pc,r000003a 030b DCB 0x03,0x0b00003c 222b3500 DCB 0x22,0x2b,0x35,0x00;266 #if LWIP_NETCONN;267 case TCPIP_MSG_API:;268 /if(msg->msg.apimsg->msg.conn = NULL);269 /break;270 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %pn", (void *)msg);271 msg->msg.apimsg->function(&(msg->msg.apimsg->msg);000040 9a00 LDR r2,sp,#0000042 6892 LDR r2,r2,#8000044 1d10 ADDS r0,r2,#4000046 9a00 LDR r2,sp,#0000048 6892 LDR r2,r2,#800004a 6811 LDR r1,r2,#000004c 4788 BLX r1;272 break;00004e e034 B |L11.1

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論