stm32中断嵌套中先占优先级和从占优先级的理解
最近在使用STM32进行一些开发,外部中断一直是我困扰的一个问题,特别是中断嵌套中先占优先级和从占优先级的内容,更是让我头疼,今天查阅了一些资料,感觉有些收获,先写下来,一来可以让自己以后忘记的时候可以从新回忆,二来也是和大家分享。
先占优先级和从占优先级也被称为是抢占式优先级和响应优先级。首先ARM cortex_m3 内核支持 256 个中断(16 个内核+240 外部)和可编程 256 级中断优先级
的设置。而stm32保留了cortex_m3的部分中断,是cortex_m3的子集。STM32 目前支持的中断共为 84 个(16 个内核+68 个外部) ,和 16 级可编程中断优先级
的设置(仅使用中断优先级设置 8bit 中的高 4 位,见后面解释)。
对于 cortex_m3 内核所支持的 240 个外部中断,在这里我们要使用了“中断通道”这个概念,因为尽管每个中断对应一个外围设备,但该外围设备通常具备若干个可以引起中断的中断源或中断事件。而该设备的所有的中断都只能通过该指定的“中断通道”向内核申请中断。因此,下面关于中断优先级的概念都是针对“中断通道”的。当该中断通道的优先级确定后,也就确定了该外围设备的中断优先级,并且该设备所能产生的所有类型的中断,都享有相同的通道中断优先级。至于该设备本身产生的多个中断的执行顺序,则取决于用户的中断服务程序
回到优先级上来。具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套在低抢占式优先级的中断中。当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。
看了上面的介绍后,相信大家都明白了这里面的关系了,总结下便是:抢占式优先级>响应优先级>中断表中的排位顺序(其中“>”理解为比较的方向)。
正是因为每个中断源都需要被指定这两种优先级,就需要有相应的寄存器位记录每个中断的优先级;在Cortex-M3中定义了8个比特位用于设置中断源的优先级,这8个比特位可以有8种分配方式,如下:
1. 所有8位用于指定响应优先级
2. 最高1位用于指定抢占式优先级,最低7位用于指定响应优先级
3. 最高2位用于指定抢占式优先级,最低6位用于指定响应优先级
4. 最高3位用于指定抢占式优先级,最低5位用于指定响应优先级
5. 最高4位用于指定抢占式优先级,最低4位用于指定响应优先级
6. 最高5位用于指定抢占式优先级,最低3位用于指定响应优先级
7. 最高6位用于指定抢占式优先级,最低2位用于指定响应优先级
8. 最高7位用于指定抢占式优先级,最低1位用于指定响应优先级
以上便是优先级分组的概念,但是Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位,这4个寄存器位的分组方式如下:
第0组:所有4位用于指定响应优先级
第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级
第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级
第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级
第4组:所有4位用于指定抢占式优先级
这里便对于于文章最前提到的固件库里相关的函数了——NVIC_PriorityGroupConfig(u32 NVIC_PriorityGroup),函数的参数共有5种:
这个函数的参数(NVIC_PriorityGroup值)有下列5种:
NVIC_PriorityGroup_0 => 选择第0组
NVIC_PriorityGroup_1 => 选择第1组
NVIC_PriorityGroup_2 => 选择第2组
NVIC_PriorityGroup_3 => 选择第3组
NVIC_PriorityGroup_4 => 选择第4组
这其实也很好理解,比如选择NVIC_PriorityGroup_1,那么抢占式优先级便占一位,也就是说可以有2^1个级别,可以设置为0和1,而响应优先级则占3位,也就是说可以有2^3个选择,可以设置为0~7;
在利用void NVIC_PriorityGroupConfig(u32 NVIC_PriorityGroup)对优先级设置了以后,就可以用void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)函数对中断进行初始化。在函数中结构体参数
NVIC_InitTypeDef structure
NVIC_InitTypeDef定义于文件“stm32f10x_nvic.h”:
typedef struct
{
u8 NVIC_IRQChannel;
u8 NVIC_IRQChannelPreemptionPriority;
u8 NVIC_IRQChannelSubPriority;
FunctionalState NVIC_IRQChannelCmd;
} NVIC_InitTypeDef;
NVIC_IRQChannelPreemptionPriority:就用于选择抢占式优先级,如果当初NVIC_PriorityGroup_1 => 选择第1组,那么NVIC_IRQChannelPreemptionPriority的值就可以为0和1,如果当初NVIC_PriorityGroup_2 => 选择第2组,那么NVIC_IRQChannelPreemptionPriority的值就可以为0、1、2和3。
NVIC_IRQChannelSubPriority: 用于选择响应式优先级,如果如果当初NVIC_PriorityGroup_1 => 选择第1组,那么NVIC_IRQChannelSubPriority的值就可以为0到7之间的一个值。
最后附上固件库的例子加以参照就可以更好地理解:
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the Priority Grouping with 1 bit */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* Enable TIM3 global interrupt with Preemption Priority 0 and Sub
Priority as 2 */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure(&NVIC_InitStructure);
/* Enable USART1 global interrupt with Preemption Priority 1 and Sub
Priority as 5 */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
NVIC_InitStructure(&NVIC_InitStructure);
/* Enable RTC global interrupt with Preemption Priority 1 and Sub
Priority as 7 */
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;
NVIC_InitStructure(&NVIC_InitStructure);
/* Enable EXTI4 interrupt with Preemption Priority 1 and Sub
Priority as 7 */
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;
NVIC_InitStructure(&NVIC_InitStructure);
/* TIM3 interrupt priority is higher than USART1, RTC and EXTI4
interrupts priorities. USART1 interrupt priority is higher than RTC
and EXTI4 interrupts priorities. RTC interrupt priority is higher
than EXTI4 interrupt prioriy. */