ARM Cortex M

HardFault Handling

Analyze Hard Fault
當Exception發生時,如何找到Exception發生的位置?

EXC_RETURN 條件
0xFFFFFFF1 返回handler mode(巢狀中斷)
0xFFFFFFF9 返回thread mode,使用msp
0xFFFFFFFD 返回thread mode,使用psp

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

實驗

  1. 定義0xFFFFFFFF位址。
#define INVALID_ADDR (*(volatile uint32_t *)0xFFFFFFFF)
  1. 嘗試放在某個程式段中,會發生Hard Fault。
INVALID_ADDR = INVALID_ADDR + 1;
  1. 判斷目前的Stack Pointer是MSP還是PSP,另外儲存LR。
__asm void HardFault_Handler(void) { tst lr, #4 ite eq mrseq r0, msp mrsne r0, psp mov r1, lr b __cpp(HardFault_Handler_C) }
  1. 倒出Stacking的Stack Memory資訊。
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); }

實驗結果

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

執行到LDR r0, [r0, #0x00]會造成Hard Fault。

Why Use "volatile"

Compiler開O0和O3的差異

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

分析組語
分析assembly,開O3結果變成重複一直跳0x080029f8。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

原因
Compiler會因為要加速程式執行的performance,把0x20000060位址的數值暫存在CPU Register(R0~R12)中,不再從Memory裡載入到CPU Register(R0~R12)中,導致value值沒有被更新。因此使用volatile來避免Compiler過度優化。

Variable Length Argument

include <stdarg.h> // 需要include stdarg.h
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); }

結果

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →