zynq中异常处理函数XScuGic_DeviceInterruptHandler与XScuGic_InterruptHandler区别

发布于:2024-10-13 ⋅ 阅读:(56) ⋅ 点赞:(0)

#define XIL_EXCEPTION_ID_RESET			0U
#define XIL_EXCEPTION_ID_UNDEFINED_INT		1U
#define XIL_EXCEPTION_ID_SWI_INT		2U
#define XIL_EXCEPTION_ID_PREFETCH_ABORT_INT	3U
#define XIL_EXCEPTION_ID_DATA_ABORT_INT		4U
#define XIL_EXCEPTION_ID_IRQ_INT		5U
#define XIL_EXCEPTION_ID_FIQ_INT		6U
#define XIL_EXCEPTION_ID_LAST			6U

/*
 * XIL_EXCEPTION_ID_INT is defined for all Xilinx processors.
 */
#define XIL_EXCEPTION_ID_INT	XIL_EXCEPTION_ID_IRQ_INT


	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, (Xil_ExceptionHandler)XScuGic_DeviceInterruptHandler,  (void *)INTC_DEVICE_ID);Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, (void *)IntcInstPtr);

有的异常是注册的XScuGic_InterruptHandler处理函数 , 有的地方需要注册XScuGic_DeviceInterruptHandler处理函数.

很明显XIL_EXCEPTION_ID_IRQ_INT 就是等价的. XIL_EXCEPTION_ID_IRQ_INT
那么后注册的会覆盖先注册的. 程序就会不正常. 到底应该用哪个呢?
通过仔细的比较两个处理函数发现, 一个的参数是指针 , 一个的参数是一个中断号
其它的代码, 功能是一模一样的, (虽然一个是XScuGic_CPUReadReg,一个是XScuGic_ReadReg), 但是从功能上来讲是一模一样的, 由此可知. 这两个函数就是同一个函数的重构.
XScuGic_DeviceInterruptHandler 更适合在只只知道中断设备ID的时候使用, 而XScuGic_InterruptHandler 更适合在有设备指针的时候使用.

但是这两种风格的代码不应该同时使用, 要么使用指针形式的, 要么使用字符串ID形式的…
否则多次混合使用必然会出现指针问题.
我感觉异常处理相关的代码整个程序只需要写一次,并且执行一次即可. 不需要写多次. 否则必然会出现一些问题.

我建议如下:

 
#include "zynq_global_var.h"

XIicPs     xIicPsInst; //I2C实例
XScuGic  xScuGicInst; /* 中断控制器实例 */
XGpioPs xGpioInst;    //GPIO实例
XUartPs  xUart0Inst;
XUartPs  xUart1Inst;
XQspiPs  xQspiPsInst;
//XScuTimer xScuTimer;

int InitQSPI(u16 deviceid) {
   // int Status;

    // 查找QSPI设备并初始化
    XQspiPs_Config *ConfigPtr;
	ConfigPtr = XQspiPs_LookupConfig(deviceid);
	XQspiPs_CfgInitialize(&xQspiPsInst, ConfigPtr, ConfigPtr->BaseAddress);

//    // 设置QSPI的工作模式,例如SPI模式,时钟速率等
//    XQspiPs_SetClkPrescaler(&xQspiPs, XQSPIPS_CLK_PRESCALER_8);
//    XQspiPs_SetOptions(&xQspiPs, XQSPIPS_MANUAL_START_ENABLE_OPTION);

    // 可能还需要配置Flash芯片特有的指令集和模式
    // 这取决于你的Flash芯片和它的数据手册

    return XST_SUCCESS;
}

void  InitGPIO( u16 deviceid )
{
	XGpioPs_Config *ConfigPtr;
	ConfigPtr = XGpioPs_LookupConfig(deviceid);
	XGpioPs_CfgInitialize(&xGpioInst, ConfigPtr, ConfigPtr->BaseAddr);
}


void  InitUart( u16 deviceid )
{
	XUartPs_Config *ConfigPtr;
	ConfigPtr = XUartPs_LookupConfig(deviceid);
	XUartPs_CfgInitialize(&xUart0Inst, ConfigPtr, ConfigPtr->BaseAddress);
}

void  InitScuGic(  u16 deviceid)
{
	// 查找中断控制器配置信息并初始化中断控制器驱动
	XScuGic_Config *IntcConfig; /*  of the interrupt controller */
	IntcConfig = XScuGic_LookupConfig(deviceid);
	XScuGic_CfgInitialize(&xScuGicInst, IntcConfig, IntcConfig->CpuBaseAddress);
}

void  InitI2C(  u16 deviceid)
{
	XIicPs_Config *IntcConfig;
	IntcConfig = XIicPs_LookupConfig(deviceid);
	XIicPs_CfgInitialize(&xIicpsInst, IntcConfig, IntcConfig->BaseAddress);
}

void  ExceptionInit( )
{
		//一定要先执行InitScuGic()

		//初始化ARM处理器异常句柄
		Xil_ExceptionInit();
		//通过调用该函数,给IRQ异常处理注册程序(IRQ:中断请求)
		Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,  (Xil_ExceptionHandler)XScuGic_InterruptHandler, &xScuGicInst);
		// 使能处理器中断
		Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
		Xil_ExceptionEnable();

}
 


void InitAllZynqInstance()
{
//	InitGPIO(   XPAR_XGPIOPS_0_DEVICE_ID );
	InitScuGic( XPAR_SCUGIC_SINGLE_DEVICE_ID  );
//	InitI2C(      XPAR_XIICPS_0_DEVICE_ID   );
	InitUart(    XPAR_XUARTPS_0_DEVICE_ID   );//初始化串口0
//	InitUart(    XPAR_XUARTPS_1_DEVICE_ID   );//初始化串口1

//	InitQSPI(   XPAR_XQSPIPS_0_DEVICE_ID   );
	InitScuTimer(  XPAR_XSCUTIMER_0_DEVICE_ID );
//
	ExceptionInit( );//这个一定要执行, 否则会有些功能不能使用
}

整个程序只需要运行一个InitAllZynqInstance() 即可. 至于中断函数连接什么的,在各个模块用得到的地方直接引用. 这可以减少大部分的重复代码.