STM32F10xxx_异常与中断

STM32F10xxx_异常与中断

[TOC]

更新记录

version status description date author
V1.0 C Create Document 2018.10.27 John Wan

status:
C―― Create,
A—— Add,
M—— Modify,
D—— Delete。


1、异常与中断的概念

??对于几乎所有的微控制器,中断都是一种常见的特性。中断一般是由硬件(如外设和外部输入引脚)产生的时间,它会引起程序偏离正常的流程(如给外设提供服务),所有的Cortex-M处理器都会提供一个专门用于中断处理的嵌套向量中断控制器(NVIC)。那么除了中断请求以外,还有其他需要服务的事件,将其称为"异常"。在ARM的说法中,中断也是一种异常。除了NVIC系统控制块(SCB)寄存器中也包含了一些常用与系统异常的寄存器。

图1 典型微控制器中的各种中断源《ARM Cortex-M3与Cortex-M4权威指南CnR3》P157

注:后续的用词,中断:即表示外设中断;系统异常:编号从1~15的各种异常;异常:指系统异常与中断。

2、异常的流程

graph TD
A(接收请求:处理器确认外设的中断请求)-->B
B(保护现场:处理器暂停当前执行的任务)-->C
C(中断处理:处理器执行外设的中断服务程序ISR)-->D
D(还原现场:处理器继续执行之前暂停的任务)

2.1 中断请求的来源

  • 系统异常
  • 外设中断

??Cortex-M处理器的异常架构具有多种特性,支持多个系统异常和外部中断。编号1~15的为系统异常,16及以上的则为中断输入。包括所有中断在内的多数异常,都具有可编程的优先级,一些系统异常则具有固定的优先级。不同的微控制器的中断编号、优先级都可能不同,具体的中断编号由芯片商根据需求进行配置,查阅对应的指导手册。

图2 系统异常列表《ARM Cortex-M3与Cortex-M4权威指南CnR3P158》

图3 中断列表《ARM Cortex-M3与Cortex-M4权威指南CnR3》P159

