STM32 (CortexM3) 中NVIC(嵌套向量中断控制)的理解

发布者:ShimmeringMoon最新更新时间:2016-07-08 来源: eefocus关键字:STM32  NVIC  向量中断控制 手机看文章 扫描二维码
随时随地手机看文章

 

一、STM32 (Cortex-M3) 中的优先级概念

    STM32(Cortex-M3)中有两个优先级的概念:抢占式优先级和响应优先级,也把响应优先级称作“亚优先级”或“副优先级”,每个中断源都需要被指定这两种优先级。

1. 何为占先式优先级(pre-emption priority)

    高占先式优先级的中断事件会打断当前的主程序/中断程序运行—抢断式优先响应,俗称中断嵌套。

2. 何为副优先级(subpriority)

    在占先式优先级相同的情况下,高副优先级的中断优先被响应;

    在占先式优先级相同的情况下,如果有低副优先级中断正在执行, 高副优先级的中断要等待已被响应的低副优先级中断执行结束后才能得到响应—非抢断式响应(不能嵌套)。

3. 判断中断是否会被响应的依据

    首先是占先式优先级,其次是副优先级;

    占先式优先级决定是否会有中断嵌套;

    Reset、NMI、Hard Fault 优先级为负(高于普通中断优先级)且不可调整。

4. 优先级冲突的处理

    具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断的嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。

    当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。

5. Cortex-M3中对中断优先级的定义

    既然每个中断源都需要被指定这两种优先级,就需要有相应的寄存器位记录每个中断的优先级;在Cortex-M3中定义了8个比特位用于设置中断源的优先级,这8个比特位可以有8种分配方式,如下:

所有8位用于指定响应优先级
最高1位用于指定抢占式优先级,最低7位用于指定响应优先级
最高2位用于指定抢占式优先级,最低6位用于指定响应优先级
最高3位用于指定抢占式优先级,最低5位用于指定响应优先级
最高4位用于指定抢占式优先级,最低4位用于指定响应优先级
最高5位用于指定抢占式优先级,最低3位用于指定响应优先级
最高6位用于指定抢占式优先级,最低2位用于指定响应优先级
最高7位用于指定抢占式优先级,最低1位用于指定响应优先级

这就是优先级分组的概念。

6. stm32中对中断优先级的定义

    Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位,这4个寄存器位的分组方式如下:

第0组:所有4位用于指定响应优先级
第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级
第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级
第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级
第4组:所有4位用于指定抢占式优先级

 

STM32 (CortexM3) 中NVIC(嵌套向量中断控制)的理解

 

    AIRC(Application Interrupt and Reset Register)寄存器中有用于指定优先级的 4 bits。这4个bits用于分配preemption优先级和sub优先级,在STM32的固件库中定义如下:

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


    可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()选择使用哪种优先级分组方式,这个函数的参数有下列5种:

NVIC_PriorityGroup_0 => 选择第0组
NVIC_PriorityGroup_1 => 选择第1组
NVIC_PriorityGroup_2 => 选择第2组
NVIC_PriorityGroup_3 => 选择第3组
NVIC_PriorityGroup_4 => 选择第4组

    接下来就是指定中断源的优先级,下面以一个简单的例子说明如何指定中断源的抢占式优先级和响应优先级:

// 选择使用优先级分组第1组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

// 使能EXTI0中断
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 指定抢占式优先级别1

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定响应优先级别0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

// 使能EXTI9_5中断
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定抢占式优先级别0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);


--------------------------------------------------------------------------------

    要注意的几点是:

    1. 如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;

    2. 抢占式优先级别相同的中断源之间没有嵌套关系;

    3. 如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。

二、开关总中断

    在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

-------------------------------------------------------------------------------------------------
补充:
可以用: 
#define CLI()    __set_PRIMASK(1) 
#define SEI() __set_PRIMASK(0) 
来实现开关总中断的功能。

关键字:STM32  NVIC  向量中断控制 引用地址:STM32 (CortexM3) 中NVIC(嵌套向量中断控制)的理解

上一篇:stm32 直接读写寄存器代码风格总结
下一篇:ARM定义特殊寄存器*(volatile unsigned long *))的理解

推荐阅读最新更新时间:2024-03-16 14:59

