MCU

ADSP-BF533 GPIO中断使用注意事项

0
阅读(4309)

今天本来只是想试一下GPIO中断的例程,不过在测试过程中发现了几个初学者比较难理解的问题,故此提出来,仅供参考。下面先给出PF口中断使能中跟中断关系较大的部分程序:

1694593154849.zip  项目文件       1694684418570.zip   exception头文件

#include <cdefBF533.h>

#include <sys\exception.h>      //中断处理相关头文件

EX_INTERRUPT_HANDLER(FlagA_ISR);//中断处理函数声明

void Init_Flags(void)

{

    *pFIO_INEN      |= PF0|PF1;  //注意端口输入应使能

    *pFIO_DIR       &=~(PF0|PF1);//端口方向应设置为输入

    *pFIO_EDGE      |= PF0|PF1;  //端口中断设置为边沿触发

    *pFIO_MASKA_D   |= PF0|PF1;  //设置PF0和PF1为中断源

}

void Init_Interrupts(void)

{

    *pSIC_IAR0 = 0xffffffff;

    *pSIC_IAR1 = 0xffffffff;

    *pSIC_IAR2 = 0xffff5fff;    //设置PFA口的中断优先级               

    register_handler(ik_ivg12, FlagA_ISR);  //注册中断函数 

    *pSIC_IMASK = 0x00080000;    //使能中断

}

EX_INTERRUPT_HANDLER(FlagA_ISR)

{

        if(*pFIO_FLAG_D == PF0)

        {

            printf("interrupt is PF0!\n");

        }

        else if(*pFIO_FLAG_D == PF1)

        {

            printf("interrupt is PF1!\n");

        }  

        *pFIO_FLAG_C = PF0|PF1; //清除中断锁存状态

}

void main(void)

{  

    Set_PLL(16,3);

    Init_Flags();

    Init_Interrupts();

    while(1);  //进入while循环等待中断

}

问题1:在程序中为什么要添加“exception.h”头文件,之前测试GPIO的时候也不用添加的?打开我们附件中的工程,我们可以试着把该句先注释掉,然后再编译该文件,就会出现下面的出错提示:

意思很明显,就是ik_ivg12和FlagA_ISR没有声明,那么这两个变量的定义应该是在exception文件中,打开附件中的exception文件,我们可以看到里面有ik_ivg12的定义,如下图所示,ik_ivg12在中断类型的枚举表中,该变量是根据中断优先级来选择的,而且变量名只能是枚举表中的某一个。

ik_ivg12是找到了,但是FlagA_ISR却找不到,我们再回到程序中,有三句是提到FlagA_ISR 的,1.“EX_INTERRUPT_HANDLER(FlagA_ISR)”;2.“register_handler(ik_ivg12, FlagA_ISR)”;3.“EX_INTERRUPT_HANDLER(FlagA_ISR)”。第一句,很明显是EX_INTERRUPT_HANDLER 中断处理函数的声明,而且该函数的原型在我们程序中也没有,它在头文件中应该至少有声明,于是我又回到exception文件中查找EX_INTERRUPT_HANDLER函数,果然不出我所料,在文件的确有下面的声明:#define EX_INTERRUPT_HANDLER(NAME)    EX_HANDLER(interrupt,NAME),该函数的作用是当中断优先级为interrupt时,进入中断变量名为NAME的中断处理函数。FlagA_ISR变量也是在该函数的声明中也同时声明的。第二句的函数是用来注册中断处理函数的,函数的作用是对中断函数进行注册,使得中断优先级ik_ivg12对应变量FlagA_ISR,而变量的名字可以由我们来改变,即FlagA_ISR是由我们来决定的,它的功能简单点说只是把中断注册函数和中断处理函数对应起来而已,只要注册函数ex_handler_fn register_handler(interrupt_kind int_kind, ex_handler_fn handler)和中断处理函数EX_INTERRUPT_HANDLER(ex_handler_fn handler)中的ex_handler_fn handler变量名一致就行啦。这个自己修改一下便知道啦。

 

问题2:在程序中为何要设置PF0和PF1的端口方向为输入?答案很简单,既然PF0和PF1作为中断响应端口,那么芯片内部的硬件电路肯定是要对它的状态进行读取判断的,然后才能根据读取的状态进入中断响应函数,所以PF1和PF0应该设置为输入属性。

 

问题3:在中断处理函数的最后为何要加上“*pFIO_FLAG_C = PF0|PF1”语句,有何作用?记得之前学习GPIO的时候知道pFIO_FLAG_C寄存器是一个16位的寄存器,它的功能是清除PF口任意一位IO口的状态,那为什么在中断处理函数的最后要加上这一句呢,我也很疑惑,于是我又打开了VisualDSP++中help里面的Search,查找pFIO_FLAG_C寄存器的相关说明,果然功夫不负有心人,查到的资料说明如下:

内容的第一点是说FIO_FLAG_S, FIO_FLAG_C, and FIO_FLAG_T 这三个寄存器是用来设置、清除和触发连接到每一个PFx口的输出状态的;第二点是说寄存器可以用来清除从PFx口捕捉到的中断锁存状态,因为只有FIO_FLAG_C寄存器有清除功能,所以说的应该就是该寄存器。很明显,程序中的语句实现的就是第二点的功能。现在我们知道该句是用来清除中断锁存状态的,那么为什么中断处理函数最后要清除该状态呢,那是因为BF533在退出中断处理函数之前没有通过硬件清除这个锁存状态,如果我们不能过软件进行清除,那么系统将不断地进入中断处理函数。
最后说一下本中断函数的一个整体思路:首先是通过PLL设置系统的时钟,然后是PF口属性设置和中断初始化,然后就进入While循环,当PF0或者PF1突然的电平变化时系统进入中断处理函数EX_INTERRUPT_HANDLER(FlagA_ISR),执行完函数中的语句后自动返回主程序中继续之前工作,即继续While循环,然后如果有中断,又是进入中断返回主程序这样不断地循环。以上就是中断的处理过程,至此,对于GPIO中断的学习也就告一段落。