STM32中断优先级相关概念与使用笔记
上海 华东师范大学 通信工程系 ma-chao
一、基本概念
1.ARM cortex_m3 内核支持 256 个中断(16 个内核+240 外部)和可编程 256 级中断优先级
的设置,与其相关的中断控制和中断优先级控制寄存器(NVIC、SYSTICK 等)也都属于
cortex_m3 内核的部分。STM32 采用了cortex_m3 内核,所以这部分仍旧保留使用,但 STM32
并没有使用 cortex_m3 内核全部的东西(如内存保护单元 MPU 等),因此它的 NVIC 是
cortex_m3 内核的 NVIC 的子集。
2.STM32 目前支持的中断共为 84 个(16 个内核+68 个外部) ,和 16 级可编程中断优先级
的设置(仅使用中断优先级设置 8bit 中的高 4 位,见后面解释)。《参考最新 101xx-107xx
STM32 Reference manual, RM0008》。
3.以下主要对“外部中断通道”进行说明。
对于 cortex_m3 内核所支持的 240 个外部中断,我在这里使用了“中断通道”这个概
念,因为尽管每个中断对应一个外围设备,但该外围设备通常具备若干个可以引起中断的
中断源或中断事件。而该设备的所有的中断都只能通过该指定的“中断通道”向内核申请
中断。因此,下面关于中断优先级的概念都是针对“中断通道”的。当该中断通道的优先
级确定后,也就确定了该外围设备的中断优先级,并且该设备所能产生的所有类型的中断,
都享有相同的通道中断优先级。至于该设备本身产生的多个中断的执行顺序,则取决于用
户的中断服务程序。
4. STM32 可以支持的 68 个外部中断通道,已经固定的分配给相应的外部设备。每个中断
通道都具备自己的中断优先级控制字节 PRI_n(8 位,但在 STM32 中只使用 4 位,高 4 位有
效),每4 个通道的 8 位中断优先级控制字 (PRI_n) 构成一个 32 位的优先级寄存器 (Priority
Register) 。68 个通道的优先级控制字至少构成 17 个 32 位的优先级寄存器,它们是 NVIC
寄存器中的一个重要部分。
5.对于这 4bit 的中断优先级控制位还必须分成 2 组看:从高位开始,前面是定义抢先式优
先级的位,后面用于定义子优先级。4bit 的分组组合可以有以下几种形式:
编 号 分配情况
7 0:4 无抢先式优先级,16 个子优先级
6 1:3 2 个抢先式优先级,8 个子优先级
5 2:2 4 个抢先式优先级,4 个子优先级
4 3:1 8 个抢先式优先级,2 个子优先级
3/2/1/0 4:0 16 个抢先式优先级,无子优先级
6.在一个系统中,通常只使用上面 5 种分配情况的一种,具体采用哪一种,需要在初始化
时写入到一个 32 位寄存器 AIRC(Application Interrupt and Reset Control Register)了解以上基本概念还是不够的,还要了解具体中断的控制有那些途径,中断服务程序
如何正确的编写。下面的描述主要以 TIME2 通道为例。
二、中断控制
1.对于 STM32 讲,外部中断通道位置 28(35 号优先级)是给外部设备 TIME2 的,但 TIME2
本身能够引起中断的中断源或事件有好多个,比如更新事件(上溢/下溢) 、输入捕获、输出
匹配、DMA 申请等。所有 TIME2 的中断事件都是通过一个 TIME2 的中断通道向 STM32 内核提
出中断申请,那么 STM32 中如何处理和控制 TIME2 和它众多的、不同的、中断申请呢?
(题外话:STM32中的一个通用定时计数器,就比8 位控制器(如AVR,MCS-51 就更不必说了)中 TIME
要复杂多了。学过AVR 的,可能对输入捕获、输出匹配等还有概念,但如果你学的标准架构的MCS-51,那
么上手 32 位可能困难就更多了。所以我一直推荐学习8位机应该认真的从AVR 开始。尽管51 有很大的市
场,价格也相对便宜,但从长远的眼光看问题,从后续掌握 32 位的使用,考虑到学生的可持续发展,AVR
应该是比较好的选择。)
2.cortex_m3 内核对于每一个外部中断通道都有相应的控制字和控制位,用于单独的和总
的控制该中断通道。它们包括有:
z 中断优先级控制字:PRI_n(上面提到的)
z 中断允许设置位:在 ISER 寄存器中
z 中断允许清除位:在 ICER 寄存器中
z 中断悬挂 Pending(排队等待)位置位:在 ISPR寄存器中(类似于置中断通道标志位)
z 中断悬挂 Pending(排队等待)位清除:在 ICPR寄存器中(用于清除中断通道标志位)
z 正在被服务(活动)的中断(Active)标志位:在 IABR 寄存器中, (只读,可以知道当
前内核正在处理哪个中断通道)
因此,与 TIME2 中断通道相关的,在 NVIC 中有13个 bits,它们是 PRI_28(IP[28]),
的 8 个 bits(只用高4 位);加上中断通道允许,中断通道清除(相当禁止中断) ,中断通道
Pending 置位(我的理解是中断请求发生了,但当前有其它中断服务在执行,你的中断级别
又不能打断别人,所以 Pending 等待,这个应该由硬件自动置位的) ,中断 Pending 位清除
(可以通过软件将本次中断请求、且尚处在 Pending 状态,取消掉),正在被服务的中断
(Active)标志位,各 1 个bit。
上面的控制字和控制位都是分布在 NVIC 的寄存器组中的,可惜在 STM32 手册中竟然不
给出任何的解释和说明。
3.作为外围设备 TIME2本身也包括更具体的,管理自己不同中断的中断控制器(位) ,它们
主要是自身各个不同类型中断的允许控制位,和各自相应的中断标志位(这个在 STM32 的手
册中有详细的说明了) 。
4.在弄清楚2、3 两点的基础上,我们可以全程、全面和综合的来了解 TIME2 的中断过程,
以及如何控制的。
a/ 初始化过程
首先要设置寄存器 AIRC 中 PRIGROUP 的值, 规定系统中的抢先优先级和子优先级的个数(在 4 个bits 中占用的位数) ;
设置 TIME2本身的寄存器,允许相应的中断,如允许 UIE(TIME2_DIER的第[0]位)
设置 TIME2中断通道的抢先优先级和子优先级(IP[28],在NVIC 寄存器组中)
设置允许 TIME2 中断通道。在 NVIC 寄存器组的 ISER 寄存器中的一位。
b/ 中断响应过程
当 TIME2 的 UIE 条件成立(更新,上溢或下溢) ,硬件将 TIME2 本身寄存器中 UIE 中断
标志置位,然后通过 TIME2 中断通道向内核申请中断服务。
此时内核硬件将 TIME2 中断通道的 Pending 标志置位(相当与中断通道标志置位) ,表
示 TIME2 有中断申请。
如果当前有中断在处理,TIME2 的中断级别不够高,那么就保持 Pending 标志,当然用
户可以在软件中通过写 ICPR 寄存器中相应的位把本次中断清除掉。
当内核有空,开始响应 TIME2 的中断,进入 TIME2 的中断服务。此时硬件将 IABR 寄存
器中相应的标志位置位,表示 TIME2中断正在被处理。同时硬件清除 TIME2 的Pending标志
位。
c/ 执行 TIME2 的中断服务程序
所有 TIME2的中断事件,都是在一个 TIME2 中断服务程序中完成的,所以进入中断程序
后,中断程序需要首先判断是哪个 TIME2 的具体事件的中断,然后转移到相应的服务代码段
去。
注意不要忘了把该具体中断事件的中断标志位清除掉,硬件是不会自动清除 TIME2寄存
器中具体的中断标志位的。
如果 TIME2本身的中断事件多于 2个,那么它们服务的先后次序就由用户编写的中断服
务决定了。换句话说,对于 TIME2本身的多个中断的优先级,系统是不能设置的。所以用户
在编写服务程序时,应该根据实际的情况和要求,通过软件的方式,将重要的中断优先处理
掉。
当然你也可以每次中断服务只处理其中的一个,然后再次进入中断,处理下一个。
d/ 中断返回
内核执行完中断服务后,便进入中断返回过程,在这个过程中需要:
硬件将 IABR寄存器中相应的标志位清另,表示该中断处理完成
如果 TIME2 本身还有中断标志位置位,表示 TIME2 还有中断在申请,则重新将 TIME2
的 Pending标志置为 1,等待再次进入 TIME2 的中断服务。
以上中断过程在《ARM Cortex-M3 权威指南》中有详细描述,并配合时序图说明,可以
参考。
上述两点弄清楚后,就可以在 ST 提供的函数库的帮助下,正确的设置和使用 STM32 的
中断系统了。
如果你要了解更深入的东西,或者直接对寄存器操作,还要继续望下看。
三、深入 NVIC
1. 看看 Cortex-M3 中与NVIC 相关的寄存器有那些
SysTick Control and Status Register Read/write 0xE000E010
SysTick Reload Value Register Read/write 0xE000E014
SysTick Current Value Register Read/write clear 0xE000E018
SysTick Calibration Value Register Read-only 0xE000E01C
//==================
Irq 0 to 31 Set Enable Register Read/write 0xE000E100
. . . . .
Irq 224 to 239 Set Enable Register Read/write 0xE000E11C
//=================
Irq 0 to 31 Clear Enable Register Read/write 0xE000E180
. . . . .
Irq 224 to 239 Clear Enable Register Read/write 0xE000E19C
//==================
Irq 0 to 31 Set Pending Register Read/write 0xE000E200
. . . . .
Irq 224 to 239 Set Pending Register Read/write 0xE000E21C
//==================
Irq 0 to 31 Clear Pending Register Read/write 0xE000E280
. . . . .
Irq 224 to 239 Clear Pending Register Read/write 0xE000E29C
//==================
Irq 0 to 31 Active Bit Register Read-only 0xE000E300
. . . . . .
Irq 224 to 239 Active Bit Register Read-only 0xE000E31C
//===================
Irq 0 to 3 Priority Register Read/write 0xE000E400
. . . . .
Irq 224 to 239 Priority Register Read/write 0xE000E4EC
//========================
CPUID Base Register Read-only 0xE000ED00
Interrupt Control State Register Read/write or read-only 0xE000ED04
Vector Table Offset Register Read/write 0xE000ED08
Application Interrupt/Reset Control Register Read/write 0xE000ED0C
System Control Register Read/write 0xE000ED10
Configuration Control Register Read/write 0xE000ED14
System Handlers 4-7 Priority Register Read/write 0xE000ED18
System Handlers 8-11 Priority Register Read/write 0xE000ED1C
System Handlers 12-15 Priority Register Read/write 0xE000ED20
. . . . .
2.STM32 中用了那些
下面是从 ST公司提供的函数库的头文件得到的,库的版本是 v3.1.0
/* memory mapping struct for Nested Vectored Interrupt Controller (NVIC) */
typedef struct
{
__IO uint32_t ISER[8]; /*!< Interrupt Set Enable Register */
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; /*!< Interrupt Clear Enable Register */
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; /*!< Interrupt Set Pending Register */
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; /*!< Interrupt Clear Pending Register */
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; /*!< Interrupt Active bit Register */
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; /*!< Interrupt Priority Register, 8Bit wide */
uint32_t RESERVED5[644];
__O uint32_t STIR; /*!< Software Trigger Interrupt Register */
} NVIC_Type;
a/ 寄存器 ISER、ICER、ISPR、ICPR、IABR 在 STM32 中都使用的 8 个(实际 3 个就够
了,后面的留在后面扩充?)。 这些 32位的寄存器中每一位对应了一个中断通道相应的标志。
比如地址在 0xE000E100的 ISER[0]这个 32 位的寄存器,第 0 位是中断通道 0 的允许位,
第 1 位是中断通道 1 的允许标志……第 31 位是中断通道 31 的允许位;接下来地址在
0xE000E104 的 ISER[1]则是中断通道 32-63 的允许位。ICER、ISPR、ICPR、IABR 的结构相
同,只是含义不同。
注意是对这些寄存器的操作:写 1表示置位或清除,写 0无任何影响。
例如:对地址在 0xE000E100 的ISER[0]的第0 位写 1,表示允许中断通道 0 中断;
但对 0xE000E100 的ISER[0]的第0 位写 0,则没有任何作用,该位保持不变。
如果要禁止中断通道 0的中断响应,那么就必须:
对地址 0xE000E180 的ICER[0]的第0位写 1,表示禁止中断通道 0 的中断;
对 0xE000E180 的ICER[0]的第 0 位写0,也是不起任何作用的。
b/ IP[240]用于定义 240 个外部中断通道的优先级,每 1 个字节对应一个中断通道。4 个
中断通道的 IP[n]字构成一个 32 位的寄存器。在 STM32 中最多有 68 个外部中断通道,每个
IP[n]的1 个字节中只使用高 4 位(见前面介绍) 。IP[n]的结构如下:
31:28 27:24 23:20 19:16 15:12 11:8 7:4 3:0
E000E400 PIR_3 PIR_2 PIR_1 PIR_0
E000E404 PIR_7 PIR_6 PIR_5 PIR_4
…… …… …… …… ……
每 8 位的高 4
位有效,灰色
位表示无效 c/ 在 ST 公司提供的函数库的头文件中另一个数据结构中,还有一个重要的 32 位寄存器
需要关注 :AIRCR
/* memory mapping struct for System Control Block */
typedef struct
{
__I uint32_t CPUID; /*!<CPU ID Base Register */
__IO uint32_t ICSR; /*!< Interrupt Control State Register */
__IO uint32_t VTOR; /*!< Vector Table Offset Register */
__IO uint32_t AIRCR; /*!< Application Interrupt / Reset Control Register */
__IO uint32_t SCR; /*!< System Control Register */
__IO uint32_t CCR; /*!< Configuration Control Register */
__IO uint8_t SHP[12]; /*!<System Handlers Priority Registers(4-7,8-11,12-15) */
__IO uint32_t SHCSR; /*!< System Handler Control and State Register */
__IO uint32_t CFSR; /*!< Configurable Fault Status Register */
__IO uint32_t HFSR; /*!< Hard Fault Status Register */
__IO uint32_t DFSR; /*!< Debug Fault Status Register */
__IO uint32_t MMFAR; /*!< Mem Manage Address Register */
__IO uint32_t BFAR; /*!< Bus Fault Address Register */
__IO uint32_t AFSR; /*!< Auxiliary Fault Status Register */
__I uint32_t PFR[2]; /*!< Processor Feature Register */
__I uint32_t DFR; /*!< Debug Feature Register */
__I uint32_t ADR; /*!< Auxiliary Feature Register */
__I uint32_t MMFR[4]; /*!< Memory Model Feature Register */
__I uint32_t ISAR[5]; /*!< ISA Feature Register */
} SCB_Type;
它就是地址在 0xE000ED0C 的 32 位寄存器 AIRCR(Application Interrupt/Reset
Control Register) ,该寄存器的[10:8]3 位就是 PRIGROUP 的定义位,它的值规定了系统中
有多少个抢先级中断和子优先级中断。而 STM32 只使用高 4 位 bits,其可能的值如下(来
自 ST 的函数库头文件中的定义)
#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 */
由于这个寄存器相当重要,为了防止误操作(写),因此当改写这个寄存器的内容时,必须要同时向这个寄存器的高 16 位[31:16]写验证字(Register key) 0x05FA。
例如:SBC->AIRCR |= (0x05FA0000 || 0x300); // 设置系统中断有 16 个抢先优先
// 级,无子优先级
d/ 下面的定义与SYSTICK相关,有时也会用到的。
/* memory mapping struct for SysTick */
typedef struct
{
__IO uint32_t CTRL; /*!< SysTick Control and Status Register */
__IO uint32_t LOAD; /*!< SysTick Reload Value Register */
__IO uint32_t VAL; /*!< SysTick Current Value Register */
__I uint32_t CALIB; /*!< SysTick Calibration Register */
} SysTick_Type;
e/ 另外的几个寄存器,也是需要使用的(请具体参考相关的资料)
__IO uint8_t SHP[12]; /*!<System Handlers Priority Registers(4-7,8-11,12-15) */
同每个外部中断通道优先级定义字相同, 它们是内核中断通道4-15的优先级定义字所在
的寄存器。用户可以通过设置SHP[n],改变内部中断通道的优先级。
__IO uint32_t VTOR; /*!< Vector Table Offset Register */
如果你的代码要在RAM中启动执行,就需要对这个寄存器进行设置。
优先级可以被分为高低两个位段,分别是抢占优先级和亚优先级
Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位 AIRC 中 PRIGROUP 的值规定了设置和确定每个外部中断通道优先级的格式。例如,在上面将 0x05 写入了 AIRC 中 PRIGROUP,也就规定了当前系统中只能有 4 个抢先式优先级,相同的抢先式优先级下还可以有 4 个不同级别的子优先级,他们分别为:
位[7:6] 位[5:4] 位[3:0]
00 0 号抢先优先级 00 0 号子优先级 无效
01 1 号抢先优先级 01 1 号子优先级 无效
10 2 号抢先优先级 10 2 号子优先级 无效
11 3 号抢先优先级 11 3 号子优先级 无效
在Cortex—M3的优先级分配中,较低的优先级值具有较高的优先级。
数值小的优先级高, 数值大的优先级低
a 只能高抢先优先级的中断可以打断低抢先优先级的中断服务,构成中断嵌套。
b 当 2(n)个相同抢先优先级的中断出现,它们之间不能构成中断嵌套,但 STM32 首先响应子优先级高的中断。
c 当 2(n)个相同抢先优先级和相同子优先级的中断出现,STM32 首先响应中断通道所对应的中断向量地址低的那个中断。
可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()选择使用哪种优先级分组方式,这个函数的参数有下列5种:
NVIC_PriorityGroup_0 => 选择第0组
NVIC_PriorityGroup_1 => 选择第1组
NVIC_PriorityGroup_2 => 选择第2组
NVIC_PriorityGroup_3 => 选择第3组
NVIC_PriorityGroup_4 => 选择第4组
第0组:所有4位用于指定响应优先级 ( 从不嵌套 )
第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级
第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级
第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级
第4组:所有4位用于指定抢占式优先级 ( 最大的嵌套可能性 ) ( 类似于 STR710 )
subpriority 开始的位号 :
如果从 7 号开始 那么没有 pre-emption priority, [ b7 b6 b5 b4 ] 全部为 subpriority
如果从 6 号开始 那么 [ b7 ]为 pre-emption priority, [ b6 b5 b4 ] 为 subpriority
如果从 3 号开始 那么 [ b7 b6 b5 b4 ]为 pre-emption priority, 没有 subpriority
[pre-emption priority] :: [ subpriority ] ( STM32 共计 4 位 ) 所以无论如何配置做多只能有 16 级, 数值最小的具有最高的优先级
在程序中合理按排中断优先级可以达到具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。
要注意的几点是:
1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;
2)抢占式优先级别相同的中断源之间没有嵌套关系;
3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。
#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 */
/**
* @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;
}
/**
* @brief Initializes the NVIC peripheral according to the specified
* parameters in the NVIC_InitStruct.
* @param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
* the configuration information for the specified NVIC peripheral.
* @retval None
*/
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));
assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
{
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;
tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
/* Enable the Selected IRQ Channels --------------------------------------*/
NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
else // if (NVIC_InitStruct->NVIC_IRQChannelCmd == DISABLE)
{
/* Disable the Selected IRQ Channels -------------------------------------*/
NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
}
stm32如何开关中断
在STM32/Cortex-M3中是通过改变CPU的当前优先级来允许或禁止中断。
PRIMASK位:只允许NMI和hard fault异常,其他中断/异常都被屏蔽(当前CPU优先级=0)。
FAULTMASK位:只允许NMI,其他所有中断/异常都被屏蔽(当前CPU优先级=-1)。
在STM32固件库中(stm32f10x_nvic.c和stm32f10x_nvic.h) 定义了四个函数操作PRIMASK位和FAULTMASK位,改变CPU的当前优先级,从而达到控制所有中断的目的。
下面两个函数等效于关闭总中断:
void NVIC_SETPRIMASK(void);
void NVIC_SETFAULTMASK(void);
下面两个函数等效于开放总中断:
void NVIC_RESETPRIMASK(void);
void NVIC_RESETFAULTMASK(void);
上面两组函数要成对使用,不能交叉使用。
例如:
第一种方法:
NVIC_SETPRIMASK(); //关闭总中断
NVIC_RESETPRIMASK();//开放总中断
第二种方法:
NVIC_SETFAULTMASK(); //关闭总中断
NVIC_RESETFAULTMASK();//开放总中断
常常使用
NVIC_SETPRIMASK(); // Disable Interrupts
NVIC_RESETPRIMASK(); // Enable Interrupts