1.中断抢占(嵌套)简述
中断抢占的优先级条件可分为两种: - 当中断优先级阈值未使能时,中断抢占的优先级必须高于当前 CPU 正在处理的中断的优先级;同级优先级不能进行抢占。(对应3.1小节的示例) - 当中断优先级阈值使能时,中断抢占的优先级不仅要高于当前 CPU 正在处理的中断优先级,而且要高于中断优先级阈值寄存器设置的阈值。 VIC 支持中断优先级的动态调整,当被嵌套的中断优先级需要调高或者调低时,在设置中断优先级设置寄存器的同时设置中断优先级阈值寄存器。(对应3.2小节的示例)
详细内容请查看使用手册。
2.汇编源码的解释
2.1 汇编源码
如下图所示,在每一个中断函数的开头都会有NIE指令,来使能中断嵌套,而结尾都会有配套的中断嵌套返回指令。
2.2 NIE和NIR指令说明
NIE——中断嵌套使能指令
将中断的控制寄存器现场{EPSR, EPC }保存到堆栈存储器中,然后更新堆栈指针寄存器到堆栈指针存储器的顶端,打开中断和异常使能位 PSR.IE 和PSR.EE。采用堆栈指针寄存器直接寻址方式。
NIR——中断嵌套返回指令
从堆栈存储器中载入中断的现场到{EPSR, EPC }中,然后更新堆栈指针寄存器到堆栈存储器的顶端; PC 值恢复为控制寄存器 EPC 中的值, PSR 值恢复为 EPSR 的值,指令执行从新的 PC 地址处开始。采用堆栈指针寄存器直接寻址方式
3.中断抢占(嵌套)的实例
按照示例的说明,配置好四个相关的中断,本示例用的中断是GPTA 和GPTB:
中断优先级设置为: GPTA0 < GPTA1 < GPTB0 < GPTB1
中断源请求产生的顺序为: GPTA0 > GPTA1 > GPTB0 > GPTB1
为了演示,在该四个中断里都加了相同的delay,让抢占更容易控制。IO的上升沿指示中断的进入和用IO的下降沿指示退出,高电平持续时间代表中断函数的执行时间。
定时器的配置
csi_gpta_timer_init(GPTA0, 20000); //初始化GPTA0, 定时20000us; GPTA定时,默认采用向上计数,PEND中断
csi_gpta_timer_init(GPTA1, 20200); //初始化GPTA1, 定时20200us; GPTA定时,默认采用向上计数,PEND中断
csi_gptb_timer_init(GPTB0, 20400); //初始化GPTB0, 定时20400us; GPTB定时,默认采用向上计数,PEND中断
csi_gptb_timer_init(GPTB1, 20600); //初始化GPTB1, 定时20600us; GPTB定时,默认采用向上计数,PEND中断
csi_vic_set_prio(GPTA0_IRQ_NUM,3);
csi_vic_set_prio(GPTA1_IRQ_NUM,2);
csi_vic_set_prio(GPTB0_IRQ_NUM,1);
csi_vic_set_prio(GPTB1_IRQ_NUM,0);
3.1 正常的中断抢占(嵌套)
按照手册的说明,在GPTB0的中断里不配置VIC->IPTR,则理论上应该是先进入GPTA0 中断,然后GPTA1抢占GPTA0 中断,然后GPTB0抢占GPTA1中断,最后GPTB1抢占GPTB0中断,然后按照抢占顺序依次退出中断。
如果没有发生抢占,则每一个中断处理函数执行的时间应该差不多;
如果抢占发生则优先级最高的中断处理时间最少,最低的执行时间最长。
实际的IO口效果如下图所示:
从图中可以看出与预期的结果一致。
3.2 低优先级中断执行过程中不被抢占的方法
如果想低优先级的中断不想被抢占则可以通过配置VIC->IPTR寄存器来实现。
示例在正常的中断抢占(嵌套)中断例子的GPTB0中断处理函数里配置了VIC->IPTR寄存器,配置如下:
VIC->IPTR = (0x1<<31) | (0x29<< 8) | (0 << 6);
使能了中断抢占需要优先级高于阈值为且中断抢占的优先级阈值设置为0,优先级阈值对应的中断向量号设置为GPTA0.
VIC-IPTR的寄存器说明如下 :
则按照手册说明,因为抢占的优先级为0,所以在进入GPTB0中断函数,并配置了VIC->IPTR后,GPTB1就不能在抢占,要GPTA0中断函数执行完后再响应GPTB1中断。下图就是配置VIC->IPTR寄存器后的的IO口的输出波形图:
从图中可以看出,与预期的效果是一致的。