最近思来想去,觉得需要技术沉淀,于是我注册了个微信公众号(airX嵌入式),这也是为我后续创业公司做准备,
一来能分享记录我的开发项目,以及开源一切设计;二来能结识更多的同道中人!有机会可以合作创业!
微信扫码关注我!(airX嵌入式)
1、什么是NVIC?
来自《CM3技术参考手册》的官方资料回答:
即嵌套向量中断控制器(Nested Vectored Interrupt Controller)。
说白了NVIC的功能就是中断优先级分组、中断优先级的配置、读中断请求标志、清除中断请求标志、使能中断、清除中断等,它控制着STM32中断向量表中的中断相关功能!!。
上面的240个中断是CM3内核对外的外部中断最大支持数量,内核本身还有16个中断,称为异常中断,所以严格来讲CM3有256个中断,虽然都能归为中断,但他们之间有本质的区别,外部中断是指系统停止当前正在运行的程序转而其他服务,可能是程序接收了比自身高优先级的请求,或者是人为设置中断,中断是属于正常现象;而异常中断是指由于cpu本身故障、程序故障或者请求服务等引起的错误,异常属于不正常现象。
在《CM3技术参考手册》第5章中有列出该16个中断。
2、知道NVIC后,那我们如何去管理这些中断呢?
要想理解stm32的中断管理,必须要先从stm32的 中断优先级分组开始说起。要理解中断优先级分组,就要先理解什么是 先占优先级 和 次占优先级。先占优先级的概念等同于单片机中的常规中断。假设有两中断先后触发,已经在执行的中断先占优先级如果没有后触发的中断 先占优先级更高,就会先处理先占优先级高的中断。也就是说又有较高的先占优先级的中断可以打断先占优先级较低的中断。这是实现中断嵌套的基础。
次占优先级只在同一先占优先级的中断同时触发时起作用,先占优先级相同,则优先执行次占优先级较高的中断。次占优先级不会造成中断嵌套。 如果中断的两个优先级都一致,则优先执行位于中断向量表中位置较高的中断。
那么优先级数量有多少呢?这就涉及了优先级分组的概念。stm32 通过一个中断向量控制器(NVIC)中的寄存器PRIGROUP来分配先占优先级和次占优先级的数量。
arm cortex-m3 内核中拥有一个3位宽度的的PRIGROUP数据区,用来指示一个8位数据序列中的小数点的位置从而表示中断优先级的分组。
来自《CM3技术参考手册》
举个例子可以更好的理解: 如果PRIGROUP数据位000 ,即为0, 说明8位数据序列中小数位置在第1位的左边为xxxxxxx.y,用于表示中断优先级的分组的含义就是用7位的数据宽度来表示先占优先级的数量即为128;用1位的数据宽度来表示次占优先级数量即为2;这样总的就有128*2 = 256个优先级;
所以arm cortex-m3中有2的三次方即为8个优先级分组 。
3、STM32F10中的中断配置!
首先STM32F103系列的有16个内核中断(异常)和60个中断:
来自《STM32中文参考手册》
在中断向量表中从优先级7-66(中断号从0-59)代表着STM32F103的60个中断。优先级号越小,优先级越高。当表中的某处异常或中断被触发,程序计数器指针(PC)将跳转到该异常或中断的地址处执行,该地址处存放这一条跳转指令,跳转到该异常或中断的服务函数处执行相应的功能。因此,异常和中断向量表只能用汇编语言编写。
在MDK中,有标准的异常和中断向量表文件可以使用(startup_stm32f10x_hd.s),在其中标明了中断处理函数的名称,不能随意定义。而中断通道NVIC_IRQChannel(即IRQn_Type类型)是在stm32f10x.h文件中进行了宏定义。
stm32f10中只有5个优先级分组,我们从库函数配置代码可以看出,在misc.h中
意味着只有5bit让我们配置中断优先级;就是只用了上面的PRIGROUP寄存器8bit中的5bit!这个跟芯片型号有关!
那这样的所有配置组合如下图:
4、stm32f10的中断库函数配置说明
我们对软件的要求是上电配置,而且整个软件只配置一次!不能修改,所以上电配置正确的中断是必须的!
A、首先中断优先级分组库函数
STM32f0的中断优先级分组函数NVIC_PriorityGroupConfig(),用来进行中断分组设置的,此函数是在固件库下misc.c文件中
以及参数配置,在misc.h中;
B、分组设置好了之后,怎么设置单个中断的抢占优先级和响应优先级?
这里使用NVIC_Init()函数来进行对每个中断优先级的设置(misc.c文件中):
我们主要分析一下传入的结构体参数
NVIC_InitTypeDef结构体有4个成员变量:
NVIC_IRQChannel //定义初始化的是哪一个中断,这个可以在stm32f10x.h文件中查到每个中断对应的名字,如USART1_IRQn;
NVIC_IRQChannelPreemptionPriority //定义此中断的抢占优先级别;
NVIC_IRQChannelSubPriority //定义此中断的响应优先级别;
NVIC_IRQChannelCmd //该中断是否使能。
所以我们只需如下配置好,调用即可!
void NvicConfig(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStruct.NVIC_IRQChannel=TIM4_IRQn; //TIM4中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级0
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1; //子优先级1
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能TIM4中断通道
NVIC_Init(&NVIC_InitStruct); //中断优先级初始化函数
}
5、总结与分析
最后总结一下软件中断优先级设置的步骤:
1、系统运行后先设置中断优先级分组。调用函数:
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
整个系统执行过程中,只设置一次中断分组;
2、针对每个中断,设置对应的抢占优先级和响应优先级:
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
3、如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。
微信扫码关注我!(airX嵌入式)