# ARM Cortex M
## HardFault Handling
**Analyze Hard Fault**
當Exception發生時,如何找到Exception發生的位置?
| EXC_RETURN | 條件 |
| ---------- | ----------------------- |
| 0xFFFFFFF1 | 返回handler mode(巢狀中斷)|
| 0xFFFFFFF9 | 返回thread mode,使用msp |
| 0xFFFFFFFD | 返回thread mode,使用psp |

**實驗**
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);
}
```
**實驗結果**

執行到LDR r0, [r0, #0x00]會造成Hard Fault。
## Why Use "volatile"
**Compiler開O0和O3的差異**
{%youtube YqWIKpjQAmM %}
**分析組語**
分析assembly,開O3結果變成重複一直跳0x080029f8。

**原因**
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);
}
```
結果
