文章目录
前言
背景介绍
中断框架
外设中断
ePIE模块
CPU中断
中断嵌套
应用实例
总结
参考资料
前言
见《【研发日记】嵌入式处理器技能解锁(一)——多任务异步执行调度的三种方法》
见《【研发日记】嵌入式处理器技能解锁(二)——TI C2000 DSP的SCI(串口)通信》
见《【研发日记】嵌入式处理器技能解锁(三)——TI C2000 DSP的C28x内核》
见《【研发日记】嵌入式处理器技能解锁(四)——TI C2000 DSP的Memory》
背景介绍
本文要讲的中断系统是TI C2000 DSP的一种多任务处理机制。其在整体软件架构中发挥的作用如下图所示:
Tips:中断任务调度不同于User软件调度,这里是芯片硬件层面的机制,切换速度快到系统时钟周期的级别。
中断框架
TI C2000 DSP的中断路径分为三级:外设、ePIE和CPU,如下图所示:
C28x CPU有14条对外中断line,其中前12条(INT1到INT12)通过ePIE(增强型外设中断扩展)模块连接到各种外设中断,最后两条(INT13和INT14)直接连到Timer1和Timer2。
ePIE有多达16*12个对外的中断Channel,每16个Channel组成一个Group,总共12个Group。每个Group的16Channel个由一个Mux(多路复用)连接到CPU的1条对外中断line。
每个外设中一般都有多个中断,例如INT_ADCA1(ADC的A模块的通道1中断)、INT_ADCA2(ADC的A模块的通道2中断)等等,每个中断都连接到ePIE对外的中断Channel。每个中断也都对应一个ISR(中断服务程序),两种通过Vector Table(中断向量表)映射在一起。如下图所示:
TI C2000 DSP的这种三级中断架构设计,使得CPU能够处理大量的外设中断。每一级都有其自身的使能和标志寄存器,这些寄存器的灵活配置,可以允许CPU处理一个中断ISR时让其他中断挂起,或者让其他中断的ISR嵌套在当前ISR中间。前者可以用于某些关键ISR期间禁用Other中断,后者可以用在软件修改中断的硬件优先级。
外设中断
TI C2000 DSP的外设子系统非常多,功能各不相同。每个外设也都有多个中断,主要用于调度跟本外设相关的任务。例如,外设SCI(serial communication interface)的中断系统,可以用于提取/填充FIFO、处理通信故障等,SCI的几个接收中断如下图所示:
Tips:在ePIE的Vector Table中可以看到单个SCI通道的RX中断只有一个,例如ITN9.1的SCIA_RX中断,但是上面的框图中SCI接收的相关中断有那么多,这就是外设级的Mux(多路复用)在发挥作用。每条中断Line上都有Enable和Flag寄存器,当ITN9.1的SCIA_RX传递到CPU中的ISR时,再读取相应的Flag寄存器就可以判断具体是什么中断,然后再switch到子代码中。
ePIE模块
TI C2000 DSP的ePIE模块为每个外围中断信号提供了一个通道,每个通道上都有单独的Flag位和Enable位寄存器,如下图所示:
ePIE模块的这些通道根据相关的CPU中断进行分组,每个组内的16个通道组成一个16位Enable寄存器(PIEIERx)、一个16位Flag寄存器(PIEIFRx)和一个ACK寄存器(PIEACKx)。PIEACKx寄存器位充当该组的公共中断掩码。
当外设中有多个中断同时发生,或者ePIE中挂着多个中断时,Mux模块就会去仲裁出优先级highest(通道号lowest)的送到CPU。当CPU接收到中断时,还要从ePIE的Vector Table中获取对应ISR的地址。
ePIE模块中的优先级仲裁就是一个比大小的过程,也是芯片硬件层面的一个行为机制,User Code在这个阶段干涉不了优先级仲裁的结果。而且TI C2000 DSP的一百多个外设中断,每一个的优先级位置都是在芯片硬件层面定义好的,第一组和第二组的32个中断,优先级示例如下:
CPU中断
CPU中断与ePIE模块一样,也是为每条连接到CPU的中断Line提供Flag位和Enable位寄存器,如下图所示:
CPU中断涉及的有一个Enable寄存器(IER)和一个Flag寄存器(IFR),这两个寄存器都是CPU内部寄存器。此外还有一个全局中断掩码(INTM),位于ST1寄存器,可以使用CPU的EINT指令(Clear INTM掩码,置为0,允许全局中断)和DINT指令(Set INTM掩码,置为1,禁止全局中断)进行配置。
中断传播到CPU Interrupt Logic模块时,CPU要做的事情包括四部分:
1、自动将IFR和IER置为0,将INTM置为1,这是芯片硬件层面的动作机制,目的是阻止再有中断进来。对于中断嵌套的应用后面再讲。
2、保存现场,把堆栈和PC指针中的数据都保存起来。
3、从Vector Table中抓取相应ISR的地址,执行中断服务程序。
4、等ISR 执行Complete后,再回到前面保存的程序现场,回到主程序,并把各级中断Enable。
当CPU阶段有多个中断同时发生,IFR寄存器中挂着多个中断时,Mux模块就会去仲裁出优先级highes的送到CPU Interrupt Logic模块。这里的优先级仲裁也是一个比大小的过程(芯片硬件层面的一个行为机制),但是不同于ePIM中的编号那么规则。在CPU阶段总共有32个中断,每一个的优先级位置也都是在芯片硬件层面定义好的,如下图所示:
Tips:上图中的系统中断比较特殊,User能设计开发的空间很小,只需了解即可,无需过多关注。
中断嵌套
默认情况下,TI C2000 DSP芯片内部的硬件机制是不对中断进行嵌套。也就是前文所讲述的,所有的中断都按照TI在芯片硬件层面设定好的优先级进行仲裁,等着高优先级的ISR先执行完,然后再执行低优先级的ISR。如果低优先级的ISR已经在执行过程中,高优先级的中断来了也要等前面的ISR执行完。这种方式是最保守,也最安全的一种应用方式。
但是在一些应用场景中,就是要求高优先级的ISR无条件地优先执行,甚至User需要改变TI在芯片硬件中定义的优先级顺序,重新设计一套Software优先级,这时候就需要用到中断嵌套了。例如,User设计的软件中用到INT1.5和INT2.4两个中断,要求INT2.4的优先级最高,无条件地优先执行,示例如下:
上图中断的Software优先级设计和中断嵌套是User Code通过控制IER和PIEIERx等寄存器来实现的,具体过程如下图所示:
1、开中断,User Code把INT1.5和INT2.4两条线路上的使能寄存器都Enable,用不到的线路都Disable;
2、外设中断事件A发生,中断信号被PIEIFR1.5寄存器捕捉到;
3、中断信号穿过PIEIER1.5之后,芯片硬件机制自动把PIEIER1.5 Disable;
4、中断信号穿过PIEACK.1之后,芯片硬件机制自动把PIEACK.1 Disable;
5、中断信号穿过INTM之后,芯片硬件机制自动把INTM Disable;
6、中断信号到达CPU Interrupt Logic后,从Vector Table中抓取INT1.5的ISR的地址,开始执行该ISR;
7 、User在INT1.5 ISR头部写入的Code重新把INTM Enable,以此保证INT2.4的中断线路是通畅的;
8、INT1.5的ISR执行过程中,外设中断事件B发生了,中断信号一路传播到CPU Interrupt Logic(同步骤2、3、4、5);
9、CPU暂停执行INT1.5的ISR,转去执行INT2.4的ISR;
10、INT2.4的ISR执行完后,返回继续执行INT1.5 ISR的后半段;
11、两个ISR都执行完后,返回主程序继续执行。
应用实例
这里展示一个示例Demo代码,直接用代码中的注释进行说明。
// C28x ISR Code //
// Enable nested interrupts //
// INT2.2的Software优先级Highest,无条件插入INT2.1的ISR中 //
void EPWM1_TZINT_ISR(void) //INT2.1的ISR
{
uint16_t TempPIEIER;
TempPIEIER = PieCtrlRegs.PIEIER2.all; // Save PIEIER register for later
//*****到这,所有中断线路都被芯片硬件机制自动Disable了,需要如下代码把INT2.2的中断线路打通*****//
//允许Group2的中断进CPU(IER是1使能)
IER |= 0x002; //Group2置1,其他Group保持不变;
IER &= 0x002; //Group2不变,其他Group置0;
//最终效果:只有Group2传播途径的通畅的;
//允许INT2.2中断(PIEIER是1使能)
PieCtrlRegs.PIEIER2.all |= 0x0002; //INT2.2置1,其他Channel保持不变;
PieCtrlRegs.PIEIER2.all &= 0x0002; //INT2.2,其他Channel置0;
//最终效果:只有2.2的传播途径的通畅的
//这里手动再把它置1(PIEACK是0使能)
PieCtrlRegs.PIEACK.all &= ~(0x002); // Enable PIE Group2 interrupts
//等流水线上的指令走一走
asm("NOP"); // Wait one cycle
//开全局中断(INTM是0有效)
EINT; // Clear INTM(置0) to enable interrupts
//*****到这,已经把INT2.2的中断线路打通打通了*****//
/**************下面这段时间如果2.2的中断发生了就会进来,CPU就会跳转去执行2.2的ISR*************//
// Insert ISR Code here.......
// for now just insert a delay
//
for(i = 1; i <= 10; i++) {}
//
//********************************************************************************************//
// Restore registers saved:
DINT; // Set INTM(置1) to disable interrupts,因为马上就要退出ISR(switch context)了
PieCtrlRegs.PIEIER2.all = TempPIEIER; //人为干预的再把它恢复了,因为Group2后面可能还有其他挂起的中断
}
//退出2.1的ISR,芯片硬件机制又会自动设置寄存器,以此保证中断传播线路畅通
总结
以上就是本人在研发中使用嵌入式处理器的中断系统时,一些个人理解和分析的总结,主要介绍了TI C2000 DSP 中断系统的工作原理,展示了具体的使用方法,并分析了它的特点和应用场景。
后续还会分享另外几个最近解锁的嵌入式处理器新技能,欢迎评论区留言、点赞、收藏和关注,这些鼓励和支持都将成文本人持续分享的动力。
另外,上述例程使用的Demo工程,可以到笔者的主页查找和下载。
参考资料
TMS320F28003x Real-Time Microcontrollers datasheet.pdf
版权声明,原创文章,转载和引用请注明出处和链接,侵权必究!