1. 中断概述
1.1 中断响应机制和分类
CPU在进程正常的程序处理的时候,有时候会被要求处理更高需求级别的任务,因此不得不中断当前任务进程,进入中断服务程序。而在处理完这些额外的任务之后,还需要回到之前的任务,因此就需要在进入中断程序之前必须保存现场,以确保在主要任务被打断并完成中断程序之后,能够准确地回到之前的任务节点。
中断请求可以分为:
- 可屏蔽中断:可通过判断优先级选择是否处理
- 不可屏蔽中断:强制停止CPU进程,进入中断程序,比如复位和NMI。
中断源也可以分成两类:
- 片内部中断源:PWM,CAP,QEP,定时器等
- 片外部中断源:外部中断输入引脚XINT1、XINT2引入的信号
1.2 中断结构
F28335有很多的外设资源,这些外设资源有可能会同时发布额外任务给CPU,换句话说就是F28335的中断源有很多,这些中断源想要得到CPU的响应就必须要中断线传递信号给CPU。可是F28335的中断线数是有限的,这个时候PIE模块来分配中断资源了。
从图中可以看出,
- 外部中断源均通过PIE模块进行判断处理
- 内部中断源中定时器1和定时器2单独通过INT13和INT14处理,其他也通过PIE模块处理
- PIE模块处理INT~INT12
- 总共16路中断线
2. 中断管理模块PIE
PIE模块作用是在有限中断线的情况下用来管理多个中断源触发。
2.1 PIE模块结构
PIE的结构如上图所示,PIE模块是由多个中断组和每个中断组的多路选择器构成的。从INT1~INT12均为PIE模块管理的可屏蔽中断,而这12个中断每个都由8个外设计中断组成,比如途中INT1.X对应的就是由INT1.1~INT1.8组成,这8个外设级中断就是我们对应的外部中断源引脚。
PIE模块通过一个8选1的多路选择器将这8个外设中断组成一组。我们在程序中配置的时候也是以这个结构为基础来配置的。
补充PIE响应的优先级
- INT1>INT2>...>INT12
- INT1.1>INT1.2>...>INT1.8
2.2 PIE模块的响应机制
PIE模块有这么多的外设需要管理,就必定有相应的响应顺序和寄存器需要配置。
在PIE模块内每组中断都有相应的中断标志位(PIEIFRx)和使能位(PIEIERx.y),除此之外,每组PIE中断(INT1~INT12)有一个响应标志位(PIEACK)。下图给出了PIEIFR和PIEIER不同设置时的PIE硬件的操作流程。
一旦PIE控制器有中断产生,相应的中断标志位(PIEIFRx.y)将置1。如果相应的PIE中断使能位也置1,则PIE将检查相应的PIEACKx以确定CPU是否准备响应该中断。如果相应的PIEACKx位清零,PIE向CPU申请中断;如果PIEACKx置1,PIE将等待到相应的PIEACKx清零才向CPU申请中断。PIE通过对PIEACKx的位控制来控制每1组中只有1个中断能被响应,一旦响应后,就需要将PIEACKx响应为清零,以让它能够响应该组中后边过来的中断。
举个例子,如果要使CPU反应INT1.1的中断。
就需要
- PIEIFR1.1标志位置1
- PIEIFR1.1使能位置1
- PIEIFR1.1响应标志位1
- IFR全局标志位置1(只对INT1~INT12)
- IER全局中断使能置1(只对INT1~INT12)
2.3 中断向量表
由于F28335各个中断源对应的地址是事先就设定好的,我们无法更改,所以中断向量表必须要备一张。
从图中可以看出
- INT1~INT12每个都对应8个外部中断
- 总共有96个可响应的资源,有很多富裕的资源
2.4 中断配置的简单实例
中断的配置是与PIE模块的响应机制完全对应的。
对外部中断XINT1进行配置。
第一步:
基础的初始化之后,对PIE模块进行指定,一般在InitPieVectTable();PIE模块初始化之后进行指定。
void main(void)
{
InitSysCtrl();
DINT;
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
EALLOW;
PieVectTable.XINT1 = &xint1_isr;
EDIS;
}
第二步:
打开PIE模块的时钟,经过查询中断向量表知道,外部中断XINT1在使能在INT1.4,打开这个中断使能。
void main(void)
{
InitSysCtrl();
DINT;
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
EALLOW;
PieVectTable.XINT1 = &xint1_isr; //赋予中断地址
EDIS;
IER |= M_INT1; //全局使能INT1
PieCtrlRegs.PIEIER1.bit.INTx4 = 1; //使能INT1.4
EINT;
ERTM;
}
当时我疑惑这个PIEIFR标志位置1去哪里了,其实中断响应的时候它是自动置1的。我们只要开使能使他能够顺利通过就好。
第三步:
就是在我们的中断里面写函数,并在中断里面清楚中断响应标志位PIEACK。
interrupt void xint1_isr(void)
{
Xint1Count++;
GpioDataRegs.GPACLEAR.all = 0x4;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}