在TMS320F28377D双核处理器中,CPU1子系统充当主系统,在默认情况下(在复位时),它拥有配置和控制所有外设和IO口权限。由于双核各自拥有各自的flash和ram空间,其中LS是每个CPU独自的空间,GS是共享内存空间,其默认是归CPU1所控制,因此CPU1和CPU2是相对独立的,可双核运行各自程序实现不同功能(外设还是共用)。
上面说完双核的基本概念,下面正式进入正题(外部中断):
首先说明一下,在F28377D中,每个CPU都有自己的PIE,且两个PIE是独立配置的
外设产生中断的流程(配合上图理解):
①、中断锁存到对应的PIE的中断标志寄存器(Interrupt Group x Flag Register)的第x组第y通道 : PIEIFRx.y(补充说明:中断在PIE中是分组分通道,以F28377D为例,它分为12组16通道,12组是因为只有12根中断线可用)
②、如果此时PIEIERx.y已经通过软件设置为有效(具体写法如下),那么中断信号将被传递至后一级PIEACK.x(Interrupt Acknowledge Register 中断确认寄存器,也叫应答寄存器)
PieCtrlRegs.PIEIER1.bit.INTx4 = 1; // Enable PIE Group 1 INT4 使能PIE第一组第四个
③、如果此时的PIEACK.x标志位已经被清除(如上图,类似于开关闭合),那么中断信号继续传递至后一级,之后需要将PIEACK.x置位1
④、中断锁存至IFR.X中
⑤、如果总中断IER.x(interrupt enable register)有效,中断传输至下一级
⑥、如果INTM清零,那么CPU收到中断。
⑦、在CPU收到中断后,CPU会将当前的状态存至堆栈stack
⑧、IFR.X(中断标志寄存器) 和 IER.X(中断使能寄存器) 被清除,INTM(interrupt mode中断模式)置位,EALLOW(edit allow关闭写保护)被清除
⑨、CPU从PIE获取中断服务子程序地址,并且将PIE中PIEIFRX.Y清除
⑩、CPU正式执行中断函数
经过了上面10步,我们了解了外部中断的从产生至传递到CPU响应的过程,下面来说具体在写程序时如何配置外部中断。
设置中断的过程一般如下 :
第一步 : 关闭全局中断(DINT)
DINT;// 关中断
第二步 :关闭PIE功能,通过设置PIECTRL.bit.ENPIE = 0来实现
PieCtrlRegs.PIECTRL.bit.ENPIE = 0;// Disable the PIE
第三步 :清空PIEIER 和PIEIFR寄存器;用以清除所有的cpu中断响应组
// Clear all PIEIER registers:
PieCtrlRegs.PIEIER1.all = 0;
PieCtrlRegs.PIEIER2.all = 0;
PieCtrlRegs.PIEIER3.all = 0;
PieCtrlRegs.PIEIER4.all = 0;
PieCtrlRegs.PIEIER5.all = 0;
PieCtrlRegs.PIEIER6.all = 0;
PieCtrlRegs.PIEIER7.all = 0;
PieCtrlRegs.PIEIER8.all = 0;
PieCtrlRegs.PIEIER9.all = 0;
PieCtrlRegs.PIEIER10.all = 0;
PieCtrlRegs.PIEIER11.all = 0;
PieCtrlRegs.PIEIER12.all = 0;
// Clear all PIEIFR registers:
PieCtrlRegs.PIEIFR1.all = 0;
PieCtrlRegs.PIEIFR2.all = 0;
PieCtrlRegs.PIEIFR3.all = 0;
PieCtrlRegs.PIEIFR4.all = 0;
PieCtrlRegs.PIEIFR5.all = 0;
PieCtrlRegs.PIEIFR6.all = 0;
PieCtrlRegs.PIEIFR7.all = 0;
PieCtrlRegs.PIEIFR8.all = 0;
PieCtrlRegs.PIEIFR9.all = 0;
PieCtrlRegs.PIEIFR10.all = 0;
PieCtrlRegs.PIEIFR11.all = 0;
PieCtrlRegs.PIEIFR12.all = 0;
第四步 : 清空中断向量表,即清空所有的中断地址表
void InitPieVectTable(void)
{
Uint16 i;
Uint32 *Source = (void *) &PieVectTableInit;
Uint32 *Dest = (void *) &PieVectTable;
// Do not write over first 3 32-bit locations (these locations are
// initialized by Boot ROM with boot variables)
Source = Source + 3;
Dest = Dest + 3;
EALLOW;
for(i = 0; i < 221; i++)
{
*Dest++ = *Source++;
}
EDIS;
// Enable the PIE Vector Table
PieCtrlRegs.PIECTRL.bit.ENPIE = 1;
}
第五步 :关闭CPU中断响应;CPU寄存器中也有两个寄存器用于设置中断;即IER个IFR;全部置位为0即可;
// 不使能中断,清中断标志
IER = 0x0000;
IFR = 0x0000;
第六步:设置外设的中断触发 :
1)配置中断函数地址
2)打开PIE中断通道组即使能PIEIERX.Y = 1;
3)配置CPU的中断寄存器以打开cpu对中断的响应即IER |= M_INTX
对应的程序如下
1)
EALLOW; // 这是写入EALLOW受保护寄存器所需要的(关闭写保护)
PieVectTable.XINT1_INT = &xint1_isr;
EDIS; //这是禁用写EALLOW受保护寄存器所需要的(再次开启写保护)2
2) PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // Enable the PIE block 使能PIE块
PieCtrlRegs.PIEIER1.bit.INTx4 = 1; // Enable PIE Group 1 INT4 使能PIE第一组第四个
3) IER |= M_INT1 | M_INT12; // Enable CPU INT1和INT12
EINT; // Enable Global Interrupts
第七步 : 打开全局中断使能 EINT / ERTM
EINT; // 开中断 enable interrupt
ERTM; // 使能调试事件
至此,外部中断已经配置完成,把工作重心放在中断服务子程序的编写中,如以下点灯函数
interrupt void xint1_isr(void) //中断服务程序1
{
Xint1Count++; //中断计数
LED3_TOGGLE = 1; //灯翻转
PieCtrlRegs.PIEACK.bit.ACK1 = 1; //下面问题2有解析写这一句的缘由
}
值得注意的是:配置中断程序的位置排布如果发生变化,是有可能影响中断的触发的
文末最后,补充一下可能会有小伙伴很有疑问的问题
问题1:dsp中 IER |= M_INT1中 |=什么意思?
答1:开中断1的意思
“|=”是赋值位运算符号 ,意思就是IER= IER||M_INT1,即IER赋值为IER和M_INT1位或。即Enable CPU INT1 ,同时,可以用或运算符同时使能多个中断,如:
IER |= M_INT1 | M_INT12; // Enable CPU INT1 INT12
类似的还有 &= 、^=
问题2:外部中断服务子程序中PieCtrlRegs.PIEACK.bit.ACK1 = 1;什么作用?
答2:我们都知道TMS320F28377D的中断分为3个级别,CPU级中断,PIE级中断和外设级中断。而应答寄存器PIEACK (Acknowledge Register)就是是中断从PIE 级进入CPU 级的门禁。一个中断在进入CPU级之前,其对应的PIEACK[x.1]必须通过软件清0,打开后续INTx 的PIE 级到达CPU 的通道。而当这个中断进入CPU 级INTx 中断线时,硬件将PIEACK[x.1]位置1,关闭后续INTx 的PIE 级到CPU 的通道。这条指令通过向PIEACK[0]写1,将PIEACK[0]位清0,从而打开后续INT1 的PIE 级到CPU 级的中断。注意:PIEACK[x.1]对INTx 中断线(1 x 12)。
源码的中断服务程序中没有将中断标志位清0 的指令。当程序开始运行并执行到指令“CpuTimer0Regs.TCR.bit.TSS = 0;”时,定时器中断标志位TIF(TCR[15])即从0 变成1。这意味着一旦启动定时器即触发定时器中断之后,即使通过软件将该位置1,也不能将其清0。