??而CMSIS-Core定义的中断标识是用枚举实现,从数值0开始(代表中断#0)表示中断编号,系统异常的编号为负数。之所以CMSIS-Core使用另外一条编号系统,是因为这样可稍微提高部分API函数的效率(例如设置优先级)。

2.2 处理器接受中断请求的条件

  • 处理器正在运行(未被暂停或处于复位状态)
  • 异常处于使能状态(NMI和HardFault为特殊情况,他们总是使能的)
  • 异常的优先级高于当前等级
  • 异常未被异常屏蔽寄存器屏蔽

2.2.1 异常的使能状态

  1. 中断的使能

??由NVIC寄存器中的中断设置使能寄存器(ISER)中断清除使能寄存器(ICER)控制,可进行字、半字或字节进行访问。需要说明的是ISER/ICER寄存器都是32位宽,每个位代表一个中断输入,如果存在32个以上的外部中断,则ISER/ICER寄存器可能不止一个。需要强调的是该寄存器只进行中断的设置,即异常编号为16开始的外部中断#0,不包括前16个异常类型的系统异常。

  1. 系统异常的使能

??由SCB寄存器中的系统处理控制和状态寄存器(SHCSR)控制,其中只能设置异常编号为4、5、6的存储管理错误、总线错误、使用错误三种系统异常的使能

2.2.2 异常的优先级

??每个异常都有一个优先级,其中绝大部分的优先等级可编辑,编程范围为0~255,极少部分的系统异常的优先等级是固定的且优先级为负数,这样可方便处理器进行判断是否应该接受异常以及何时接受并执行异常处理,大致分为两种决定的场景:

  • 正常的流程被中断
  • 中断的流程被中断(中断的嵌套)
  1. 优先级的定义

??只有更高优先级的异常(优先级编号更小)可以抢占低优先级的异常(优先级编号更大)Cortex-M3处理器在设计上具有3个固定的最高优先级以及256个可编程优先级(最多具有128个抢占等级),可编程优先级的实际数量由芯片设计商决定,多数使用Cortex-M3的芯片,支持的优先级较少,这样可降低NVIC的复杂度,降低功耗且增加速度。

??在Cortex-M3处理器中每个异常都存在一个8bit的优先级寄存器来设置其中断优先级等级(例如后面讲的NVIC->IP[n]),而该8bit的优先级寄存器进一步分为两个部分:抢占优先级与子优先级,可利用系统控制块SCB中的应用中断和复位控制寄存器AIRCR的BIT[10:8](见图4)来配置优先级的分组共23=8个分组(见图5),而这里的分组就决定了8bit的优先级寄存器中抢占优先级占几位,子优先级占几位:

图4 SCB_AIRCR优先级分组《ARM Cortex-M3与Cortex-M4权威指南CnR3》P180

图5 Cortex-M优先级分组定义《ARM Cortex-M3与Cortex-M4权威指南CnR3》P162

??上面是Cortex-M3的最大允许设置范围,前面提到,可编程优先级的实际数量根据芯片商的各种需求可进行裁剪设计,通过芯片商的手册可以查询,例如在STM32F10xxx中就限制了只能使用8bit的优先级寄存器高四位BIT[7:4],称其有效宽度,那么优先级分组的方式就只有5个分组,在这5个分组中,抢占优先级最多只能占4bit,即抢占优先级等级最多只能设置24 = 16个,见下图。1

图6 STM32F10xxx的优先级分组配置《STM32F10XXX_programming_mannual_PM0056_ENV6》P135

??在处理器已经在运行一个中断处理时能否产生另外一个中断,是由该中断的抢占优先级决定的。子优先级只会用在具有两个相同分组优先级的异常同时产生的情形,此时,具有更高子优先级(数值更小)的异常会被首先处理。

问题:

(1)为什么前面提到Cortex-M3有256个可编程优先级,而最多只具备128个抢占优先级?

如图5,优先级分组时总会配置一种情况,即达到分组的最大宽度时,抢占优先级最多只能分配7位,保留一位的子优先级。

(2)为什么8bit的优先级寄存器的宽度设置是通过移除LSB用高位表示,而不是通过移除MSB用低位表示?

便于不同处理器之间进行移植,按照这种方式,在具有4位优先级配置寄存器的设备上写的程序,就可能会在具有3位优先级配置寄存器的设备上运行。例如某应用程序,IRQ#0的优先级为0x05,IRQ#1的优先级为0x03,那么移除了最高位bit2之后,则IRQ#0的优先级会变为0x01,高于IRQ#1的优先级。如果IRQ#0的优先级为0x50,IRQ#1的优先级为0x30,那么移除最低位bit0之后,还是IRQ#0的优先级较低。

  1. 中断的优先级

??每个中断都有对应的优先级寄存器,可根据在系统控制块SCB应用中断和复位控制寄存器AIRCR配置的优先级分组所规定的抢占优先级范围和子优先级范围来设定抢占优先级等级以及子优先级等级。其优先级分组有几种情况由芯片商决定。该寄存器可通过字节、半字和字访问,优先级寄存器的数量取决于芯片中实际存在的外部中断数。可通过中断优先级寄存器NVIC->IP[n]来进行设置.

图7 中断优先级寄存器《ARM Cortex-M3与Cortex-M4权威指南CnR3》P176

  1. 系统异常的优先级

??关于可编辑的系统异常优先级,原理同中断的优先级设定,其可通过系统处理优先级寄存器 SCB->SHP[0~11]来进行设置。

图8 系统处理优先级寄存器《ARM Cortex-M3与Corte-M4权威指南CnR3》P181

  1. CMSIS-Core设置异常优先级
core_cm3.h

优先级分组
static __INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)   //设置优先级分组
static __INLINE uint32_t NVIC_GetPriorityGrouping(void)                 //读取优先级分组

