4. 中断优先级:硬件优先级与软件优先级、优先级仲裁机制、优先级嵌套规则
中断优先级,说白了就是给中断排个队。谁更重要,谁先处理。
我刚开始做DSP开发那会儿,觉得优先级嘛,不就是数字大的先跑?结果项目一复杂,各种中断互相打断,系统直接乱套。后来才明白,这里面的门道深着呢。
4.1 硬件优先级 vs 软件优先级
DSP里有两套优先级系统。一套是芯片出厂就定死的,叫硬件优先级。另一套是我们程序员可以改的,叫软件优先级。
硬件优先级,是芯片设计时就焊死的。比如TI的C2000系列,复位中断永远是最高优先级,NMI(不可屏蔽中断)排第二。这个你改不了,也别想改。我见过有人试图绕过硬件优先级,结果系统直接崩溃——嗯,别这么干。
软件优先级,才是我们真正能玩出花的地方。通过中断控制寄存器,我们可以给每个中断源分配一个优先级数值。比如在C28x内核里,有专门的PIE(外设中断扩展)模块,它允许我们把多个外设中断映射到不同的CPU中断上。
核心区别:
- 硬件优先级:芯片固定,不可更改。用于复位、NMI等关键中断。
- 软件优先级:可编程配置。用于普通外设中断,如定时器、ADC、串口等。
举个例子。我做过一个电机控制项目,电流环中断要求极低的延迟,而通信中断可以慢一点。硬件上,电流环和通信中断可能挂在同一个CPU中断线上。这时候,我就得靠软件优先级来区分:把电流环的软件优先级设高,通信的设低。这样,即使它们同时触发,电流环也能先跑。
4.2 优先级仲裁机制
多个中断同时来了,谁先上?这就是仲裁机制要干的事。
DSP的仲裁机制,我总结为三步走:
- 第一步:硬件优先级初筛。所有中断先按硬件优先级排个序。硬件优先级高的,直接进入下一轮。硬件优先级低的,先靠边站。
- 第二步:软件优先级定胜负。如果硬件优先级相同(比如都挂在同一个CPU中断线上),那就看软件优先级。数值越小,优先级越高(不同DSP可能相反,记得查手册)。
- 第三步:固定优先级兜底。如果软件优先级也相同,那就看中断向量号。向量号小的先处理。这是最后的保底方案。
我用一个流程图来展示这个过程,你一看就明白:
我的经验:实际项目中,90%的冲突都发生在软件优先级这一层。硬件优先级基本不会打架,因为芯片设计时已经考虑得很周全了。你真正需要花心思的,是合理分配软件优先级。
4.3 优先级嵌套规则
嵌套,就是高优先级中断打断低优先级中断的处理。这个机制用好了,系统实时性飞起;用不好,就是死锁和崩溃。
DSP的嵌套规则,我总结为三条:
- 规则一:高优先级可以打断低优先级。这是嵌套的基础。比如你在处理串口中断,突然来了个定时器中断(优先级更高),CPU会暂停串口处理,先去跑定时器。跑完再回来继续串口。
- 规则二:同级中断不能互相打断。如果两个中断优先级相同,后到的必须等先到的处理完。这个很好理解,不然就乱套了。
- 规则三:低优先级不能打断高优先级。这个更不用说了,天经地义。
但这里有个坑,我踩过。有些DSP默认是不开启嵌套的。也就是说,即使你设了优先级,中断处理期间CPU也会自动屏蔽所有其他中断。你得手动在中断服务函数里开中断,才能实现嵌套。
我曾经踩过的坑:有一次做多级嵌套,我在高优先级中断里调了一个函数,这个函数居然又触发了同一个中断。结果就是无限递归,栈溢出,系统直接死机。后来我学乖了:中断服务函数里,绝对不要调用可能触发中断的函数。如果非要调用,先关中断。
嵌套的深度也要控制。我一般建议不超过3层。层数太多,栈空间消耗大,而且调试起来极其痛苦。你想想看,中断套中断,套了三层,最里面那层出错了,你得一层层往外查,头都大了。
4.4 实际配置示例
拿TI C2000系列举个例子。配置中断优先级,主要操作PIE模块:
// 配置PIE中断优先级
// 假设我们要把ADC中断设为高优先级,SCI中断设为低优先级
// 第一步:使能PIE模块
PieCtrlRegs.PIECTRL.bit.ENPIE = 1;
// 第二步:设置ADC中断(INT1.1)为高优先级
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // 使能ADC中断
PieCtrlRegs.PIEIFR1.bit.INTx1 = 0; // 清除标志位
// 第三步:设置SCI中断(INT9.1)为低优先级
PieCtrlRegs.PIEIER9.bit.INTx1 = 1; // 使能SCI中断
PieCtrlRegs.PIEIFR9.bit.INTx1 = 0; // 清除标志位
// 第四步:在中断向量表中注册
EALLOW;
PieVectTable.ADCINT1 = &adc_isr;
PieVectTable.SCIRXINT = &sci_isr;
EDIS;
这里要注意,PIE模块的优先级是分组的。INT1到INT12,每个组内又有8个中断。组间的优先级是固定的(INT1最高,INT12最低),但组内的优先级可以通过软件配置。
关键点:配置优先级时,一定要考虑中断的实时性要求。比如电流环、PWM保护这类中断,必须最高优先级。而按键扫描、LED闪烁这类,放最低优先级就行。别把优先级用反了,否则系统响应速度会大打折扣。
我个人习惯,在项目初期就会画一张中断优先级分配表。把每个中断源、硬件优先级、软件优先级、嵌套深度都列清楚。这样后期调试时,一眼就能看出问题在哪。
| 中断源 | 硬件优先级 | 软件优先级 | 嵌套深度 | 说明 |
|---|---|---|---|---|
| PWM保护 | 1(最高) | 0 | 0 | 不可嵌套,必须立即响应 |
| 电流环ADC | 2 | 1 | 1 | 可被PWM保护打断 |
| 速度环定时器 | 3 | 2 | 2 | 可被电流环打断 |
| SCI通信 | 4 | 3 | 3 | 最低优先级,可被任何中断打断 |
嗯,这张表我每次做项目都会更新。它就像一张地图,告诉你中断系统里谁说了算。
最后说一句,优先级配置不是一劳永逸的。项目迭代过程中,需求会变,中断的实时性要求也会变。定期review你的优先级分配,是个好习惯。
公众号:蓝海资料掘金营,微信deep3321