中断是一个信号,它使CPU暂停当前的执行,并转移到另一段被称为中断服务例程(ISR)的代码。这是种用于处理外围事件的有用机制,与寄存器轮询相比,它涉及更少的CPU开销或程序复杂性。但是,由于中断对程序流是异步的,因此必须注意避免在中断和主程序代码中访问的资源上发生冲突。
中断通过一系列标志传播到CPU并启用寄存器。标志寄存器存储中断,直到它被处理。使能寄存器阻止中断的传播。当一个中断信号到达CPU时,CPU从一个叫做向量表的列表中获取适当的ISR地址。
如下图所示,器件支持五个外部中断(XINT1 到 XINT5),这些中断可以映射到任何 GPIO 引脚上。
在此器件中,16 个 ePIE 块中断分组为 1 个 CPU 中断。共 12 个 CPU 中断组,每组 16 个中断。12个通过增强型外设中断扩展模块 (ePlE,或简称PLE)连接到外设中断信号。PE多路复用多达16个外设中断到每个CPU中断线。它还扩展了向量表,允许每个中断有它自己的ISR。这使得CPU能够支持大量的外围设备。
中断路径分为三个阶段,外围设备、PIE和CPU。每个阶段都有自己的使能和标志寄存器。该系统允许CPU处理一个中断,而其他中断正在等待,在软件中实现嵌套中断并对其排序,并在某些关键任务中禁用中断。
2.1 外部中断配置步骤
外部中断相关函数及寄存器在 F2837xS_PieCtrl.c、F2837xS_PieVect.c以及 F2837xS_GlobalVariableDefs.c 文件及其对应的头文件内查找到。
(1)失能 CPU 级中断,并初始化 PIE 控制器寄存器和 PIE 中断向量表
代码如下:
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
EALLOW; // 打开写入
PieVectTable.XINT1_INT = &xint1_isr; //绑定中断向量函数地址入口
PieVectTable.XINT2_INT = &xint2_isr; //绑定中断向量函数地址入口
EDIS; // 禁用写入
(2)在PIE中使能XINT1和XINT2,中断组1的中断4和5,使能INT1
PieCtrlRegs.PIECTRL.bit.ENPIE = 1; //使能PIE
PieCtrlRegs.PIEIER1.bit.INTx4 = 1; // 使能PIE1组的 INT4
PieCtrlRegs.PIEIER1.bit.INTx5 = 1; // 使能PIE1组的 INT5
IER |= M_INT1; // 使能 CPU INT1
EINT; // 中断使能
(3)使能 IO 口时钟,配置 IO 口为输入
GPIO_SetupPinMux(54, GPIO_MUX_CPU1, 0);
//第一个参数为IO口,第二个参数为内核,在F2837xS_Gpio _defines.h里可找到;第三个参数为选择IO口的复用功能,复用功能介绍在F28377的数据手册中的多路复用引脚图。
GPIO_SetupPinOptions(54, GPIO_OUTPUT, GPIO_PUSHPULL);
//设置为输出上拉
GPIO_SetupPinMux(55, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(55, GPIO_INPUT, GPIO_SYNC);
//IO口55,设置为输入,频率跟随系统
(5)中断绑定引脚
GPIO_SetupXINT1Gpio(54); //外部中断1绑定引脚54
GPIO_SetupXINT2Gpio(55); //外部中断2绑定引脚55
(6)设置中断触发方式
XintRegs.XINT1CR.bit.POLARITY = 0; //下降沿触发
XintRegs.XINT2CR.bit.POLARITY = 1; // 上升沿触发
(7)使能中断组
XintRegs.XINT1CR.bit.ENABLE = 1; //使能外部中断1 XINT1
XintRegs.XINT2CR.bit.ENABLE = 1; //使能外部中断2 XINT2
(8)编写外部中断服务函数
配置好中断后如果有触发,即会进入中断服务函数,中断服务函数名在前面已定义好,所以要保证一致,否则将不会进入中断服务函数内执行。
要在中断服务函数名前加上关键字 interrupt。
interrupt void xint1_isr(void)
{
...功能程序
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
//在中断执行结束前要清除相应的中断标志位,以等待下次中断的到来。
}
interrupt void xint2_isr(void)
{
...此处为自定义代码
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
//在中断执行结束前要清除相应的中断标志位,以等待下次中断的到来。
}