标签:ram 进程 emma 原理 工程 volatile 正是 异常处理 ogr
STM32 F407 采用 Cortex-M4 的内核,该内核的 Fault 异常可以捕获非法的内存访问和非法的编程行为。Fault异常能够检测到以下几类非法行为:
为了解释所述的 Fault 中断处理程序的原理,这里重述一下当系统产生异常时 MCU 的处理过程:
当系统产生异常时,我们需要两个关键寄存器值,一个是 PC ,一个是 LR (链接寄存器),通过 LR找到相应的堆栈,再通过堆栈找到触发异常的PC 值。将产生异常时压入栈的 PC 值取出,并与反汇编的代码对比就能得到哪条指令产生了异常。
这里解释一下关于 LR 寄存器的工作原理。如上所述,当 Cortex-M4 处理器接受了一个异常后,寄存器组中的一些寄存器值会被自动压入当前栈空间里,这其中就包括链接寄存器(LR )。这时的 LR 会被更新为异常返回时需要使用的特殊值(EXC_RETURN)。关于EXC_RETURN 的定义如下,其为 32 位数值,高 28 位置 1,第 0 位到第三位则提供了异常返回机制所需的信息,如下表所示。可见其中第 2 位标示着进入异常前使用的栈是 MSP还是PSP。在异常处理过程结束时,MCU 需要根据该值来分配 SP 的值。这也是本方法中用来判断所使用堆栈的原理,其实现方法可以从后面_init_hardfault_isr 中看到。
异常处理流程:
首先要定义异常处理函数,在M4和M3核中,这两个是一样的,可以直接在stm32_f4xx.s中定义:
.cpu cortex-m3 .thumb .global HardFault_Handler .extern hard_fault_handler_c HardFault_Handler: TST LR, #4 ITE EQ MRSEQ R0, MSP MRSNE R0, PSP B hard_fault_handler_c
这里有几个命令要说明一下含义: TST 是Bit级别的与操作。ITE 是 MRSEQ和MRSNE都是两个命令的合体,分别可以拆开成:MRS,EQ和MRS,NE,分别的意思是如果两者相等,则把MSP的值赋值到R0,如果R0和PSP不等,则把PSP赋植到R0.ITE读为 if-then-else
关于HardFault_Handler 这个函数,一般在stm32_f4xx.s的中断向量表中,我的系统中的代码如下所示:
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
接下来就是整个流程的代码实现:
/ hard fault handler in C, // with stack frame location as input parameter void hard_fault_handler_c (unsigned int * hardfault_args) { unsigned int stacked_r0; unsigned int stacked_r1; unsigned int stacked_r2; unsigned int stacked_r3; unsigned int stacked_r12; unsigned int stacked_lr; unsigned int stacked_pc; unsigned int 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 ("\n\n[Hard fault handler - all numbers in hex]\n"); printf (“R0 = %x\n”, stacked_r0); printf (“R1 = %x\n”, stacked_r1); printf (“R2 = %x\n”, stacked_r2); printf (“R3 = %x\n”, stacked_r3); printf (“R12 = %x\n”, stacked_r12); printf (“LR [R14] = %x subroutine call return address\n”, stacked_lr); printf (“PC [R15] = %x program counter\n”, stacked_pc); printf (“PSR = %x\n”, stacked_psr); printf (“BFAR = %x\n”, (*((volatile unsigned long )(0xE000ED38)))); printf (“CFSR = %x\n”, (((volatile unsigned long )(0xE000ED28)))); printf (“HFSR = %x\n”, (((volatile unsigned long )(0xE000ED2C)))); printf (“DFSR = %x\n”, (((volatile unsigned long )(0xE000ED30)))); printf (“AFSR = %x\n”, (((volatile unsigned long *)(0xE000ED3C)))); printf (“SCB_SHCSR = %x\n”, SCB->SHCSR); while (1); } /* hard fault interrupt handler */ void _int_hardfault_isr( ) { __asm(“TST LR, #4”); __asm(“ITE EQ”); __asm(“MRSEQ R0,MSP”); __asm(“MRSNE R0,PSP”); __asm(“B hard_fault_handler_c”); } void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ DEBUG_ERR(" hard fault handler "); _int_hardfault_isr(); while (1) { } }
上面的这些代码,一般的工程师就可以看懂了,就不多做介绍了,假如你有啥这方面的问题,欢迎交流和沟通,反正是我的板子可以正常使用这些代码了。
标签:ram 进程 emma 原理 工程 volatile 正是 异常处理 ogr
原文地址:https://www.cnblogs.com/dylancao/p/11142205.html