优先级等级
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)//设置异常的优先级
static __INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)               //读取异常的优先级
  1. STM32F10xxx库文件中设置异常优先级
misc.h

/** @defgroup Preemption_Priority_Group
  * @{
  */

#define NVIC_PriorityGroup_0         ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
                                                            4 bits for subpriority */
#define NVIC_PriorityGroup_1         ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
                                                            3 bits for subpriority */
#define NVIC_PriorityGroup_2         ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
                                                            2 bits for subpriority */
#define NVIC_PriorityGroup_3         ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
                                                            1 bits for subpriority */
#define NVIC_PriorityGroup_4         ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
                                                            0 bits for subpriority */

#define IS_NVIC_PRIORITY_GROUP(GROUP) (((GROUP) == NVIC_PriorityGroup_0) ||                                        ((GROUP) == NVIC_PriorityGroup_1) ||                                        ((GROUP) == NVIC_PriorityGroup_2) ||                                        ((GROUP) == NVIC_PriorityGroup_3) ||                                        ((GROUP) == NVIC_PriorityGroup_4))

#define IS_NVIC_PREEMPTION_PRIORITY(PRIORITY)  ((PRIORITY) < 0x10)

#define IS_NVIC_SUB_PRIORITY(PRIORITY)  ((PRIORITY) < 0x10)

#define IS_NVIC_OFFSET(OFFSET)  ((OFFSET) < 0x000FFFFF)

misc.c

/** @defgroup MISC_Private_Defines
  * @{
  */

#define AIRCR_VECTKEY_MASK    ((uint32_t)0x05FA0000)

/**
  * @brief  Configures the priority grouping: pre-emption priority and subpriority.
  * @param  NVIC_PriorityGroup: specifies the priority grouping bits length.
  *   This parameter can be one of the following values:
  *     @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
  *                                4 bits for subpriority
  *     @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
  *                                3 bits for subpriority
  *     @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
  *                                2 bits for subpriority
  *     @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
  *                                1 bits for subpriority
  *     @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
  *                                0 bits for subpriority
  * @retval None
  */
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
  /* Check the parameters */
  assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));

  /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
  SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}
  1. 中断的设置步骤

(1)设置优先级分组,STM32F10XXX默认的优先级分组是2位抢占优先级,2位子优先级。(SCB->AIRCR的复位为0x05FA0000,如果不进行设置bit[10:8]为0x05)

(2)设置中断的抢占优先级与子优先级。

(3)在NVIC或外设中使能中断

2.2.3 异常的屏蔽

用于异常屏蔽的特殊寄存器,包括PRIMASK、FAULTMASK、BASEPRI:

  1. PRIMASK

??在许多应用中,可能都需要暂时禁止所有中断以执行一些时序关键的任务,此时可以使用PRIMASK寄存器。该寄存器只能在特权状态下访问。

??PRIMASK寄存器用于禁止除NMIHardFault外的所有异常。实际上它是将当前优先级改为0(最高可编程等级),以不被其它异常所中断

CMSIS-Core的core_cm3.c中提供以下函数进行查询与设置:

/**
 * @brief  Return the Priority Mask value
 *
 * @return PriMask
 *
 * Return state of the priority mask bit from the priority mask register
 */
__ASM uint32_t __get_PRIMASK(void)
{
  mrs r0, primask
  bx lr
}

/**
 * @brief  Set the Priority Mask value
 *
 * @param  priMask  PriMask
 *
 * Set the priority mask bit in the priority mask register
 */
__ASM void __set_PRIMASK(uint32_t priMask)
{
  msr primask, r0
  bx lr
}

core_cm3.h中:

#define __enable_irq                __enable_interrupt        /*!< global Interrupt enable */
#define __disable_irq               __disable_interrupt       /*!< global Interrupt disable */

关于下面的core_cm3.h中可参考开关中断

  1. FAULTMASK

