【STM32】HAL库-嵌套向量中断控制器NVIC
2022-06-16 来源:eefocus
中断与异常
嵌套向量中断控制器,简称为NVIC,其支持为数众多的系统异常和外部中断。
Cortex-M3支持256个中断。
中断/异常类型表如下
编号为 1-15 的称为系统异常(注意:没有编号为 0 的异常),大于等于 16 的称为(外部)中断。
除了个别异常的优先级被定死外,其它中断/异常的优先级都是可编程的


外部中断表如下

优先级
在 CM3 中,优先级对于异常来说很关键的,它会决定一个异常是否能被掩蔽,以及在未掩蔽的情况下何时可以响应。优先级的数值越小,则优先级越高。
CM3 支持中断嵌套,使得高优先级异常会抢占(preempt)低优先级异常。
有3个系统异常的优先级是固定的,并且是负数,分别为:复位,NMI 以及硬 fault
所有其它异常的先级则都是可编程的((但不能被编程为负数)
CM3 支持 3 个固定的高优先级(复位,NMI 以及硬 fault)和多达 256 级的可编程优先级,并且支持 128 级抢占式优先级
256级对应一个字节的大小,8位二进制,也就是每一个可编程的中断/异常有一个至少一个字节大小的寄存器来配置其优先级。并且是以 MSB 对齐的。
CM3 允许的最少使用位数为 3 个位,亦即至少要支持 8 级优先级
如使用3个位来定义优先级,则只有最高3位有效。

优先级 优先级设置寄存器的值

优先级分组
为了使抢占机能变得更可控,CM3 还把 256 级优先级按位分成高低两段,分别称为抢占优先级和子优先级
通过应用程序中断及复位控制寄存器(AIRCR)地址:0xE000_ED00来设置抢占式优先级与子优先级占用的位数。


PRIGROUP的取值

子优先级至少是 1 个位。因此抢占优先级最多是 7 个位,造成了最多只有 128 级抢占的现象。
如使用最高3位来表达优先级,优先级分组选择5,则抢占式优先级用2个位表达,剩下的一个位则是子优先级。

使用最高3位来表达优先级,优先级分组选择1,则抢占式优先级占用3位,子优先级无效

如果两个中断的抢占式优先级和子优先级都相同,则先响应异常编号最小的那一个,例如,当 IRQ #3 的优先级与 IRQ #5 的优先级相等时,IRQ #3 会比 IRQ #5 先得到响应。
向量表
当发生中断或者异常时,需要定位其服务例程的入口地址(中断复位函数的入口地址)这些入口地址存储在所谓的“向量表”中。
也就是说向量表存储的是一个个函数的地址。默认情况下,,CM3 认为该表位于零地址处,且各向量占用 4 字节。

CM3支持动态重分发中断,CM3 允许向量表重定位——从其它地址处开始定位各异常向量。
为了实现这个功能,NVIC 中有一个寄存器,称为“向量表偏移量寄存器”(在地址 0xE000_ED08 处),通过修改它的值就能重定位向量表。

中断的触发与悬起(挂起)
当中断发生时候,该中断就被悬起。即使后来中断源撤消了中断请求,
已经被标记成悬起的中断也被记录下来。到了系统中它的优先级最高的时候,就会得到响应
悬起被置位:告诉CPU,有一个中断触发了,当该中断优先级最高时候,CPU将会根据向量表找到中断服务函数的入口地址,从而处理中断,当某中断的服务例程开始执行时,就称此中断进入了“活跃”状态,并且其悬起位会被硬件自动清除。

但是如果在某个中断得到响应之前,其悬起状态被清除了,则中断被取消。

如果中断源咬住请求信号不放,该中断就会在其上次服务例程返回后再次被置为悬起状态

Fault 类异常
CM3 中的 Faults 可分为以下几类:
总线 faults
存储器管理 faults
用法 faults
每个faults都有其对应的faults状态寄存器,用来指示出错的原因与类型。
更多细节请看CM3权威指南。
NVIC
嵌套向量中断控制器(NVIC)
NVIC 的访问地址是 0xE000_E000。所有 NVIC 的中断控制/状态寄存器都只能在特权级下访问,仅软件触发中断寄存器可以在用户级下访问以产生软件中断。
每个外部中断都有在 NVIC 的下列寄存器
使能与除能(失能)寄存器
悬起与“解悬”寄存器
优先级寄存器
活动状态寄存器(中断是否正在被CPU响应)
使能与除能(失能)寄存器
SETENA(使能)/CLRENA(失能) 可以按字/半字/字节的方式来访问
32 位寄存器,写1使能/失能,写0无效
CM3 中可以有 240 对使能位/除能位(SETENA 位/CLRENA 位),每个中断拥有一对。这 240 个对子分布在 8 对 32 位寄存器中(最后一对没有用完)

悬起与解悬寄存器
如果中断发生时,正在处理同级或高优先级异常,或者被掩蔽,则中断不能立即得到响应。此时中断被悬起。
中断的悬起状态可以通过“中断设置悬起寄存器(SETPEND)”和“中断悬起清除寄存器(CLRPEND)”来读取,还可以写它们来手工悬起中断。
其用法与前面介绍的使能/除能寄存器完全相同

中断优先级寄存器
每个外部中断都有一个对应的优先级寄存器,每个寄存器占用 8 位。
优先级寄存器都可以按字节访问,当然也可以按半字/字来访问
根据优先级组的设置,优先级可以被分为高低两个位段,分别是抢占优先级和亚优先级,
通过应用程序中断及复位控制寄存器(AIRCR)地址:0xE000_ED00来设置抢占式优先级与子优先级占用的位数。

系统异常的优先级设置

活动状态
每个外部中断都有一个活动状态位。在处理器执行了其 ISR(中断服务函数) 的第一条指令后,它的活动位就被置 1,并且直到 ISR 返回时才硬件清零。
哪怕中断被抢占,其活动状态也依然为 1。
按字/半字/字节访问,但是只读的
软件中断
软件触发中断请求

STM32的中断
以STM32F103C8T6为例
68个可屏蔽中断通道(不包含16个Cortex™-M3的中断线);
16个可编程的优先等级(使用了4位来表示中断优先级);

下面介绍HAL库的常用中断相关函数
其他的函数请查看stm32f1xx_hal_cortex.c文件
中断优先级分组
/**
* @brief Sets the priority grouping field (preemption priority and subpriority)
* using the required unlock sequence.
* @param PriorityGroup: The priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PRIORITYGROUP_0: 0 bits for preemption priority
* 4 bits for subpriority
* @arg NVIC_PRIORITYGROUP_1: 1 bits for preemption priority
* 3 bits for subpriority
* @arg NVIC_PRIORITYGROUP_2: 2 bits for preemption priority
* 2 bits for subpriority
* @arg NVIC_PRIORITYGROUP_3: 3 bits for preemption priority
* 1 bits for subpriority
* @arg NVIC_PRIORITYGROUP_4: 4 bits for preemption priority
* 0 bits for subpriority
* @note When the NVIC_PriorityGroup_0 is selected, IRQ preemption is no more possible.
* The pending IRQ priority will be managed only by the subpriority.
* @retval None
*/
void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup));
/* Set the PRIGROUP[10:8] bits according to the PriorityGroup parameter value */
NVIC_SetPriorityGrouping(PriorityGroup);
}
设置中断的抢占式优先级与子优先级
/**
* @brief Sets the priority of an interrupt.
* @param IRQn: External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xx.h))
* @param PreemptPriority: The preemption priority for the IRQn channel.
* This parameter can be a value between 0 and 15
* A lower priority value indicates a higher priority
* @param SubPriority: the subpriority level for the IRQ channel.
* This parameter can be a value between 0 and 15
* A lower priority value indicates a higher priority.
* @retval None
*/
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)
{
uint32_t prioritygroup = 0x00U;
/* Check the parameters */
assert_param(IS_NVIC_SUB_PRIORITY(SubPriority));
assert_param(IS_NVIC_PREEMPTION_PRIORITY(PreemptPriority));
prioritygroup = NVIC_GetPriorityGrouping();
NVIC_SetPriority(IRQn, NVIC_EncodePriority(prioritygroup, PreemptPriority, SubPriority));
}
使能中断
/**
* @brief Enables a device specific interrupt in the NVIC interrupt controller.
* @note To configure interrupts priority correctly, the NVIC_PriorityGroupConfig()
* function should be called before.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h))
* @retval None
*/
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Enable interrupt */
NVIC_EnableIRQ(IRQn);
}
失能中断
/**
* @brief Disables a device specific interrupt in the NVIC interrupt controller.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h))
* @retval None
*/
void HAL_NVIC_DisableIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Disable interrupt */
NVIC_DisableIRQ(IRQn);
}
清除中断的挂起位
/**
* @brief Clears the pending bit of an external interrupt.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h))
* @retval None
*/
void HAL_NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Clear pending interrupt */
NVIC_ClearPendingIRQ(IRQn);
}
STM32CubeMX中的中断优先级配置
- 意法半导体中国本地造STM32微控制器启动规模量产
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 基于机智云与STM32的智能拐杖安全监测系统在养老物联网中的应用
- 内置全栈安全,一站式满足CRA法案与IEC 62443标准——米尔STM32MP257核心板
- 如何用 STM32 FLASH 实现等效 100 万次擦写的 EEPROM 功能?
- 实战解析:通过一个小项目掌握STM32所有外设
- STM32学了两年半,却还是不会做项目
- 意法半导体推出最新STM32MP21微处理器,兼具高性价比、低功耗、高灵活性
- 基于STM32的矿井作业环境监测系统设计与实现
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析
- 意法半导体中国本地造STM32微控制器启动规模量产
- 蓝牙信道探测技术原理与开发套件实践






