NVIC简介:
其除了是熟知的嵌套向量中断控制器外,还包括Systick定时器和MPU
NVIC功能:
中断在使用前应当先对其进行分组设置(确定抢占优先级和亚优先级的位数),原则就是根据当前系统方案的实际使用情况进行设定,比如当前系统一共使用了多少中断,对其进行优先级评估。众所周知,Cortex-M3使用8位来表达优先级,分为抢占优先级和亚优先级,所以其最对支持256种不同的优先级;但是亚优先级至少占据1位。只要在下图寄存器中PRIGROUP中设置对应的值即完成优先级组的设置,比如将其设置成5,即表示5位抢占优先级,3位亚优先级。
ARM官方提供的库函数如下:
static __INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
uint32_t reg_value;
uint32_t PriorityGroupTmp = (PriorityGroup & 0x07); /* only values 0..7 are used */
reg_value = SCB->AIRCR; /* read old register configuration */
reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk); /* clear bits to change */
reg_value = (reg_value |
(0x5FA << SCB_AIRCR_VECTKEY_Pos) |
(PriorityGroupTmp << 8)); /* Insert write key and priorty group */
SCB->AIRCR = reg_value;
}
上面的设置中仅仅需要调用函数
NVIC_SetPriorityGrouping(5);
但是一般的Cortex-M3内核的芯片不是有8位优先级,一般都小于8,比较典型的是ST的芯片,例如STM32F103为4位(高4位),所以其最多支持16种不同的优先级。设置该芯片的优先级组时,假如需要设置3位表示枪占优先级,1位表示亚优先级,调用函数
NVIC_SetPriorityGrouping(4);
上述优先级的设置对于异常一样有效,需要注意的是复位;NMI;HardFault优先级已经固定好了,不能修改。其均为负数,说明其优先级是最高的
下面介绍下中断和异常优先级配置和使用注意事项
中断
1:中断配置
- 中断使能与除能:打开关闭中断
- 中断优先级:配置中断的优先级
2:中断注意事项
- 中断的悬起与解悬:中断发生时,正在处理同级或高优先级异常,或者被掩蔽,则中断不能立即得到响应,此时中断被悬起。可以通过查询该寄存器判断当前系统中还未执行的中断,同时可以手动悬起和解悬以达到置起中断和清除中断的目的。
- 中断活动状态:只有CPU执行了该中断服务函数的第1条指令后,中断对应的活动状态位才会被置位为1,直到该中断服务函数被执行完 返回时才会清0。可以通过结合悬起和解悬寄存器综合判断中断运行的状态。
- 软件触发中断:通过软件的方式触发中断的产生,详见下面的步骤
异常
1:异常配置:
- 异常使能与除能
- 异常优先级:
2:异常注意事项:
- 异常的悬起与解悬,异常的活动状态:
- 异常软件触发
通过上面可以发现中断和异常有相似的操作。
特殊功能寄存器Basepri
设置函数如下:
static __INLINE void __set_BASEPRI(uint32_t basePri)
{
register uint32_t __regBasePri __ASM("basepri");
__regBasePri = (basePri & 0xff);
}
这个函数的目的就是将优先级大于basePri的中断或异常屏蔽,但是有个问题basePri怎么设置?
basePri的设置依赖于当前优先级组的设置,假设STM32F103的例子我们将优先级组设置为3个抢占优先级,1个子优先级。
问题:将优先级大于3的中断或异常屏蔽掉。
方法:
根据优先级组设置可知最高3位表示抢占优先级,所以Basepri的最高3位才是有意义的,通过下面的设置即可,其中5表示将3左移动5位,使得高3位的值为3。
__set_BASEPRI(0x3<<5)
特殊功能寄存器Primask
用于将NMI 和硬 fault 之外的所有异常和中断屏蔽掉
特殊功能寄存器Faultmask
用于将NMI之外的所有异常和中断屏蔽掉
注:以上参考Cortex-M3权威之南