前言
本文重点探讨DSP PIE模块的学习笔记,由于学这部内容的时候,是用28335学的,所以标题是用的28335,但其实28377D和28335的PIE使用基本上是一样的,也是可以借鉴的。
正文
原理
讲点原理,PIE,peripheral interrupt expansion,外设中断扩展模块
TMS320F28335内部有16个中断线,其中包括2个不可屏蔽中断(RESET和NMI)与14个可屏蔽中断,可屏蔽中断通过相应的中断使能寄存器可以使能或者禁止产生的中断
外部中断源→DSP芯片IO引脚上的电平变化触发中断
内部中断源→DSP内部CPU和各个外设模块产生的中断比如ADC、PWM、SCI、SPI等等模块产生的中断
DSP比作人,外部中断就是相当于手被割伤的疼痛,内部中断就是相当于肚子痛
在2833x处理器中,定时器1和定时器2预留给实时操作系统使用,其中断分配给INT13和INT14,两个不可屏蔽的中断RESET和NMI各自占用独立的专用专断,同时NMI中断也可以选择同定时器1复用INT13,其余12个可屏蔽中断直接连接在外设中断扩展模块 (也就是PIE模块),供外部中断和处理器内部外设单元使用。
问题:28335内部有那么多的外设(PWM、SCI、ADC等等),这些外设又有自己的中断,并且中断还很多个,那么剩余12个中断怎么能够够用呢?
为了解决这个问题,就引入了PIE模块,可以管理多路中断,最后分配到12个核中断上面
看懂这个图,基本上就能把PIE的原理明白的差不多了。
(IFR是interrupt flag register,IER是interrupt enable register,28335参考手册的pg139)
我们可以把这个图的上下分成两级(LEVEL), 上面的CPU LEVEL总公司,下面是PIE LEVEL分公司。
首先来看这个INTx.1 ~ INTx.8, 这个x它可以是1~12。 比如我是INT2.2或者INT2.3。 我的中断信号最终就会送到INT2这里来。
下面举例 中断INT2.2如何才能传递到CPU,看懂这个例子,PIE的原理你的学会了。
INT2.2产生之后,PIEIFR2.2(PIE interrupt flag register PIE中断标志寄存器)这里的开关会直接闭合
然后,中断信号会传递到PIEIER2.2(PIEIER是PIE interrupt enable register,PIE中断使能寄存器),如果想让INT2.2信号继续传递,那这里需要配置 PieCtrlRegs.PIEIER2.bit.INTx2 = 1;那这个时候,第二个开关闭合。
接下来信号会传递到左下角的与门这里,与门上支路是直接导通的,如果想让INT2.2信号继续传递,下面PIEACK2需要为0才行,因为前面还有一个取反。PIEACK2默认应该是0(换句话说就是第一次中断能够直接从与门这里过去),但是每次执行了中断之后,对应的PIEACK就会被置1,如果想要INT2.2每次都能把信号传递到CPU,那么在中断处理函数,就需要把PIEACK2清零。即
interrupt void INT2.2_ISR(void){
// do something
PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;
}
如果保持PIEACK2为零,信号就会通过与门
此时INT2.2信号已经从PIE LEVEL传递到了CPU LEVEL了, 信号会传到IFR2(interrupt flag register 中断标志寄存器)这里。这个开关也会直接闭合。
然后中断信号会进一步传递到IER2这里(interrupt enable register,中断使能寄存器),如果想让INT2.2信号继续传递,那这里需要配置 IER |= M_INT2;这时候, CPU LEVEL的第二个开关闭合。
当INT2.2的信号通过了IER2的开关之后,最后就来到了 Global Enable开关这里了。我们最后只需要把中断的全局使能开关打开:
EINT; // 使能全局中断
所有的开关都闭合了。最终就能使得INT2.2的信号传递到CPU里面。
当然,另外值得一提的是PIE模块整体有个使能,也得打开,PIE模块如果都不工作,INT2.2肯定到不了CPU这里。
PieCtrlRegs.PIECTRL.bit.ENPIE = 1;
那么我们怎么知道我这个外设的中断对应的是INT几点几呢? 28335请看参考手册的pg149。
28377D请看参考手册的pg102。
代码
下面我与28377D的INT1.1为例,写一个PIE中断配置的参考代码,关于ADCa的其他配置部分,请到我讲ADC的博客去看哈。
void main(void)
{
InitSysCtrl();
DINT; // 先关闭全局中断使能,等配置完了所有的外设,再打开全局中断使能
InitPieCtrl();
InitGpio();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
// 👆前面这些默认初始化函数也很关键哈
// ADC
EALLOW; // 设置中断入口函数
PieVectTable.ADCA1_INT = &ADCaHandler;
EDIS;
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // Enable PIE Level interrupt
IER |= M_INT1; // Enable CPU Level interrupt
PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // PIE模块使能
EINT; // 全局中断使能
while(1){;}
}
interrupt void ADCaHandler(void){
// do something
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
愿我们共同进步! 感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。