读取stm32 产品的唯一身份的寄存器
读取stm32 产品的唯一身份的寄存器 voidGet_ChipID(void) { uint32_t temp0,temp1,temp2; temp0 = *(__IO uint32_t*)(0x1FFF7A10); temp1 = *(__IO uint32_t*)(0x1FFF7A14); temp2 = *(__IO uint32_t*)(0x1FFF7A18); // temp0=(*( uint32_t *)0x1FFF7A10); //产品唯一身份标识寄存器(96位) // temp1=(*( uint32_t *)0x1FFF7A14); // temp2=(*( ui
[单片机]
stm32 j-link IAR下烧写后脱机运行设置
1、 projectEWARMv4lnkarm_flash.xcl // Code memory in FLASH -DROMSTART=0x8008000 -DROMEND=0x8014fff 更改为 // Code memory in FLASH -DROMSTART=0x8000000 -DROMEND=0x8014fff 2、 #define NVIC_VectTab_RAM ((u32)0x20000000) #define NVIC_VectTab_FLASH ((u32)0x08000000)
[单片机]
STM32模拟IIC程序
#ifndef __AT24C02_H__ #define __AT24C02_H__ #include stm32f10x.h void i IC init(void); void iicwrite(u8 add,u8 Achar); u8 iicread(u8 add); #endif #include stm32f10x.h #include at24c02.h void iicstart(void); void iicstop(void); void ack(void); void iicwritebyte(u8 a); u8 iicreadbyte(voi
[单片机]
基于DSP和STM32的电液伺服控制器设计
摘要:基于DSP和STM32的智能伺服控制器在位置闭环反馈伺服控制系统中有着广泛的应用。本设计采用TMS320F28335与STM32F103RET6双核控制器,两者通过SPI进行数据通信分工协作。另外,设计了完善的系统故障自检测报警程序与复合控制算法程序,在提高了系统稳定性与智能化的同时,又提高了整个系统的精度。 引言 伺服控制系统大部分都采用传统的硬件结构,控制算法比较固定,而且也无法实现不同工况下的高性能控制算法,难以满足现代工业的需求。现阶段迫切需要研制一种智能型、具有高可靠性、控制性能更加优秀的电液伺服系统。基于DSP与STM32的智能型伺服控制器具有软硬件结合程度更加紧密、系统的智能化程度更高、可实现多种控制策略的
[单片机]
基于DSP和<font color='red'>STM32</font>的电液伺服<font color='red'>控制</font>器设计
STM32定时器触发ADC的时序话题
在STM32芯片的ADC应用中,我们往往会利用定时器来触发ADC的启动转换,而能够触发ADC转换的定时器事件往往有多个,有时我们可能很关注这些定时器事件在触发ADC时有哪些时序上的差别。下面以STM32G4芯片为例,来大致聊聊该话题。 这里选择TIM1来触发ADC。我们从手册或CubeMx配置界面不难看到可用来触发ADC的定时器事件可以是定时器TRGO信号和通道CC事件/信号,而TRGO可能来自定时器的使能动作、定时器的更新事件、通道输出比较事件、通道比较输出参考信号以及编码时钟。 这里先重点就Update事件、通道OCx信号和OCxREF信号作为TRGO来触发ADC,看看相应的触发时间点在哪里。 另外,作为ADC的外部触
[单片机]
<font color='red'>STM32</font>定时器触发ADC的时序话题
STM32之SysTick
STM32单片机是以Cortex-M3为内核的 以用Cortex-M3中关于SysTick的描述: SysTick定时器被捆绑在NVIC中,用于产生SysTick异常(异常号:15)。在以前,操作系统还有所有使用了时基的系统,都必须一个硬件定时器来产生需要的“滴答”中断,作为整个系统的时基。滴答中断对操作系统尤其重要。例如,操作系统可以为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。 Co
[单片机]
<font color='red'>STM32</font>之SysTick
STM32使用J-FLASH合并Hex文件
STM32开发过程中,使用boot方式实现IAP功能,应用程序运行在flash的起始地址之后,有一个偏移。在生产过程中,需要为芯片现在boot.hex和app.hex两个程序,为了简化过程,将两个hex合并为一个hex文件。 1、使用J-FLASH打开工程或建立工程。 2、file- open data file打开第一个hex文件,没有先后顺序。 3、可以看到boot.hex的起始地址是0x8000000 4、file- merge data file打开要合并的文件,flash地址必须没有重叠 5、可以看到app.hex的起始地址是0x8020000 6、上述步骤执行完毕,hex文件已经合并了,使用f
[单片机]
<font color='red'>STM32</font>使用J-FLASH合并Hex文件
使用VSCode搭建STM32开发环境
首先附上一张VS Code图一直都喜欢这种,黑色主题感觉高大上。 一、需要的软件和工具。 下载最新版VS Code: 安装好插件,具有良好的代码补全与调试功能。 “VS Code下载地址:https://code.visualstudio.com/” 下载 LLVM:用于代码补全,其实可以理解为 Clang。因为VS Code 中“C/C++”插件的自动补全功能不太好用。STM32中好多库函数都补全不出来。记得按照好之后,将路径添加到环境变量里。 “LLVM下载地址:http://releases.llvm.org/download.html” 下载安装 Git for Windows: 提供Git支持和MINGW64指令终端
[单片机]
使用VSCode搭建<font color='red'>STM32</font>开发环境
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved