试验硬件:正点原子领航者ZYNQ开发板(芯片xc7z020clg400-2)
试验软件:Vivado 2020.2与Vitis 2020.2
Vivado中的Block Design:
打开UART0,打开MIO与EMIO,EMIO位宽为1,正确设置DDR型号,设置FCLK为50MHz,VIO输出与EMIO输入对接,此时无需指定EMIO引脚,VIO输出默认为0。
Vitis中的代码:
#include "xil_printf.h"
#include "xgpiops.h"
#include "sleep.h"
#include "xparameters.h"
#include "xscugic.h"
#define EMIO0 54U
XGpioPs psGpio;
XScuGic scuGic;
void psGpio_Handler(void *CallBackRef);
int main(void)
{
xil_printf("begin!\r\n");
// 初始化psGpio
XGpioPs_Config *psGpio_configPtr;
psGpio_configPtr = XGpioPs_LookupConfig(XPAR_XGPIOPS_0_DEVICE_ID);
XGpioPs_CfgInitialize(&psGpio, psGpio_configPtr, psGpio_configPtr->BaseAddr);
// 打开系统的中断处理功能
Xil_ExceptionInit(); // 初始化异常句柄,只在很早版本的bsp中需要,此处为了兼容性保留
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler,
&scuGic); // 为IRQ注册中断处理程序
Xil_ExceptionEnable(); // 使能系统中断功能
// 初始化中断控制器
XScuGic_Config *scuGic_config;
scuGic_config = XScuGic_LookupConfig(XPAR_XSCUTIMER_0_DEVICE_ID); // 根据器件ID查找配置
XScuGic_CfgInitialize(&scuGic, scuGic_config, scuGic_config->CpuBaseAddress);
// 关联中断处理函数
XScuGic_Connect(&scuGic, XPAR_XGPIOPS_0_INTR, (Xil_ExceptionHandler)psGpio_Handler, (void *)&psGpio);
// 启用对应中断ID的中断源
XScuGic_Enable(&scuGic, XPAR_XGPIOPS_0_INTR);
// 注意psGPIO中断不需要设置中断优先级
// 设置psGPIO中断类型
XGpioPs_SetIntrTypePin(&psGpio, EMIO0, XGPIOPS_IRQ_TYPE_EDGE_RISING);
// 使能psGPIO中断
XGpioPs_IntrEnablePin(&psGpio, EMIO0);
while(1)
{
}
return 0;
}
void psGpio_Handler(void *CallBackRef)
{
XGpioPs *psGpioPtr = (XGpioPs *)CallBackRef;
if (XGpioPs_IntrGetStatusPin(psGpioPtr, EMIO0) == TRUE)
{
xil_printf("This is EMIO0 Interrupt!\r\n");
XGpioPs_IntrClearPin(psGpioPtr, EMIO0);
}
}
试验现象:
)
此时ZYNQ的启动方式为QSPI,也就是从FLASH启动。
可以看到第一次烧写打印了"This is EMIO Interrupt",这表示烧写后自动进了一次中断,而第二次烧写则未打印,表明烧写未进入此中断。不进中断才是对的。
当设置启动方式为JTAG,从JTAG启动后,看一下这种情况会不会消失。
从上图可见,设置为JTAG启动后,烧写后不会自动触发一次EMIO中断了。
还有一种更通用的办法是在GPIO PIN中断使能之前,先清除一次中断状态,也可以防止烧写自动进一次EMIO中断,即加入一行代码:
XGpioPs_IntrClearPin(&psGpio, EMIO0);
如下:
// 设置psGPIO中断类型
XGpioPs_SetIntrTypePin(&psGpio, EMIO0, XGPIOPS_IRQ_TYPE_EDGE_RISING);
// 使能之前先清除中断状态!
XGpioPs_IntrClearPin(&psGpio, EMIO0);
// 使能psGPIO中断
XGpioPs_IntrEnablePin(&psGpio, EMIO0);
推测造成这种现象的原因是烧写前EMIO被FLASH中的程序控制着,可能中断状态就是1,而烧写也没有清除中断状态寄存器,所以烧写后自动进了一次中断,所以QSPI模式出现此问题,而JTAG模式不出现。