最近在学习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; //开全局中断
}


