外设中断扩展模块(PIE:Peripheral Interrupt Expansion)是为了使 F2812 DSP 微处理器能够有效管理众多的中断而设计的。PIE 将 DSP 微处理器中的中断分组,使多个中断信号复用 1 个 CPU 级中断信号,从而使 CPU 能够高效地管理中断信号请求。
PIE 管理的中断源共 96 个(其中正在使用的有45个,其它的作为扩展资源供厂商测试或留待芯片升级时使用),这些中断分为 12 组,每个组有 8 个中断。这 12 组从 1 开始编号,依次分别接到 CPU 级的 INT1-INT12 中断信号上。96 个中断源对应 96 个中断向量,在存储器空间中专门留出一块来保存 96 个中断向量,当中断发生时,其对应的中断向量能够自动被取出从而调用相应的中断服务程序(F2812 中断向量的取出和跳转是由硬件自动完成的,相对于软件分离子中断的方式,这种方式能够大大提高中断的响应速度)。
注意:中断向量表是受 EALLOW 保护的。
PIE 配置及控制寄存器:
PIE 相关的寄存器咋看一下非常多,但是如果按组归类,对于一个特定的中断,与它相关的寄存器就只有 PIECTRL、PIEACK、PIEIERx、PIEIFRx。
除了上述寄存器,中断还与 IFR、IER 寄存器及全局中断屏蔽位 INTM 相关,下图是典型的 PIE - CPU 响应流程:
下面通过分析源代码来深入理解 F2812 中断机制:
void main()
{
DINT;//关全局可屏蔽中断 #define DINT asm(" setc INTM")
InitPieCtrl();//初始化pie寄存器
IER = 0x0000;//禁止所有的中断
IFR = 0x0000;
InitPieVectTable();//初始化pie中断向量表
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.TINT0 = &cpu_timer0_isr;//指定中断服务子程序
EDIS;
……
// Enable CPU INT1 which is connected to CPU-Timer 0:
IER |= M_INT1; //#define M_INT1 0x0001
// Enable TINT0 in the PIE: Group 1 interrupt 7
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
// Enable global Interrupts
EINT; //#define EINT asm(" clrc INTM")
}
// This function initializes the PIE control registers to a known state.
void InitPieCtrl(void) @ DSP281x_PieCtrl.c
{
// Disable Interrupts at the CPU level:
DINT;
// Disable the PIE
PieCtrlRegs.PIECRTL.bit.ENPIE = 0;
// 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;
}
使用 PIE 最重要的就是定义中断向量表,然后将其映射到指定的内存位置(0x00 0D00 - 0x00 0DFF),在 TI 提供的源代码中,向量表的定义如下(@ DSP281x_PieVector.h):
// Define Vector Table: 32+96 个函数指针,每个函数指针 32 位,整个向量表映射到 0x00 0D00 - 0x00 0DFF。
struct PIE_VECT_TABLE {
// Reset is never fetched from this table.
// It will always be fetched from 0x3FFFC0 in either
// boot ROM or XINTF Zone 7 depending on the state of
// the XMP/MC input signal.
PINT PIE1_RESERVED; //typedef interrupt void(*PINT)(void);
PINT PIE2_RESERVED;
PINT PIE3_RESERVED;
PINT PIE4_RESERVED;
PINT PIE5_RESERVED;
……
// Non-Peripheral Interrupts:
PINT XINT13; // XINT13
PINT TINT2; // CPU-Timer2
PINT DATALOG; // Datalogging interrupt
……
// Group 1 PIE Peripheral Vectors: 定义12组PIE中断向量表
PINT PDPINTA; // EV-A
PINT PDPINTB; // EV-B
……
// Group 12 PIE Peripheral Vectors:
PINT rsvd12_1;
PINT rsvd12_2;
……
}
上述只是定义一个中断向量表的结构体,在文件的最末尾才真正定义了一个 PIE_VECT_TABLE 变量:extern struct PIE_VECT_TABLE PieVectTable; 它的初始化是在 DSP281x_PieVector.c 文件 InitPieVectTable() 函数中完成的。
void InitPieVectTable(void)
{
int16 i;
Uint32 *Source = (void *) &PieVectTableInit;
Uint32 *Dest = (void *) &PieVectTable;
EALLOW;
for(i=0; i < 128; i++)
*Dest++ = *Source++;
EDIS;
// Enable the PIE Vector Table
PieCtrlRegs.PIECRTL.bit.ENPIE = 1;
}
InitPieVectTable() 函数中通过 PieVectTableInit 变量来初始化中断向量表 PieVectTable,PieVectTableInit 也是 PIE_VECT_TABLE 结构体变量,里面初始化了各种中断函数的入口地址(定义在DSP281x_DefaultIsr.c),用户可以通过重新赋值来使相应的中断向量指向用户自定义 ISR 入口地址,也可以在 DSP281x_DefaultIsr.c 中找到相应的中断服务函数并实现它。
相关资料下载:
——忠于梦想 勇于实践 linux_xpj@opencores.org
阅读(3705) | 评论(0) | 转发(0) |