# ARM Cortex M ## HardFault Handling **Analyze Hard Fault** 當Exception發生時,如何找到Exception發生的位置? | EXC_RETURN | 條件 | | ---------- | ----------------------- | | 0xFFFFFFF1 | 返回handler mode(巢狀中斷)| | 0xFFFFFFF9 | 返回thread mode,使用msp | | 0xFFFFFFFD | 返回thread mode,使用psp | ![](https://i.imgur.com/NZm0U2n.png) **實驗** 1. 定義0xFFFFFFFF位址。 ```cpp= #define INVALID_ADDR (*(volatile uint32_t *)0xFFFFFFFF) ``` 2. 嘗試放在某個程式段中,會發生Hard Fault。 ```c=+ INVALID_ADDR = INVALID_ADDR + 1; ``` 3. 判斷目前的Stack Pointer是MSP還是PSP,另外儲存LR。 ```c=+ __asm void HardFault_Handler(void) { tst lr, #4 ite eq mrseq r0, msp mrsne r0, psp mov r1, lr b __cpp(HardFault_Handler_C) } ``` 4. 倒出Stacking的Stack Memory資訊。 ```c=+ void HardFault_Handler_C(unsigned int *hardfault_args, unsigned int lr_value) { unsigned long stacked_r0; unsigned long stacked_r1; unsigned long stacked_r2; unsigned long stacked_r3; unsigned long stacked_r12; unsigned long stacked_lr; unsigned long stacked_pc; unsigned long stacked_psr; stacked_r0 = ((unsigned long)hardfault_args[0]); stacked_r1 = ((unsigned long)hardfault_args[1]); stacked_r2 = ((unsigned long)hardfault_args[2]); stacked_r3 = ((unsigned long)hardfault_args[3]); stacked_r12 = ((unsigned long)hardfault_args[4]); stacked_lr = ((unsigned long)hardfault_args[5]); stacked_pc = ((unsigned long)hardfault_args[6]); stacked_psr = ((unsigned long)hardfault_args[7]); printf("[HardFault]\r\n"); printf("Stack frame:\r\n"); printf(" R0 = %x\r\n", stacked_r0); printf(" R1 = %x\r\n", stacked_r1); printf(" R2 = %x\r\n", stacked_r2); printf(" R3 = %x\r\n", stacked_r3); printf(" R12 = %x\r\n", stacked_r12); printf(" LR = %x\r\n", stacked_lr); printf(" PC = %x\r\n", stacked_pc); printf(" PSR = %x\r\n", stacked_psr); printf(" LR/EXC_RETURN = %x\r\n", lr_value); while(1); } ``` **實驗結果** ![](https://i.imgur.com/s5UvPz8.png) 執行到LDR r0, [r0, #0x00]會造成Hard Fault。 ## Why Use "volatile" **Compiler開O0和O3的差異** {%youtube YqWIKpjQAmM %} **分析組語** 分析assembly,開O3結果變成重複一直跳0x080029f8。 ![](https://i.imgur.com/g8ORU6K.png) **原因** Compiler會因為要加速程式執行的performance,把0x20000060位址的數值暫存在CPU Register(R0~R12)中,不再從Memory裡載入到CPU Register(R0~R12)中,導致value值沒有被更新。因此使用volatile來避免Compiler過度優化。 ## Variable Length Argument ```c= include <stdarg.h> // 需要include stdarg.h ``` ```c= static void printmsg(char *msg, ...) { char str[80]; va_list args; va_start(args, msg); vsprintf(str, msg, args); for(uint32_t i = 0; i < strlen(str); i++) { while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) != SET); USART_SendData(USART2, str[i]); } while(USART_GetFlagStatus(USART2, USART_FLAG_TC) != SET); va_end(args); } ``` 結果 ![](https://i.imgur.com/TPhLAtz.png)