对ZYNQ设备GPIO中断函数的详解 (二)

对ZYNQ设备GPIO中断函数的详解 (二)

1.XScuGic_CfgInitialize函数

函数整体观:

对ZYNQ设备GPIO中断函数的详解 (二)_第1张图片

1.1函数原型

s32  XScuGic_CfgInitialize(XScuGic *InstancePtr,XScuGic_Config *ConfigPtr, u32 EffectiveAddr)

  他需要传入三个参数XScuGic 结构体指针,XScuGic_Config结构体指针,以及u32的EffectiveAddr变量。

1.2 XScuGic 结构体

对ZYNQ设备GPIO中断函数的详解 (二)_第2张图片

  该结构没有什么好解释的了,第二个参数是当前是否准备好,第三个函数的含义我们后面会解释。

1.3 u32 Cpu_Id = CpuId + (u32)1;

static u32 CpuId = XPAR_CPU_ID; /**< CPU Core identifier */
/* Definition for CPU ID */
#define XPAR_CPU_ID 0U

由宏定义来看,这里定义的Cpu_Id变量,指向的是第二个CPU。

1.4 for (Int_Id = 0U; Int_Id

1.4.1首先关注此for循环的次数,XSCUGIC_MAX_NUM_INTR_INPUTS参数的值为宏定义

#define XSCUGIC_MAX_NUM_INTR_INPUTS	195U

为总共支持的中断个数。

1.4.2

/*
	* Initalize the handler to point to a stub to handle an
	* interrupt which has not been connected to a handler. Only
	* initialize it if the handler is 0 which means it was not
	* initialized statically by the tools/user. Set the callback
	* reference to this instance so that unhandled interrupts
	* can be tracked.
*/

  上面是官方对这个循环功能的描述,这个起始最开始的时候没有详细去理解,今天晚上的时候我又重新看了一下,他说,会初始化handler,让这个handler指向一个stub。Handler我把他理解成一个处理器,一般是一个函数或者结构。该处理器指向stub,stub指的是stub code,一种用于占坑的代码,称作桩代码给出的实现是临时性的/待编辑的。它使得程序在结构上能够符合标准,又能够使程序员可以暂时不编辑这段代码。

  用于处理还没有连接到这个中断所对应的处理器的中断。仅仅初始化那些,还没有被工具或者工程师静态初始化的handler。并设置回掉参考(callback reference),以使得那些未被处理的中断,可以被追踪。

1.4.3

if 	((InstancePtr->Config->HandlerTable[Int_Id].Handler == NULL)) {
				InstancePtr->Config->HandlerTable[Int_Id].Handler =
									StubHandler;
}

  这里就需要回忆一下Handler参数,我们通过上一博文可以知道,他是函数指针类型,为了方便观看,我将其截图:

对ZYNQ设备GPIO中断函数的详解 (二)_第3张图片

  这个是Config变量的类型。接着看到HandlerTable为XScuGic_VectorTableEntry类型,该类型上一博文中同样有叙述,截图如下:

对ZYNQ设备GPIO中断函数的详解 (二)_第4张图片

  同时,可以看到该结构中的Handler,为一个函数指针变量。并且Handler的值,由上一个博客可以看到,被初始化为0,即NULL。

  下面回到该If语句,则等号右边的StubHandler就是我们的残状函数:

static void StubHandler(void *CallBackRef) {
	/*
	 * verify that the inputs are valid
	 */
	Xil_AssertVoid(CallBackRef != NULL);

	/*
	 * Indicate another unhandled interrupt for stats
	 */
	((XScuGic *)((void *)CallBackRef))->UnhandledInterrupts++;
}

下面对于该stub函数加以解释:

  首先他的形参为一个返回值为Void*的函数。这种用法我们通过下图进行举例。

对ZYNQ设备GPIO中断函数的详解 (二)_第5张图片

((XScuGic *)((void *)CallBackRef))->UnhandledInterrupts++;

  着一句是这样的意思是,他将原本返回值为void类型的函数,强转为返回值为XScuGic类型的函数,并对返回值中的UnhandledInterrupts进行递增。

而对于这个操作,我使用下面代码作为示例。

#include 
typedef unsigned int u32;
struct type_trans{
	int age;
	int num;
};
type_trans type_trans_tmp = {0,0};
void StubHandler(void *CallBackRef(type_trans* type_trans_v), u32 Bank, u32 Status);
void* call_back(type_trans* type_trans_v);
void* test(int a);
void test_test(void* tmp(int));
int main()
{
	int tmp_num;
	printf("hello world!\n");
	test_test(test);//形参为函数,且该函数带参数 
	call_back(&type_trans_tmp);
	printf("main :age = %d , num = %d\n",type_trans_tmp.age,type_trans_tmp.num);
	StubHandler(call_back,0,0); 
	printf("main :age = %d , num = %d\n",type_trans_tmp.age,type_trans_tmp.num);
	((type_trans*)((void *)call_back(&type_trans_tmp)))->age += 1;
	((type_trans*)((void *)call_back(&type_trans_tmp)))->num += 1;
	printf("main :age = %d , num = %d\n",type_trans_tmp.age,type_trans_tmp.num);
	return 0;
} 
void test_test(void* tmp(int))
{
	printf("this is test_test function\n");
	tmp(2);
}
void* test(int a)
{
	printf("this is test function\n");
	printf("a = %d",a);
}
void StubHandler(void *CallBackRef(type_trans* type_trans_v), u32 Bank, u32 Status)
{
	CallBackRef(&type_trans_tmp);
	(void) Bank;
	(void) Status;
}
void* call_back(type_trans* type_trans_v)
{
	printf("this is call_back function\n");
	type_trans_v->age += 1; type_trans_v->num += 1;
	return type_trans_v;
}

其结果如下图:

对ZYNQ设备GPIO中断函数的详解 (二)_第6张图片

接着执行下面的代码:

InstancePtr->Config->HandlerTable[Int_Id].CallBackRef =InstancePtr;

  CallBackRef如下图,我们可以看到,他是一个返回值为Void行的回掉函数,这是我的初步想法,但是看到这里之后我眉头一皱,发现此事并不简单。这里void的用法,起始也是只起到占位的作用,它可以指向任何类型的地址,而这里显然是将void指向了XScuGic类型的变量了。

对ZYNQ设备GPIO中断函数的详解 (二)_第7张图片

  这里的意思是,我将全部195个中断的InstancePtr->Config->HandlerTable[Int_Id].CallBackRef全部都指向我的Gic中断控制器InstancePtr。我把这里理解成做备份,或者方便调用。

你可能感兴趣的:(ZYNQ)