??行为上与PRIMASK寄存器类似,只是它实际上会将当前优先级修改为-1,这样甚至是HardFlaut处理也会被屏蔽,则当FAULTMASK置位时,只有NMI异常处理才能执行

CMSIS-Core的core_cm3.c中提供以下函数:

/**
 * @brief  Return the Fault Mask value
 *
 * @return FaultMask
 *
 * Return the content of the fault mask register
 */
__ASM uint32_t  __get_FAULTMASK(void)
{
  mrs r0, faultmask
  bx lr
}

/**
 * @brief  Set the Fault Mask value
 *
 * @param  faultMask  faultMask value
 *
 * Set the fault mask register
 */
__ASM void __set_FAULTMASK(uint32_t faultMask)
{
  msr faultmask, r0
  bx lr
}

core_cm3.h中:

static __INLINE void __enable_fault_irq()         { __ASM ("cpsie f"); }
static __INLINE void __disable_fault_irq()        { __ASM ("cpsid f"); }

??FAULTMASK也只能在特权状态下访问,不过不能在NMIHardFault处理中设置。

??FAULTMASK会在退出异常处理被自动清除,从NMI中退出时除外。因此可以利用此特性,如果在低优先级的异常处理中触发了一个高优先的异常(NMI除外),但是想要先处理完低优先级的异常处理再进行高优先的处理,那么可以:

  • 设置FAULTMASK禁止所有异常(NMI除外)
  • 设置高优先级异常的挂起状态
  • 退出处理

??由于在FAULTMASK置位时,挂起的高优先级异常处理无法执行,高优先级的异常就会在FAULTMASK被清除前继续保持挂起状态,低优先级处理完成后才会将其清除。因此,可以强制让高优先级处理在低优先级处理结束后开始执行。

  1. BASEPRI

??有些情况下,可能只想禁止优先级低于某特定等级的中断,只需将所需的屏蔽优先级写入BASEPRI寄存器。只能在特权状态下访问。

CMSIS-Core的core_cm3.c中提供以下函数:

/**
 * @brief  Return the Base Priority value
 *
 * @return BasePriority
 *
 * Return the content of the base priority register
 */
__ASM uint32_t  __get_BASEPRI(void)
{
  mrs r0, basepri
  bx lr
}

/**
 * @brief  Set the Base Priority value
 *
 * @param  basePri  BasePriority
 *
 * Set the base priority register
 */
__ASM void __set_BASEPRI(uint32_t basePri)
{
  msr basepri, r0
  bx lr
}

2.2.4 异常的请求设置与查询

  1. 中断输入与挂起行为

??每个中断都有多个属性:

  • 每个中断都可被禁止(默认)或使能。
  • 每个中断都可被挂起(等待服务的请求)或解除挂起。
  • 每个中断可处于活跃(正在处理)或非活跃状态。

??为了支持这些属性,NVIC中包含了多个可编程寄存器,用于中断使能控制、挂起状态和只读的活跃状态位。

??当NVIC的中断输入被确认后,它就会引发该中断的挂起状态,被存储在NVIC的可编程寄存器中,即使该中断请求在处理器还没来的急处理,就已经被取消,只要在NVIC中已经被挂起过,那么就算有效,这就是NVIC支持脉冲中断请求特性。

??当中断正被处理时,它就会处于活跃状态,处理完成,活跃状态自动清除。但对于许多微控制器设计,外设会产生电平触发的中断,因此ISR必须要手动清除中断请求,如写入外设中的某个寄存器。

(1)、当中断处于活跃状态是,处理器无法在中断完成和异常返回前再次接受同一个中断请求。

(2)、若中断请求产生时处理器正在处理另一个具有更高优先级的中断,而在处理器队该中断请求做出响应之前,通过软件代码将挂起状态清除掉,那么该请求就会被取消且不会再得到处理。

(3)、若外设持续保持某个中断请求,那么即使软件尝试着清除该挂起状态,挂起状态还是会再次置位的。

