ARM学习(5) 异常模式学习(CortexM3/M4)

笔者来聊聊对CortexM3/M4的异常模式理解。

之前的了解,都是基于具体的芯片而言的,比如ST/GD/NXP公司的,STM32,很常用,基于Keil或者IAR集成开发环境,一直到工作之后,才更清楚的了解了架构这种概念,这种芯片本质上还是基于CortexM3/M4这种架构的,各种厂商都是基于这种架构进行开发的,然后添加很多外设,满足不同的功能需求。

1、通用寄存器

寄存器首先是架构的不可或缺的一部分,也是了解架构编程模型的重要地方。

1.寄存器 ,r0-r12,r13(sp),r14(lr),r15(pc)

2.状态寄存器PSR:APSR、EPSR、IPSR


T:thumb指令,总是为1
异常编号:正常处理的异常编号,与接下来介绍的中断向量表编号相关,
NZCV:标志位,

与经典的arm架构相比(比如arm7 ),M系列做了很多改变。
模式:模式减少,只有特权模式和非特权模式(均是在线程下,异常模式自动是特权等级),
堆栈:只有主栈+线程栈,MSP+PSP,不像经典架构,每个模式都有各自独立的栈。
寄存器:减少,模式下除了SP,其他寄存器都是共享,经典架构下,寄存器较多,各个模式下都有几个独立的寄存器。
异常:异常也有变化,新增hard fault等,将svc模式转为svc的函数处理,等等

3.中断相关寄存器 :PRIMASK、FAULTMASK和BASEPRI

a. PRIMASK:中断屏蔽位,1位宽,屏蔽除NMI以及hard_fault之外的中断
b. FAULTMASK:中断屏蔽位,1位宽,屏蔽除NMI之外的所有中断
c . BASEPRI:当前优先级设置,位数取决于厂商有多少个外设中断,
d. CMSIS-Core 提供了多个C函数,可以访问中断相关寄存器,也提供了汇编函数

x = __get_BASEPRI(); // Read BASEPRI register
x = __get_PRIMARK(); // Read PRIMASK register
x = __get_FAULTMASK(); // Read FAULTMASK register
__set_BASEPRI(x); // Set new value for BASEPRI
__set_PRIMASK(x); // Set new value for PRIMASK
__set_FAULTMASK(x); // Set new value for FAULTMASK
__disable_irq(); // Set PRIMASK, disable IRQ
enable_irq(); // Clear PRIMASK, enable IRQ
; 汇编代码
MRS r0, BASEPRI ; Read BASEPRI register into R0
MRS r0, PRIMASK ; Read PRIMASK register into R0
MRS r0, FAULTMASK ; Read FAULTMASK register into R0
MSR BASEPRI, r0 ; Write R0 into BASEPRI register
MSR PRIMASK, r0 ; Write R0 into PRIMASK register
MSR FAULTMASK, r0 ; Write R0 into FAULTMASK register
;primask 以及 faultmask 特殊处理
CPSIE i ; Enable interrupt (clear PRIMASK)
CPSID i ; Disable interrupt (set PRIMASK)
CPSIE f ; Enable interrupt (clear FAULTMASK)
CPSID f ; Disable interrupt (set FAULTMASK)
  • Control寄存器
    nPRIV:设置特权等级还是非特权等级
    SPSEL:选择主栈还是线程栈
    之前介绍的,异常永远是特权模式,且使用主栈。

    这里有两种情况:(通常RTOS中栈切换版本会使用进程栈/线程栈 PSP,其他裸机情况下都使用的时候主栈MSP)
    a .进入异常模式之前是主栈:压栈使用主栈,然后切到异常函数下执行(下文图1),
    b. 进入异常模式之前是进程栈(线程栈): 压栈使用进程栈,然后切到异常函数下执行,这时使用主栈,特权模式(下文图2)

    步奏:
  • 线程模式下:使用主栈(MSP)
  • 中断#1来临,首先使用主栈(MSP)压栈,然后切到中断服务程序#1,这时处于特权模式下,使用主栈(MSP)
  • 中断#2来临:使用主栈进行压栈,然后切到中断服务程序#2执行,这时处于特权模式下,使用主栈(MSP)
  • 中断#2结束:根据LR 选择 MSP主栈,进行出栈,同时还是处于特权模式下,
  • 中断#1结束,根据LR选择MSP主栈,进行出栈,同时还是特权模式下执行
  • 线程模式下:使用主栈继续执行

    步奏:
  • 线程模式下:使用线程栈
  • 中断#1来临,首先使用进程栈(PSP)压栈,然后切到中断服务程序#1,这时处于特权模式下,使用主栈(MSP)
  • 中断#2来临:使用主栈进行压栈,然后切到中断服务程序#2执行,这时处于特权模式下,使用主栈(MSP)
  • 中断#2结束:根据LR 选择 MSP主栈,进行出栈,同时还是处于特权模式下,
  • 中断#1结束,根据LR选择PSP进程栈,进行出栈,同时切到线程非特权模式下执行
  • 线程模式下:使用线程栈继续执行

上文说的:特权模式与图中的处理模式一致含义。

2、异常与中断

系统异常

  • 复位:reset_handler,用来做系统初始化以及分散加载,最终跳到main函数,
  • 异常函数处理:hard_fault,mem_mange_fault,bus_fault,usg_fault,处理各种异常
  • SVC:常用来做系统调用,必须立即响应,否则造成硬件错误
  • PendSV:RTOS常用该异常做上下文切换,因为该异常可以软件触发且挂起
  • SysTick:定时中断,可用作滴答定时器


CortexM3/M4响应异常时,会有一些列的操作,

  1. 入栈:硬件自动压入xPSR, PC, LR, R12以及R3‐R0
  2. 取向量:取出正确的异常向量,这样能找到异常处理函数,
  3. 选择堆栈指针:更新SP指针,更新PSR,更新PC,更新LR(EXC_RETURN),

    中断返回:

    1. 出栈:与入栈的顺序想对应,
    2. 更新NVIC寄存器:清除相关的中断或者异常标志位,

异常返回值LR (EXC_RETURN),异常处理LR在M3/M4架构下有新的意义,

中断

中断管理使用NVIC,嵌入式向量中断控制器进行管理,

3、参考

ARM Cortex-M3与Cortex-M4权威指南
Cortex-M3权威指南

版权声明:
作者:ZhangYixi
链接:http://zyixi.xyz/arm%e5%ad%a6%e4%b9%a0%ef%bc%885%ef%bc%89-%e5%bc%82%e5%b8%b8%e6%a8%a1%e5%bc%8f%e5%ad%a6%e4%b9%a0%ef%bc%88cortexm3-m4%ef%bc%89/
来源:一西站点
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
< <上一篇
下一篇>>
文章目录
关闭
目 录