注:本文以stm32G431为例。
NVIC简介
NVIC即嵌套向量中断控制器(Nested Vectored Interrupt Controller)。STM32的中有一个强大而方便的NVIC,它是属于CM4内核的器件。NVIC 控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对CM4内核里面的NVIC进行裁剪,把不需要的部分去掉,所以说STM32的NVIC是CM4的NVIC的一个子集。
NVIC寄存器定义在core_cm4.h文件中,CM4内核支持256个中断,其中包含了16个系统异常和240个外部中断,并且具有256级的可编程中断设置。但 STM32并没有使用CM4内核的全部东西,而是只用了它的一部分。 stm32G431芯片有111个中断,包括9个内核中断和102个可屏蔽中断,具有16级可编程的中断优先级,我们常用的就是这102个可屏蔽中断。
我们可以在stm32G431参考手册的14.3查到该芯片的中断向量表。
![图片[1]-基于stm32HAL库浅析NVIC中断系统](https://www.r6b.cn/wp-content/uploads/2022/01/13t01-1024x598.jpg)
中断优先级
Cortex-M4优先级支持3个固定的高优先级和多达256级的可编程优先级,支持128级抢占。每个中断的优先级由一个8位的寄存器来设定,分为高低两个位段。高位段表示抢占优先级,低位段表示响应(子)优先级。 CM4允许最少使用位数为3个位,即至少要支持8级优先级。STM32只用了中断优先级寄存器的高4位。
中断优先级分组
STM32中有两个优先级的概念:抢占式优先级和响应优先级,响应优先级也称子优先级,每个中断源都需要被指定这两种优先级。具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套在低抢占式优先级的中断中。当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断向量表中的排位顺序决定先处理哪一个。
STM32 将中断分为 5 个组,组 0~4。该分组的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。具体分配关系如下表:
组 | AIRCR[10:8] | bit[7:4]分配情况 | 分配结果 |
0 | 111 | 0: 4 | 0 位抢占优先级,4 位响应优先级 |
1 | 110 | 1: 3 | 1 位抢占优先级,3 位响应优先级 |
2 | 101 | 2: 2 | 2 位抢占优先级,2 位响应优先级 |
3 | 100 | 3: 1 | 3 位抢占优先级,1 位响应优先级 |
4 | 011 | 4: 0 | 4 位抢占优先级,0 位响应优先级 |
NVIC相关函数
中断优先级分组函数
void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);
形参选择:
NVIC_PRIORITYGROUP_0:0位抢占式优先级,4位响应优先级
NVIC_PRIORITYGROUP_1:1位抢占式优先级,3位响应优先级
NVIC_PRIORITYGROUP_2:2位抢占式优先级,2位响应优先级
NVIC_PRIORITYGROUP_3:3位抢占式优先级,1位响应优先级
NVIC_PRIORITYGROUP_4:4位抢占式优先级,0位响应优先级
中断优先级设置函数
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority);
HAL_NVIC_SetPriority函数用于设置一个中断的优先级,它有三个形参,第一个为IRQn_Type类型参数,指定中断源。第二个和第三个形参分别设定中断的抢占式优先级和响应优先级。HAL_NVIC_SetPriority函数实际是调用定义在core_cm4.h文件的NVIC_SetPriority函数实现功能的,该函数通过设置SCB_SHP寄存器或者NVIC_IPRx寄存器实现功能。
中断使能函数
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
HAL_NVIC_EnableIRQ函数用于在NVIC控制器中使能指定中断,它有一个形参,是IRQn_Type类型参数。HAL_NVIC_EnableIRQ函数实际是通过调用定义在core_cm4.h文件中的NVIC_EnableIRQ函数实现功能,NVIC_EnableIRQ函数设置了NVIC_ISER寄存器内容。
中断禁用函数
void HAL_NVIC_DisableIRQ(IRQn_Type IRQn);
HAL_NVIC_DisableIRQ函数是在NVIC控制器中禁用指定中断,用法与HAL_NVIC_EnableIRQ函数相同。最终通过设置NVIC_ICER寄存器值实现功能。
中断复位函数
void HAL_NVIC_SystemReset(void);
HAL_NVIC_SystemReset函数用于初始化一个MCU复位要求,它调用NVIC_SystemReset函数实现功能。