最近在学习DSP,想把自己的学习感想,记录下来,大家讨论一下。
DSP的三级中断机制,分别是外设级,PIE级和CPU级,也就是说,对于一个具体的外设中断请求,我们需要三级的许可。
CPU相当于分组,分成了12个小组,而PIE是CPU组里边的成员每个小组又有8个成员。PIE的英语称作Peripheral interrupt Expansion block
专门处理外设中断的扩展模块。很准确的描述了PIE的含义。
书上用了一个使用CPU定时器0的周期中断来控制LED灯的例子。
CPU定时器0在完成一个周期的计数之后,会产生一个周期中断,设置CPU定时器0的周期为1S,每隔1S进入一次周期中断,在中断服务程序里边
改变了GPIO引脚的电平。
void main(void)
{ InitSysCtrl(); //初始化系统函数
DINT;
IER = 0x0000; //禁止CPU中断
IFR = 0x0000; //清除CPU中断标志
这两个寄存器分别是中断使能寄存器和中断标志寄存器,说明这个程序里边的中断时可屏蔽中断,
InitPieCtrl(); //初始化PIE控制寄存器
InitPieVectTable(); //初始化PIE中断向量表
InitPeripherals(); //初始化Cpu定时器模块 I
nitGpio(); //初始化GPIO
PieCtrl.PIEIER1.bit.INTx7 =1; //使能PIE模块中的Cpu定时器0的中断 I
ER|=M_INT1; //开CPU中断
EINT; //使能全局中断
ERTM; //使能实时中断
ConfigCpuTimer(&CpuTimer0, 150, 1000000); //Cpu定时器0的周期为1s
StartCpuTimer0(); //启动Cpu定时器0 for(;;) { }
}
以上的MIAN的主程序,下边是DSP28_PIEVECT.H这个头文件,书上说定义了PIE的中断向量,我觉得这个头文件还有一个重点
就是定义了PINT的指针,指向了中断。之后要去找找这个PINT的指针在哪里。
#ifndef DSP28_PIE_VECT_H #define DSP28_PIE_VECT_H // 定义一个名称为PINT的指针,指向中断: typedef interrupt void(*PINT)(void); // 定义中断向量表: struct PIE_VECT_TABLE { //中断向量表起始地址为0x3FFFC0, 在BOOT ROM还是XINTF ZONE7 取决于引脚XMP/MC的状态 //当XMP/MC=0时,向量表在BOOT ROM内;当XMP/MC=1,向量表在XINTF ZONE7内 PINT PIE1_RESERVED; ........ // 非外设中断: PINT XINT13; // XINT13 ..... // PIE组1外设中断向量: PINT PDPINTA; // EV-A ..... // PIE组2外设中断向量: PINT CMP1INT; // EV-A ........ // PIE组3外设中断向量: PINT T2PINT; // EV-A ........ // PIE组4外设中断向量: PINT CMP4INT; // EV-B ........ // PIE组5外设中断向量: PINT T4PINT; // EV-B .......
......... extern struct PIE_VECT_TABLE PieVectTable; #endif
InitPieCtrl这个函数对PIE的中断使能寄存器进行初始化,对应上图画红圈的寄存器。
程序里边第一步先是给PieCtrl.PIECRTL.bit.ENPIE = 0;对PIE控制寄存器的ENPIE位置0,此时PIE块是无效的。
第二步,对PIE中断使能寄存器设置,这个寄存器一共有12个分别为PIEIERx,而每个寄存器正好有8位,对应每个CPU小组里边的8个成员。
也就是说这个PIE中断使能寄存器有96个分别使能每个成员中断。对应上边图中的开关闭合对应每个CPU小组里边的8个成员。也就是说这个PIE中断使能寄存器有96个分别使能每个成员中断。对应上边图中的开关闭合
第三步,对PIE中断标志寄存器设置,和中断使能寄存器类似分成12组,每个组有8个成员,一共12个寄存器,每个寄存器8位。书上说当中断激活的时候,各个寄存器位置1,当中断被处理完成或者向该位写0,该为清0.还不能理解--------------------------------------------------------------------------------
void InitPieCtrl(void) { // 禁止PIE模块 PieCtrl.PIECRTL.bit.ENPIE = 0; // 禁止PIE所有中断 PieCtrl.PIEIER1.all = 0; PieCtrl.PIEIER2.all = 0; PieCtrl.PIEIER3.all = 0; PieCtrl.PIEIER4.all = 0; PieCtrl.PIEIER5.all = 0; PieCtrl.PIEIER6.all = 0; PieCtrl.PIEIER7.all = 0; PieCtrl.PIEIER8.all = 0; PieCtrl.PIEIER9.all = 0; PieCtrl.PIEIER10.all = 0; PieCtrl.PIEIER11.all = 0; PieCtrl.PIEIER12.all = 0; // 清除所有PIEIFR的中断标志位 PieCtrl.PIEIFR1.all = 0; PieCtrl.PIEIFR2.all = 0; PieCtrl.PIEIFR3.all = 0; PieCtrl.PIEIFR4.all = 0; PieCtrl.PIEIFR5.all = 0; PieCtrl.PIEIFR6.all = 0; PieCtrl.PIEIFR7.all = 0; PieCtrl.PIEIFR8.all = 0; PieCtrl.PIEIFR9.all = 0; PieCtrl.PIEIFR10.all = 0; PieCtrl.PIEIFR11.all = 0; PieCtrl.PIEIFR12.all = 0; // 使能PIE模块 PieCtrl.PIECRTL.bit.ENPIE = 1; PieCtrl.PIEACK.all = 0xFFFF; } 下边是DSP28_PieVect.c对PIE中断向量初始化,执行完这个程序之后,各个中断函数有了入口地址。const struct PIE_VECT_TABLE PieVectTableInit = {省去}void InitPieVectTable(void) { int16 i; Uint32 *Source = (void *) &PieVectTableInit; Uint32 *Dest = (void *) &PieVectTable; EALLOW; for(i=0; i < 128; i++) *Dest++ = *Source++; EDIS; // 使能PIE向量表 PieCtrl.PIECRTL.bit.ENPIE = 1; }for(i=0; i < 128; i++)注意这里赋值了128次
这个程序大概就是设置定时器0的周期为1S,每隔1S进入一次周期中断
ConfigCpuTimer(&CpuTimer0, 150, 1000000); //Cpu定时器0的周期为1s StartCpuTimer0(); //启动Cpu定时器0
void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period) { Uint32 temp; Timer->CPUFreqInMHz = Freq; Timer->PeriodInUSec = Period; temp = (long) (Freq * Period); Timer->RegsAddr->PRD.all = temp; //给定时器周期寄存器赋值 Timer->RegsAddr->TPR.all = 0; //给定时器预定标寄存器赋值 Timer->RegsAddr->TPRH.all = 0; // 初始化定时器控制寄存器: Timer->RegsAddr->TCR.bit.TIF=1; //清除中断标志位 Timer->RegsAddr->TCR.bit.TSS = 1; //停止定时器 Timer->RegsAddr->TCR.bit.TRB = 1; //定时器重装,将定时器周期寄存器的值装入定时器计数器寄存器 Timer->RegsAddr->TCR.bit.SOFT = 1; Timer->RegsAddr->TCR.bit.FREE = 1; Timer->RegsAddr->TCR.bit.TIE = 1; //使能定时器中断 Timer->InterruptCount = 0; //初始化定时器中断计数器 }然后每计数1S进入一次中断在中断里边编写了灯闪硕的代码
interrupt void TINT0_ISR(void) // CPU-Timer0中断函数 { CpuTimer0.InterruptCount++; if(CpuTimer0.InterruptCount==1) { GpioDataRegs.GPFCLEAR.bit.GPIOF14=1; //XF引脚低电平,D3亮 } if(CpuTimer0.InterruptCount==2) { GpioDataRegs.GPFSET.bit.GPIOF14=1; //XF引脚高电平,D3灭 CpuTimer0.InterruptCount=0; } CpuTimer0Regs.TCR.bit.TIF=1; //清除定时器中断标志位 PieCtrl.PIEACK.bit.ACK1=1; //响应同组其他中断 EINT; //开全局中断 }