Cortex-M中断优先级抢占及嵌套

最初从M4系列的K60上手,由于K60的现成第三方库已经非常完善了,所以没有考虑过深入研究内核的架构(其实只是恐于庞大的数据手册的借口而已(;д;)),如今上手KEA自己搭建底层驱动库时,便不得不考虑中断的优先级是如何配置的了。

对于中断优先级配置的需求实际上主要体现在系统存在多个可能的中断源情况下,这时为了保证代码的可靠执行,我们不得不考虑很现实的两个问题,一个是如果两个以上中断同时发生,pending请求到CPU,CPU决策该先进哪一个相应的中断服务Routine,第二个问题是CPU当前已经在响应某个中断服务,此时来了另一个中断请求,是否允许其打断当前中断服务转而响应新的中断请求即我们常说的中断嵌套问题。中断优先级管理属于内核问题,所以这方面的信息你不会在各大半导体厂家的官方手册中找到,我们只能追根溯源直接到内核的老家ARM官网去找,但官网信息太冗杂了,其实ARM的很多资料可以在这里找:https://developer.arm.com/

对于不同的内核架构,中断优先级管理方式自然是不同的,虽然都是NVIC和SCB两个寄存器来管理,但深层的架构却有很大的不同,我们暂且只说明M0+架构的中断优先级配置。

首先我们可以在上述的网址内搜索Cortex-M0+,可以看到下图所示的架构,得知M0+系列采用的是ARM V6的架构。

对于ARMV6的手册,可以在上面给出的arm developer网址内搜索:ARMv6-M Architecture Reference Manual Documentation

ARM的中断源分为内核中断和IRQ中断,对IRQ的中断管理是由NVIC来主导的,内核的中断管理则是由SCB来主导的,我们先讲IRQ中断的优先级问题(关于中断使能和禁能不在本篇讨论范围内哈)

搜索NVIC,可以找到NVIC_IPRn,用于配置中断优先级的寄存器,在这里我们看到这样一张表格:

NVIC_IPR一共有8个寄存器,而每个寄存器管理4个IRQ中断,我们就明白了为啥M0+的IRQ中断源最多只支持32个了,再加上16个内核中断,也就是说M0+最多就是48个中断源,所以M0+架构还不算复杂,算是比较好理解的了。

回过来看KEA的寄存器映像,可以看到IRQ确实只有32的中断源。

到KEA的数据手册中我们可以看到,NVIC寄存器编号已经分配好了

优先级寄存器里面的配置值越低表明相应的中断优先级越高,每个PRIxx的8位中只有最高两位有效,也就是说实际上M0+的优先级只有四个即0,1,2,3。其余位均为只读位(RAZ/WI表示Read All Zero/Write Ignore)。

(上图在M0+的开发手册中截取,而非ARM v6手册)

至于嵌套的问题,对M0+是比较简单的,即只要相应中断的优先级比较高即可随时抢占比它优先级低的中断服务。至于内核中断,其中断优先级则由SCB模块的SCB_SHPR寄存器来管理如下图所示,实际上我们平时常用的就是systemtick中断,其优先级配置同NVIC,这里就不赘述了。另外,需要注意的是,该寄存器还具有 word-accessible的属性,也就是说这几个寄存器都只能按字操作,切记不要为了显示我们的编程技巧而使用指向字节的指针只对某个单独中断的优先级进行配置。

那么有一个问题出现了,只有四个优先级显然不够分配那么多的中断源,而这也是M0系列的局限,M4中做出了更好的中断优先级管理,可见后文。

如果我们不对优先级进行配置的话,所有优先级默认都为0;如果优先级相同的中断同时发生,则默认相应中断源的向量号越低其优先级越高。因此如果希望中断向量表中位号较靠后的中断优先级较高,则需要将之前的中断配置为较低的优先级才可(如果中断很多是不是非常麻烦!幸好ARM公司也意识到了这些问题并推出了更新的ARM架构v7和v8)。

ARM其实已经将这部分的函数API列出来了(core_cm0plus.h)设置中断优先级可以如下:NVIC_SetPriority(PORTA_IRQn, 1);

 

 

对于Cortex-M4,虽然指令集是向下兼容M0+的,但是在中断优先级管理上是有区别的,由于M4的中断源比较多(最多允许256),所以其对中断优先级管理是略有些复杂的。数据手册可以以文末形式查找,在此不另贴图,大致与上述类似。

M4最高支持16+4*60=256个中断源,这60个寄存器是可以按字节操作的,值越小优先级越高,每个寄存器的8位数据都是可以定义其中断优先级了。但并不是说M4的优先级最高可以256个级别,PRIGROUP定义了这8位数据到底该怎么用。在M4内核中,其对中断优先级管理是分了两个部分,一个是组优先级一个是子优先级,即组优先级是管理抢占优先级的(即是否能嵌套),即高的组优先级中断(数值低)可以抢占低的组优先级(数值高)中断的,而如果组优先级是一样的,即使子优先级比正在执行的中断的子优先级高也是不能抢占的。在组优先级一致的情况下,多个中断请求同时发生,这样的情况下子优先级高的可以先执行的,而子优先级低的则只能暂时pending等着了。

而回到PRIGROUP的作用是用来配置NVIC的8位数据域是如何分配给抢占优先级和子优先级的,而一般情况下,最好是各留4位,即组优先级和子优先级分别最多可配16个优先级,而PRIGROUP是从哪来的呢?实际上它是SCB_AIRCR寄存器的其中3位如图所示。


对于M4系列的中断优先级配置示例如下:

NVIC_SetPriorityGrouping(0x03);

NVIC_SetPriority(PORTA_IRQn, NVIC_EncodePriority(0x03,1, 2));

NVIC_SetPriority(PORTB_IRQn, NVIC_EncodePriority(0x03, 2, 2));

 

附:以上所有资料来源:

我也将其下载放在了网盘中

链接:https://pan.baidu.com/s/12fbR1WlKhPD2M6w9diGoTg 密码:hk2c

2 thoughts on “Cortex-M中断优先级抢占及嵌套

留下评论