(4)、若在得到处理后,中断源仍在继续保持中断请求,那么这个中断就会再次进入挂起状态且再次得到处理器的服务。

(5)、对于脉冲中断请求,若在处理器开始处理前,中断请求信号产生了多次,它们会被当作一次中断请求。

(6)、中断的挂起状态可以在其正被处理时再次置位。

(7)、即使中断被禁止了,它的挂起状态仍可置位。在这种情况下,若中断稍后被使能了,可以被触发并得到服务。有些时候,这种情况并不是所希望的,因此需要在使能NVIC中的中断前手动清除挂起状态。

  1. 中断挂起的设置、清除、查询

??中断的挂起状态可通过中断设置挂起寄存器 NVIC->ISPR[n]中断清除挂起寄存器 NVIC->ICPR[n]访问,若存在32个以上的外部中断输入,则寄存器可能不止一个。

CMSIS-Core中core_m3.h提供以下函数:

static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
  1. 中断的活跃状态查询

??每个外部中断都有一个活跃状态位,当处理器开始执行中断处理时,该位会被置1,而在执行中断返回时会被清零,通过中断活跃状态寄存器 NVIC->IABR[n]进行查询。如果被抢占,还是会处于活跃状态。当外部中断的数量超过32个,寄存器不止一个。

CMSIS-Core中core_m3.h提供以下函数:

static __INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)
  1. 系统异常的挂起设置、清除、查询

??通过中断控制和状态寄存器 SCB->ICSR进行访问。

  1. 系统异常的活跃状态查询

??通过系统处理控制和状态寄存器 SCB->SHCSR进行访问。

2.3 如何暂停当前任务进入异常流程

2.4 如何执行异常处理,并触发异常返回

2.5 如何进行异常返回,执行暂停的任务


  1. 参考《STM32中文参考手册_V10》P130,《STM32F10xxx_20xxx_21xxx_L1xxx_Programming_Mannual_PM0056_ENV6》P135 Binary Point?

原文地址:https://www.cnblogs.com/wanjianjun777/p/10252357.html

时间: 2024-08-12 20:19:21

STM32F10xxx_异常与中断的相关文章

浅析arm的异常、中断和arm工作模式的联系

说到异常向量,会让人联想到中断向量.其实,中断是属于异常的子集的,也就是说中断其实是异常其中的一种. 回到异常向量,他其实是一张表格,每个格子里存放的是一个地址,或者是一个跳转命令,不管是哪个,其目的都是让PC跳转到真正处理异常的代码的地方. 以下是arm的异常向量表: 图1 初步介绍完异常向量,就来对比下ARM的arm的7种工作模式: 图2 User : 非特权模式,大部分任务执行在这种模式 FIQ :   当一个高优先级(fast) 中断产生时将会进入这种模式 IRQ :   当一个低优先级

RT-thread内核之异常与中断

一.什么是中断? 中断有两种,一种是CPU本身在执行程序的过程中产生的,一种是由CPU外部产生的. cpu外部中断,就是通常所讲的“中断”(interrupt).对于执行程序来说,这种“中断”的发生完全是异步的,因为不知道什么时候会发生.CPU对其的响应也完全是被动的, 可以通过“关中断”指令关闭对其的响应. 然而由软件产生的中断一般是由专设的指令,如X86中的“INT n”在程序中有意产生的, 是主动的,同步的.只要CPU执行一条INT指令,在开始执行下一条指令之前一定会进入中 断服务程序.这

深入浅出计算机组成原理:异常和中断-程序出错了怎么办?(第28讲)

一.引子 过去这么多讲,我们的程序都是自动运行且正常运行的.自动运行的意思是说,我们的程序和指令都是一条条顺序执行,你不需要通过键盘或者网络给这个程序任何输入.正常运行是说,我们的程序都是能够正常执行下去的,没有遇到计算溢出之类的程序错误. 不过,现实的软件世界可没有这么简单.一方面,程序不仅是简单的执行指令,更多的还需要和外部的输入输出打交道.另一方面,程序在执行过程中,还会遇到各种异常情况,比如除以0.溢出,甚至我们自己也可以让程序抛出异常. 那这一讲,我就带你来看看,如果遇到这些情况,计算

