最近在看广州创龙给的GPIO_KEY_EDMA例程代码时,关于中断有个问题不太明白,请教下各位。创龙给的代码中,当GPIObank0P6下降沿触发中断后,在中断服务函数中会清除EVTFLAG2寄存器的EF65位,然后还会清除INTSTAT01寄存器GP0P6位。但是我把这两句注释掉之后,发现没有任何影响,程序不会不断地重复进入中断服务程序中,只有当我按下按键,在GP0P6产生下降沿触发时,程序才能进入中断服务子程序。我原来的理解是,中断服务程序中,如果不把中断标志位清除,程序一退出,又会立马进入中断服务程序。现在的结果和这不一样,是我理解有误吗?请各位大师给我指点下迷津。代码如下:
/****************************************************************************/ /**/ /*中断服务函数*/ /**/ /****************************************************************************/ void USER0KEYIsr(void) {// 禁用 GPIO BANK 0 中断GPIOBankIntDisable(SOC_GPIO_0_REGS, 0);// 清除 GPIO BANK 0 中断事件 //IntEventClear(SYS_INT_GPIO_B6INT);IntEventClear(SYS_INT_GPIO_B0INT);if(GPIOPinIntStatus(SOC_GPIO_0_REGS, 7) == GPIO_INT_PEND){ // 清除中断状态 GPIOPinIntClear(SOC_GPIO_0_REGS, 7); // 核心板 LED unsigned int i; GPIOPinWrite(SOC_GPIO_0_REGS, 110, GPIO_PIN_HIGH); for(i=0x00FFFFFF;i>0;i--);// 延时 GPIOPinWrite(SOC_GPIO_0_REGS, 110, GPIO_PIN_LOW);} // 使能 GPIO BANK 6 中断GPIOBankIntEnable(SOC_GPIO_0_REGS, 0); // 释放之前分配的 EDMA3 通道 EDMA3FreeChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA, chNum, trigMode, tccNum, evtQ); // EDMA3 初始化 EDMA3GpioInit(); } /****************************************************************************/ /**/ /*GPIO 管脚中断初始化*/ /**/ /****************************************************************************/ void GPIOBankPinInterruptInit(void) {// 底板按键中断// 配置 USER0 KEY GPIO0[6] 为下降沿触发GPIOIntTypeSet(SOC_GPIO_0_REGS, 7, GPIO_INT_TYPE_FALLEDGE);// 使能 GPIO BANK 中断GPIOBankIntEnable(SOC_GPIO_0_REGS, 0);// USER0 KEY GPIO0 // 注册中断服务函数 IntRegister(C674X_MASK_INT6, USER0KEYIsr); // 映射中断到 DSP 可屏蔽中断 IntEventMap(C674X_MASK_INT6, SYS_INT_GPIO_B0INT); // 使能 DSP 可屏蔽中断 IntEnable(C674X_MASK_INT6); } /****************************************************************************/ /**/ /*主函数*/ /**/ /****************************************************************************/ int main(void) { // 外设使能配置 PSCInit(); // 管脚复用配置 GPIOBankPinMuxSet(); // GPIO 管脚初始化 GPIOBankPinInit(); // DSP 中断初始化 InterruptInit(); // GPIO 管脚中断初始化 GPIOBankPinInterruptInit(); // EDMA3 初始化 EDMA3GpioInit(); // 主循环 for(;;) { } }
Shine:
在中断处理程序中要清一下EVTFLAG,INTSTAT,否则如果程序还运行在中断处理程序中,这时又有中断来的话,这个中断就不能被识别了。请看下面的文档说明。7.4.2 CPU Servicing of Interrupt Eventshttp://www.ti.com/lit/ug/sprufk5a/sprufk5a.pdf
yuke yang:
回复 Shine:
谢谢Shine Zhang,不过我还是不太明白,手册中这段话
It is also important to note that within the service routine, the appropriate event flag register bits must becleared by software in order to receive a subsequent event. If the event flag(s) does not clear, then a newsystem event will not be recognized.
这里说的新的系统事件无法识别是指如果在中断子程序中不清中断标志位,在中断子程序运行中发生的新的其他中断事件无法被识别,还是说即使退出了该中断子程序,其他中断事件也无法再被识别了?我感觉实际和这两个解释都不太一样啊。
我试了一下,两个按键user0和user1中断服务程序,分别对应GPIObank0和GPIObank6中断,我在user0中设置了断点,当进入user0停在断点的时候,我按下按键1触发GPIObank6中断,当程序退出user0中断服务程序的时候,会进入到user1中断服务程序,这就说明程序还运行在user0中断服务程序的时候,是能够识别其他中断事件的,可我在中断程序中已经屏蔽了清除中断标志EVTFLAG和INTSTAT的语句了啊。
可以再麻烦一下给我解释下吗?
yuke yang:
回复 Shine:
补上user0和user1的中断服务程序,user1中清除相关中断标志的语句已经被我注释了。
void USER0KEYIsr(void) {// 软件断点 方便调试//SW_BREAKPOINT;// 禁用 GPIO BANK 0 中断GPIOBankIntDisable(SOC_GPIO_0_REGS, 0);// 清除 GPIO BANK 0 中断状态IntEventClear(SYS_INT_GPIO_B0INT);if(GPIOPinIntStatus(SOC_GPIO_0_REGS, 7) == GPIO_INT_PEND){// 清除 GPIO0[6] 中断状态GPIOPinIntClear(SOC_GPIO_0_REGS, 7);Flag=0;}// 使能 GPIO BANK 0 中断GPIOBankIntEnable(SOC_GPIO_0_REGS, 0); }void USER1KEYIsr(void) {// 软件断点 方便调试//SW_BREAKPOINT;// 禁用 GPIO BANK 6 中断GPIOBankIntDisable(SOC_GPIO_0_REGS, 6);// 清除 GPIO BANK 6 中断状态 //IntEventClear(SYS_INT_GPIO_B6INT);if(GPIOPinIntStatus(SOC_GPIO_0_REGS, 98) == GPIO_INT_PEND){// 清除 GPIO6[1] 中断状态 //GPIOPinIntClear(SOC_GPIO_0_REGS, 98);Flag=1;}// 使能 GPIO BANK 6 中断GPIOBankIntEnable(SOC_GPIO_0_REGS, 6); }
Shine:
回复 yuke yang:
1. 这里说的新的系统事件无法识别是指如果在中断子程序中不清中断标志位,在中断子程序运行中发生的新的该中断事件无法被识别,因为这个标志位一直是置1的,如果新的该中断来也是置1,这会识别不出新的中断。
2. 其他中断没问题,因为用的是不同的标志位。
yuke yang:
回复 Shine:
谢谢shine,不过我实际试了一下好像和你说的不太一样。我在中断服务函数USER0中把禁用GPIO bank0中断和清除EVTFLAG寄存器两句话都注释了,并且在该中断函数里设置了一个断点,当我第一次按下user0按键进入该函数后,程序运行到该中断函数的断点位置,此时,我又一次按下user0按键,按照你的说法,因为没有清除中断标志,所以第二次按下按键(在GPIO bank0 pin6产生下降沿,触发中断)这个中断事件没法捕捉到,但是实际上当我退出该中断函数后,程序会再次进入user0中断服务函数,说明第二次中断其实是有识别到的,这又是为什么呀?
Shine:
回复 yuke yang:
要更正一下,如果你的单个中断是直接映射到interrupt selector的话,不用清EVTFLAGx。
For the case where the CPU services single-event interrupts (where system events are specified directlyin the Interrupt Selector), there is no need to read or clear the Event Flag (EVTFLAGx) registers in theInterrupt Controller.