完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、STM32的异常处理机制
对于cortex M3/M4来说,CPU每执行完一条指令都会检查有无异常产生,当CPU发现有异常产生时,它就会进行如下处理:
我们可以打开一个STM32库的汇编启动文件,例如startup_stm32f10x_hd.s,我们可以看到,前面的时异常,后面的就是中断了(其实中断也是一种异常)。 二、未定义指令异常 未定义指令,即使"还没有定义的指令",也就是CPU不认识的指令。 修改汇编文件,如下所示,添加各种异常的向量表项,另外在调用mymain()函数前调用串口初始化函数,并添加一个未定义的指令异常。 Stack_Size EQU 0x00000500 ;定义堆栈大小为1024byte AREA STACK, NOINIT, READWRITE, ALIGN=3 ;定义一个数据段,标记为STACK,即栈,不写入初始值初,对RAM来说,即初始化为0,8字节对齐 Stack_Mem SPACE Stack_Size ;保留Stack_Size大小的栈空间 __initial_sp ;标号,代表堆栈顶部地址,后面有用 PRESERVE8 ;指示编译器8字节对齐 THUMB ;指示编译器以后的指令为THUMB指令 ; Vector Table Mapped to Address 0 at Reset AREA RESET, CODE, READONLY ;定义只读数据段,标记为RESET,其实放在CODE区,位于0地址 EXPORT __Vectors ;在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用 IMPORT NMI_Handler ; NMI Handler IMPORT HardFault_Handler ; Hard Fault Handler IMPORT MemManage_Handler ; MPU Fault Handler IMPORT BusFault_Handler ; Bus Fault Handler IMPORT UsageFault_Handler ; Usage Fault Handler IMPORT SVC_Handler ; SVCall Handler IMPORT DebugMon_Handler ; Debug Monitor Handler IMPORT PendSV_Handler ; PendSV Handler IMPORT SysTick_Handler ; SysTick Handler __Vectors DCD __initial_sp ;当前地址写入一个字(32bit)数据,值应该为栈顶地址 DCD Reset_Handler ;当前地址写入一个字(32bit)数据,值为Reset_Handler指向的地址值,即程序入口地址 DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD MemManage_Handler ; MPU Fault Handler DCD BusFault_Handler ; Bus Fault Handler DCD UsageFault_Handler ; Usage Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler AREA |.text|, CODE, READONLY ;定义代码段,标记为.text ; Reset handler ;利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰 Reset_Handler PROC ;过程的开始 EXPORT Reset_Handler [WEAK] ;[WEAK] 弱定义,意思是如果在别处也定义该标号(函数),在链接时用别处的地址。 IMPORT |Image$$RW_IRAM1$$Base| ;从别处导入data段的链接地址 IMPORT |Image$$RW_IRAM1$$Length| ;从别处导入data段的长度 IMPORT |Load$$RW_IRAM1$$Base| ;从别处导入data段的加载地址 IMPORT |Image$$RW_IRAM1$$ZI$$Base| ;从别处导入ZI段的链接地址 IMPORT |Image$$RW_IRAM1$$ZI$$Length|;从别处导入ZI段的长度 ; 复制数据段 LDR R0, = |Load$$RW_IRAM1$$Base| ;将data段的加载地址存入R0寄存器 LDR R1, = |Image$$RW_IRAM1$$Base| ;将data段的链接地址存入R1寄存器 LDR R2, = |Image$$RW_IRAM1$$Length| ;将data段的长度存入R2寄存器 CopyData SUB R2, R2, #4 ;每次复制4个字节的data段数据 LDR R3, [R0, R2] ;把加载地址处的值取出到R3寄存器 STR R3, [R1, R2] ;把取出的值从R3寄存器存入到链接地址 CMP R2, #0 ;将计数和0相比较 BNE CopyData ;如果不相等,跳转到CopyData标签处,相等则往下执行 ; 清除BSS段 LDR R0, = |Image$$RW_IRAM1$$ZI$$Base| ;将bss段的链接地址存入R1寄存器 LDR R1, = |Image$$RW_IRAM1$$ZI$$Length| ;将bss段的长度存入R2寄存器 CleanBss SUB R1, R1, #4 ;每次清除4个字节的bss段数据 MOV R3, #0 ;将0存入r3寄存器 STR R3, [R0, R1] ;把R3寄存器存入到链接地址 CMP R1, #0 ;将计数和0相比较 BNE CleanBss ;如果不相等,跳转到CleanBss标签处,相等则往下执行 IMPORT mymain ;通知编译器要使用的标号在其他文件 IMPORT uart_init BL uart_init ;跳转去执行uart_init函数 DCD 0XFFFFFFFF ;一个未定义的指令 BL mymain ;跳转去执行main函数 B . ;原地跳转,即处于循环状态 ENDP ALIGN ;填充字节使地址对齐 END ;整个汇编文件结束 然后新建exception.c文件,并添加各种异常处理函数 #include "uart.h" void NMI_Handler(void) { putstring("Exception: NMI.rn"); } void HardFault_Handler(void) { putstring("Exception: Hard Fault.rn"); } void MemManage_Handler(void) { putstring("Exception: Mem Manage Fault.rn"); } void BusFault_Handler(void) { putstring("Exception: Bus Fault.rn"); } void UsageFault_Handler(void) { putstring("Exception: Usage Fault.rn"); } void SVC_Handler(void) { putstring("Exception: SVCall.rn"); } void DebugMon_Handler(void) { putstring("Exception: Debug Monitor.rn"); } void PendSV_Handler(void) { putstring("Exception: PendSV.rn"); } void SysTick_Handler(void) { putstring("Exception: SysTick.rn"); } 然后编译烧录运行,可以看到,串口一种打印硬件错误异常,这是因为没有将异常标志位清除的结果 另外,进入了硬件错误异常而不是未定义指令异常,是因为cortex M3/M4的如下机制,因为未定义指令属于"处理器操作相关的错误",如果没有使能"Usage Fault",发就会触发"Hard Fault"。 那么要怎么使能"Usage Fault",我们要对SCB->SHCSR寄存器的第十八位写1来使能。即System Control Block的System Handler Control and State Register。 我们找到STM32库里的core_cm3.h文件可以看到这个寄存器的结构体定义,将这个文件加入我们的工程中 然后在exception.c文件中添加exception_init()函数使能"Usage Fault", void exception_init(void){ SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk);} 然后在汇编文件中调用 编译发现core_cm3.h有许多未定义的错误, 我们不使用这些将其屏蔽掉即可,然后重新编译链接烧录运行,可以看到进入了使用错误异常 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1771 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1619 浏览 1 评论
1070 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
724 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1673 浏览 2 评论
1935浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
728浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
567浏览 3评论
593浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
551浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 10:32 , Processed in 0.728547 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号