ARM中的异常和中断

ARM中有5种异常模式,有7种中断源.这7种中断源中有些中断是我们希望发生的,但有些中断是我们不希望发生的. 我们希望发生的中断: 软中断:属于svc模式,通过SWI指令便可以产生软中断,进入到svc模式. irq中断:属于irq模式,当产生普通的外部中断时,处理器便进入到IRQ模式. fiq中断:属于fiq模式,当产生高优先级外部中断时,处理器便进入到FIQ模式. 我们不希望发生的中断: 复位:属于svc模式,当系统上电时便会产生复位中断,系统进入到svc模式.复位中断不需要中断返回. 取指中

Java异常的中断和恢复

中断:抛出一个异常类的实例而终止现有程序的执行:恢复:不是抛出一个异常类的实例,而是调用一个用于解决问题的方法或就地解决问题. 在Java中,对那些要调用方法的客户程序员,我们要通知他们可能从自己的方法里"掷"出违例.这是一种有礼貌的做法,只有它才能使客户程序员准确地知道要编写什么代码来捕获所有潜在的违例. catch(Exception e) { System.out.println("caught an exception"); } 这段代码能捕获任何违例,所以

服务器间歇性异常网络中断问题的临时处理

最近几天,公司的服务器总有用户报连不上服务器的情况,而我们跟服务器处在一个vlan内的机器ping却一直正常.而其他网段的机器却隔一段时间就连接不上了,把服务器重启后又可以连接正常. 把服务器中间连接的交换机更换之后,现象并没有什么变化,仍然后连不上的时候.把网线也换了,并且直接接入到核心交换机上,还是这样的症状. 这个现象很像是arp病毒在作怪,在服务器上装了arp的杀毒软件也并没有什么反应,没查到病毒.又把系统的补丁都打了一下,现象依旧.而执行一次arp -d再ping的话就能ping通.

中断与异常详解(二)

中断或异常发生之前 当 CPU 执行了当前指令之后,CS 和 EIP 这对寄存器中所包含的内容就是下一条将要执行 指令的逻辑地址.在对下一条指令执行前,CPU 先要判断在执行当前指令的过程中是否发生 了中断或异常. 如果发生了一个中断或异常 那么 CPU 将做以下事情 • 确定所发生中断或异常的向量i(在 0-255 之间). • 通过 IDTR 寄存器找到 IDT 表,读取 IDT 表第i项(或叫第i个门). • 分两步进行有效性检查:首先是“段”级检查,将 CPU 的当前特权级 CPL(存放

深入理解Linux内核-中断和异常

Linux内核代码查看 http://androidxref.com/ 中断:被定义位一个事件,它能改变处理器执行指令的顺序.它对应硬件(CPU.其他硬件设备)电路产生的电信号. 同步中断:指令执行时CPU控制单元产生:称为同步,是因为只有在一条指令终止执行后CPU才回发出中断.也被称为异常 异步中断:其他硬件设备按照CPU时钟信号随机产生的.也被简称中断 中断的约束:1.中断必须尽快处理完成:中断一般被分两部分执行:关键而且紧急的部分,内核立即执行:其余部分内核稍后执行: 2.中断的处理必须能

2-1 处理器状态(模式)中断与异常

一.处理器是由运算器.控制器.一系列的寄存器以及高速缓存构成 1. 两类寄存器:              用户可见寄存器:高级语言编译器通过优化算法分配并使用,以减少程序访问内存的次数              控制和状态寄存器:用于控制处理器的操作通常由操作代码使用 常见的控制和状态寄存器 程序计数器(PC:Program Counter),记录将要取出的指令的地址              指令寄存器(IR:Insruction Register),记录最近取出的指令