中断系统概述
X2812的中断系统从下至上分成了三级,即外设中断、PIE级中断、CPU级中断,三级中断类似于串联的关系,共同完成中断信号的发生、判断及次处理。现对中断系统的执行流程作简要概述:
首先,如果有外设产生中断事件,则寄存器中相应的中断标志位被置1,如果相应的中断使能位被置位,那么外设将向PIE控制器发出一个中断请求。
其次,当外设向PIE控制器发送中断请求时,相应的PIE中断标志位(PIEIFRx.y)置1,如果相应的PIE中断使能位(PIEIERx.y)也被置位,则PIE将检查相应的PIEACKx位,以确定CPU是否位该组中断准备好,如果PIEACKx位被清除,则PIE会向CPU发送管理请求,如果PIEACKx位为1,则PIE将一直等待直到该位被清除才向CPU发送中断请求。
最后,当中断请求被发送到CPU,相应的CPU级中断标志位置1。当中断标志锁存到标志寄存器后,会检查CPU中断使能寄存器(IER)或调试中断使能寄存器(DBGIER)和全局中断屏蔽位(INTM)被使能后才被执行。
X2812的三级中断机制如下图所示:
1.外设级中断
外设中断操作流程
在程序执行过程中,某一外设产生了一个中断事件,那么这个外设的某寄存器中与该中断事件相关的中断标志位(IF)被置位为1。此时,如果该中断相应的中断使能位(IE)已经被置位,也就是该值为1,该外设就会向PIE控制器发出一个中断请求,如果中断使能位未被置位,外设不会向PIE控制器提出中断请求,但是相应的中断标志位会一直保持,除非用程序将其手动清除,或者中断被使能,外设也会立即向PIE发出中断请求。
以CPU定时器为例,手动请求清除定时器中断标志位代码如下:
CpuTimer0Regs.TCR.bit.TIF= 1; //清除定时器中断标志位
// TCR: Control register bit definitions:
struct TCR_BITS { // bits description
Uint16 rsvd1:4; // 3:0 reserved
Uint16 TSS:1; // 4 Timer Start/Stop
Uint16 TRB:1; // 5 Timer reload
Uint16 rsvd2:4; // 9:6 reserved
Uint16 SOFT:1; // 10 Emulation modes
Uint16 FREE:1; // 11
Uint16 rsvd3:2; // 12:13 reserved
Uint16 TIE:1; // 14 Output enable 定时器中断使能位
Uint16 TIF:1; // 15 Interrupt flag 定时器中断标志位
};
如上述代码所示,当CPU定时器0的计数器寄存器TIMH:TIM计数到0时,就产生一个T0INT事件,即CPU定时器0的周期中断,此刻第15位定时器中断标志TIF被置位,这时,如果第14位TIE位1,CPU定时器0就会向PIE控制器发出中断请求。
2.PIE级中断
2.1 PIE中断概述
中断控制器PIE,专门处理外设中断的扩展模块(Peripheral Interrupt Expansion),它能够对各种中断请求源做出判断和相应决策。
PIE一共可以支持96个不同的中断,且将这些中断分成了12组,每组8个,12组依次反馈到CPU内核的INT1~INT12这12条中断线中的某一条上。平时能够用到的外设在PIE中的分布情况如下表所示:
从上表中看到,CPU定时器0的周期中断TINT0对应于INT1,在PIE第一组的第七位。PIE第一组的所有外设中断复用CPU中断INT1,依次类推,PIE第12组的所有外设中断复用CPU中断INT12。在PIE同组内,INTx.1的优先级高于比INTx.2高,不同组之间,排在前面组内的任何一个中断优先级要比排在后面组内的任何一个中断的优先级高。
2.2 PIE中断寄存器
PIE的每个组都有三个相关的寄存器,分别是PIE中断使能寄存器PIEIERx、PIE中断标志寄存器PIEIFRx和PIE中断应答寄存器PIEACKx(介绍省略)。
2.3 PIE中断向量表
PIE一共可以支持96个中断,每个中断都会有终端服务子程序ISR,DSP将各个中断服务子程序的地址存储在一片连续的RAM空间内,称之为PIE中断向量表。
2.4 PIE中断操作流程
当外设将中断请求提交给PIE,PIE中对应外设中断组的标志寄存器PIEIFRx将被置位,此时如果对应组的中断使能寄存器PIEIERx为使能状态,则PIE会根据中断的优先级优先处理高优先级中断,同时PIE寄存器还将根据中断应答寄存器PIEACK表示PIE是否准备好去响应这些组内中断。如CPU定时器0的周期中断被响应了,则PIEACK的第0位(对应于PIE1,即INT1)就会被置位,并且一直保持直到手动清除这个标志位,清除语句如下所示:
PieCtrlRegs.PIEACK.bit.ACK1 = 1; //可以响应组1内的其他中断
所以,每个外设中断被响应之后,一定要对PIEACK的相关位进行手动复位,以使得PIE控制器能够响应组内的其他中断。
3.CPU级中断
X2812一共支持32个CPU中断,其中每一个中断都是一个32位的中断向量,用于存储相应的中断服务子程序的入口地址。CPU中断里,INT1~INT14是14个通用中断,也是可屏蔽中断,可通过CPU中断使能寄存器IER和中断标志寄存器IFR来响应中断。
当一个外设中断请求通过PIE发送到CPU时,CPU中断标志寄存器IFR中相对应的中断标志位INTx就会被置位。这时,CPU不会立即执行中断,而是检查IER寄存器中相关位的使能情况和CPU寄存器ST1中全局中断屏蔽位INTM的是能情况。如果IER中的相关位被置位,并且INTM的值为0,则中断就会被CPU响应。
4.CPU定时器0的周期中断控制LED灯闪烁实例
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h" // DSP2833x Examples Include File
interrupt void cpu_timer0_isr(void); //定义定时器周期中断响应子函数
void main(void)
{
InitSysCtrl(); //初始化系统控制寄存器,包括锁相环、看门狗级外部时钟
DINT; //禁止CPU中断(INTM)
InitPieCtrl(); //初始化PIE控制寄存器置默认状态
IER = 0x0000; //禁止CPU中断使能寄存器
IFR = 0x0000; //禁止CPU中断标志寄存器
InitPieVectTable(); //初始化PIE中断向量表
EALLOW;
PieVectTable.TINT0 = &cpu_timer0_isr; //定时器的响应子程序赋值给TINT中断向量表
EDIS;
InitCpuTimers(); // 初始化CPU计时器
ConfigCpuTimer(&CpuTimer0, 150, 1000000); //配置CPU计时器,每1响应一次定时器中断
CpuTimer0Regs.TCR.all = 0x4001; // 定时器外设中断使能
EALLOW;
GpioCtrlRegs.GPCMUX1.bit.GPIO66 = 0; //配置GPIO66为IO口
GpioCtrlRegs.GPCDIR.bit.GPIO66 = 1; //配置GPIO66方向为输出
EDIS;
IER |= M_INT1; //CPU中断使能
PieCtrlRegs.PIEIER1.bit.INTx7 = 1; //PIE中断第一组的INTx7中断使能
EINT; //使能全局中断中断
ERTM; // 使能实时中断
for(;;);
}
interrupt void cpu_timer0_isr(void)
{
CpuTimer0.InterruptCount++;
GpioDataRegs.GPCTOGGLE.bit.GPIO66 = 1; // 反转 GPIO66 的输出高低电平
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // 执行定时器中断子程序后,PIEACK标记位主动清除
}