#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() 即可. 至于中断函数连接什么的,在各个模块用得到的地方直接引用. 这可以减少大部分的重复代码.