STM32-NVIC中断优先级分组-中断优先级设置
2022-01-12 00:59 jym蒟蒻 阅读(3426) 评论(0) 编辑 收藏 举报STM32-中断优先级管理NVIC
NVIC的全称是Nested vectoredinterrupt controller,即嵌套向量中断控制器。STM32F中文参考手册中搜索向量表可以找到相应的中断说明。
CM4/CM7 内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。
STM32F4/F7并没有使用CM4内核的全部东西,而是只用了它的一部分。
STM32F40xx/STM32F41xx总共有92个中断。10个内核中断,82个可屏蔽中断。
STM32F42xx/STM32F43xx则总共有97个中断。10个内核中断,87个可屏蔽中断。
STM32F76x总共118个中断,10个内核中断,108个可屏蔽中断。
STM32具有16级可编程的中断优先级,而我们常用的就是这些可屏蔽中断。
几十个中断,怎么管理?
首先,对STM32中断进行分组,组0~4。同时,对每个中断设置一个抢占优先级和一个响应优先级值。
分组配置是在寄存器SCB->AIRCR中配置: IP bit[7:4]有4位,2^4=16,所以说它们的优先级可以有16个值,这时候如果是2位抢占优先级,那么它的值可能为0、1、2、3。也就是抢占优先级可以取0到3 。首先进行分组来决定几位抢占优先级、几位响应优先级。数越小它的优先级越高。
组 | AIRCR[10:8] | IP 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位响应优先级 |
抢占优先级 & 响应优先级区别:
高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。抢占决定了是否能打断别人。
抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
举例:
假定设置中断优先级组为2,然后设置
中断3(RTC中断)的抢占优先级为2,响应优先级为1。
中断6(外部中断0)的抢占优先级为3,响应优先级为0
中断7(外部中断1)的抢占优先级为2,响应优先级为0。
那么这3个中断的优先级顺序为:中断7>中断3>中断6。
一般情况下,系统代码执行过程中,只设置一次中断优先级分组,比如分组2,设置好分组之后一般不会再改变分组。随意改变分组会导致中断管理混乱,程序出现意想不到的执行结果。
中断优先级分组函数位于HALLIB中的stm32f7xx_hal_cortex.c:void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);
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);
}
可以找到IS_NVIC_PRIORITY_GROUP的定义,进而确定PriorityGroup参数怎么写。
#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))
在stm32f7xx_hal.c中可以找到HAL_Init函数:其中HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);可以看到中断分组为2 。
HAL_StatusTypeDef HAL_Init(void)
{
/* Configure Flash prefetch and Instruction cache through ART accelerator */
#if (ART_ACCLERATOR_ENABLE != 0)
__HAL_FLASH_ART_ENABLE();
#endif /* ART_ACCLERATOR_ENABLE */
/* Set Interrupt Group Priority */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
HAL_InitTick(TICK_INT_PRIORITY);
/* Init the low level hardware */
HAL_MspInit();
/* Return function status */
return HAL_OK;
}
分组设置好之后,怎么设置单个中断的抢占优先级和响应优先级?
中断设置相关寄存器:
_IO uint8_t IP[240]; //中断优先级控制的寄存器组
_IO uint32_t ISER[8]; //中断使能寄存器组
_IO uint32_t ICER[8]; //中断失能寄存器组
_IO uint32_t ISPR[8]; //中断挂起寄存器组
_IO uint32_t ICPR[8]; //中断解挂寄存器组
_IO uint32_t IABR[8]; //中断激活标志位寄存器组
位于core_cm7.h中:NVIC_Type结构体中成员变量就是那些寄存器。
/**
\brief Structure type to access the Nested Vectored Interrupt Controller (NVIC).
*/
typedef struct
{
__IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
uint32_t RESERVED0[24U];
__IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
uint32_t RSERVED1[24U];
__IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
uint32_t RESERVED2[24U];
__IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
uint32_t RESERVED3[24U];
__IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */
uint32_t RESERVED4[56U];
__IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */
uint32_t RESERVED5[644U];
__OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */
} NVIC_Type;
对于每个中断怎么设置优先级?
中断优先级控制的寄存器组:IP[240],全称是:Interrupt Priority Registers
240个8位寄存器,每个中断使用一个寄存器来确定优先级。STM32F40x系列一共82个可屏蔽中断,使用IP[81]~IP[0]。
每个IP寄存器的高4位用来设置抢占和响应优先级(根据分组),低4位没有用到。
在stm32f7xx_hal_cortex.c可找到:
/**
* @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 (stm32f7xxxx.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 = 0x00;
/* 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));
}
中断优先级设置步骤:
- 系统运行后在HAL_Init函数中设置中断优先级分组。调用函数:
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
//中断优先级分组2 整个系统执行过程中,只设置一次中断分组。 - 针对每个中断,设置对应的抢占优先级和响应优先级:
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t
PreemptPriority, uint32_t SubPriority); - 使能中断通道:
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Enable interrupt */
NVIC_EnableIRQ(IRQn);
}