软件环境:vivado 2017.4 硬件平台:XC7Z020
噹噹~又到了每月一更的时间,我真的是在是太懒了,最近小实验是做了不少,但是一打开CSDN,懒劲儿就上来了,只是回回评论就关了,也太违背初衷了,最近争取好好更一更新。
今天这篇主要说下怎样在zynq平台的microblaze上实现外部中断,之前大概搜了下相关的博客,在zynq上跑microblaze的资料并不多,大多还都是一个抄一个的,图都糊的看不清了,不过话说,zynq上已经有ARM硬核了,为什么还要用microblaze...问的好...姑且就当我无聊吧(其实也不是,因为方法是通用的,K系列和A系列没有ARM硬核的,就可以借鉴这里的microblaze中断方法了啊)。工程如下所示。
测试原理很简单,通过debug时候点击VIO,产生中断信号,中断信号通过AXI_INTC传递给microblaze,在microblaze中断函数内打断点,能进入断点,就认为中断被有效触发,这里右上角的zynq核只是个摆设,为啥只是个摆设还要放在那,最后会说。
编译生成bitstream完毕后,导入SDK,在SDK新建个microblaze的空工程,因为工程中即包含zynq核又包含microblaze核,所以在创建时候,一定注意红框处别选错了。
然后将三个文件加入到工程中,分别是main.c、sys_intr.c、sys_intr.h
main.c
#include "sys_intr.h"
#include "xintc.h"
#include "xparameters.h"
#define VIO_INTR_ID XPAR_INTC_0_DEVICE_ID
static XIntc Intc;
void VioHandler(void *CallbackRef);
void init_intr_sys(void);
void main(void)
{
init_intr_sys();
while(1);
}
void init_intr_sys(void)
{
Init_Intr_System(&Intc);
XIntc_Connect(&Intc, VIO_INTR_ID,
(Xil_ExceptionHandler)VioHandler, 0);
Intc_Enable(&Intc, VIO_INTR_ID);
Intc_Start(&Intc);
Setup_Intr_Exception(&Intc);
}
void VioHandler(void *CallbackRef)
{
usleep(5000);
}
sys_intr.c
#include "sys_intr.h"
#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID
void Setup_Intr_Exception(XIntc * IntcInstancePtr)
{
/* Enable interrupts from the hardware */
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XIntc_InterruptHandler,
(void *)IntcInstancePtr);
Xil_ExceptionEnable();
}
int Init_Intr_System(XIntc * IntcInstancePtr)
{
int Status;
Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
void Intc_Enable(XIntc *IntcInstancePtr,u16 Intr_Id)
{
XIntc_Enable(IntcInstancePtr, Intr_Id);
}
int Intc_Start(XIntc *IntcInstancePtr)
{
int Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);
if(Status != XST_SUCCESS){
return XST_FAILURE;
}
return XST_SUCCESS;
}
sys_intc.h
#ifndef SYS_INTR_H_
#define SYS_INTR_H_
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "XIntc.h"
int Init_Intr_System(XIntc * IntcInstancePtr);
void Intc_Enable(XIntc *IntcInstancePtr,u16 Intr_Id);
int Intc_Start(XIntc *IntcInstancePtr);
void setup_Intr_Exception(XIntc * IntcInstancePtr);
#endif /* SYS_INTR_H_ */
开始debug以后,可以看到zynq的核和microblaze的核都显示出来了,这里因为只跑microblaze,所以先单击最上面的红框,然后就在中间的红框看到函数的入口在main的init_intr_sys()中断初始化函数这里了,在最下方的中断函数的红框处记得加一个断点。
然后,先别急着点运行,因为中断的触发是通过VIO产生的,所以先去vivado那边, 进hardware manager,刷新一下,然后将VIO切换到active-high button模式。
接着再在SDK这边点运行,当点击vio时,可见,SDK这边,程序确实停止在中断函数的断点处了。
最后,说一下为什么zynq在这个工程里面没啥用,仍然还要摆在那里,因为如果不加zynq,虽然bitstream能够正常编译通过,SDK的程序也能够正常编译通过,但是在SDK的debug时候,你就会发现,会报出no arm processor的错误。
错误的原因是红框处缺少了zynq中arm的初始化文件,当然这个问题只会在zynq上跑microblaze但不加zynq核的时候会遇到,如果是k系列或者a系列,直接搭建microblaze的工程就可以。