[X]关闭
0

(基础篇)S05-CH05-GPIO-Interrupt

摘要: 中断的概念想必大家在学习中已经碰到过很多,也很熟悉什么是中断了。中断的重要性不严而喻,本节课就将为大家介绍在MicroBlaze中如何设计中断。不同于其他器件,MIcroBlaze的中断需要借助一个中断控制器(INTC)来管 ...

软件版本:VIVADO2017.4

操作系统:WIN10

硬件平台: ARTIX-7 系列开发板

米联客(MSXBO)论坛www.osrc.cn答疑解惑专栏开通,欢迎大家给我提供!!!

5.1 概述

      中断的概念想必大家在学习中已经碰到过很多,也很熟悉什么是中断了。中断的重要性不严而喻,本节课就将为大家介绍在MicroBlaze中如何设计中断。不同于其他器件,MIcroBlaze的中断需要借助一个中断控制器(INTC)来管理中断,所以要学会INTC的使用,INTC的使用方法稍后会为大家详细的讲解。

5.2 硬件工程搭建

Step1:创建一个新的vivado工程,命令为System.

Step2:将第一章生成的tcl文件复制到当前文件目录中来,并在tcl控制台中输入如下指令(注意tcl文件路径根据自身情况进行调整):

Step3:点击IP添加图标,输入关键字intc,添加一个intc.

Step4:点击Run connection Automation,然后直接单击OK。

Step5:连接intc的Interrupt和MicroBlaze的INTERRUPT。

 

Step6:单击添加IP图标,添加一个GPIO。

Step7:双击GPIO,然后修改配置如下:

Step8:单击Run connection Automation,然后勾选所有复选框,最后点击OK。

Step9:连接GPIO的中断输出引脚和intc的中断输入引脚。并将GPIO的引脚引出。

Step10:再添加一个GPIO,然后修改配置如下所示:

Step11:单击Run connection  Automation,勾选所有的复选框,然后单击OK。将GPIO的引脚引出。


5.3软件设计

Step1:单击File-New-Application Project开始创建一个SDK工程。

Step2:在新弹出来的窗口中,输入工程名字Interrupt(注意不能有非法字符)。

Step3:单击Next,然后在左侧选择Empty Application(空白工程),最后选择Finish。

Step4:在我们提供的源代码中,找到sdk_src文件夹,然后复制里面的sys_intr.h,sys_intr.c,main.c文件。

Step5:选中Interrupt下的src,然后按Ctrl+V将刚才复制的文件拷贝到工程中。

Step6:选中SDK工程文件,右单击选择Debug as-Debug configuration。

Step7:在弹出来的新窗口中,勾选Reset entire system和Program FPGA。

Step8:单击Apply,然后单击Debug(进行这一步之前,先给开发板上电)。

5.4 程序分析 

       开始程序分析之前,有必要先看看官方提供的GPIO中断的历程,通过这个历程可以帮助我们来设计我们想要的功能,现在我们就先看看这个历程的内容,见下表:

/***************************** Include Files *********************************/


#include "xparameters.h"

#include "xgpio.h"

#include "xil_exception.h"


#ifdef XPAR_INTC_0_DEVICE_ID

 #include "xintc.h"

 #include

#else

 #include "xscugic.h"

 #include "xil_printf.h"

#endif


/************************** Constant Definitions *****************************/

#ifndef TESTAPP_GEN

/*

 * The following constants map to the XPAR parameters created in the

 * xparameters.h file. They are defined here such that a user can easily

 * change all the needed parameters in one place.

 */

#define GPIO_DEVICE_ID XPAR_GPIO_0_DEVICE_ID

#define GPIO_CHANNEL1 1


#ifdef XPAR_INTC_0_DEVICE_ID

 #define INTC_GPIO_INTERRUPT_ID XPAR_INTC_0_GPIO_0_VEC_ID

 #define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID

#else

 #define INTC_GPIO_INTERRUPT_ID XPAR_FABRIC_AXI_GPIO_1_IP2INTC_IRPT_INTR

 #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID

#endif /* XPAR_INTC_0_DEVICE_ID */


/*

 * The following constants define the positions of the buttons and LEDs each

 * channel of the GPIO

 */

#define GPIO_ALL_LEDS 0xFFFF

#define GPIO_ALL_BUTTONS 0xFFFF


/*

 * The following constants define the GPIO channel that is used for the buttons

 * and the LEDs. They allow the channels to be reversed easily.

 */

#define BUTTON_CHANNEL  1 /* Channel 1 of the GPIO Device */

#define LED_CHANNEL  2 /* Channel 2 of the GPIO Device */

#define BUTTON_INTERRUPT XGPIO_IR_CH1_MASK  /* Channel 1 Interrupt Mask */


/*

 * The following constant determines which buttons must be pressed at the same

 * time to cause interrupt processing to stop and start

 */

#define INTERRUPT_CONTROL_VALUE 0x7


/*

 * The following constant is used to wait after an LED is turned on to make

 * sure that it is visible to the human eye.  This constant might need to be

 * tuned for faster or slower processor speeds.

 */

#define LED_DELAY 1000000


#endif /* TESTAPP_GEN */


#define INTR_DELAY 0x00FFFFFF


#ifdef XPAR_INTC_0_DEVICE_ID

 #define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID

 #define INTC XIntc

 #define INTC_HANDLER XIntc_InterruptHandler

#else

 #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID

 #define INTC XScuGic

 #define INTC_HANDLER XScuGic_InterruptHandler

#endif /* XPAR_INTC_0_DEVICE_ID */


/************************** Function Prototypes ******************************/

void GpioHandler(void *CallBackRef);


int GpioIntrExample(INTC *IntcInstancePtr, XGpio *InstancePtr,

u16 DeviceId, u16 IntrId,

u16 IntrMask, u32 *DataRead);


int GpioSetupIntrSystem(INTC *IntcInstancePtr, XGpio *InstancePtr,

u16 DeviceId, u16 IntrId, u16 IntrMask);


void GpioDisableIntr(INTC *IntcInstancePtr, XGpio *InstancePtr,

u16 IntrId, u16 IntrMask);


/************************** Variable Definitions *****************************/


/*

 * The following are declared globally so they are zeroed and so they are

 * easily accessible from a debugger

 */

XGpio Gpio; /* The Instance of the GPIO Driver */


INTC Intc; /* The Instance of the Interrupt Controller Driver */



static u16 GlobalIntrMask; /* GPIO channel mask that is needed by

    * the Interrupt Handler */


static volatile u32 IntrFlag; /* Interrupt Handler Flag */


/****************************************************************************/

/**

* This function is the main function of the GPIO example.  It is responsible

* for initializing the GPIO device, setting up interrupts and providing a

* foreground loop such that interrupt can occur in the background.

*

* @param None.

*

* @return

* - XST_SUCCESS to indicate success.

* - XST_FAILURE to indicate failure.

*

* @note None.

*

*****************************************************************************/

#ifndef TESTAPP_GEN

int main(void)

{

int Status;

u32 DataRead;


  print(" Press button to Generate Interrupt\r\n");


  Status = GpioIntrExample(&Intc, &Gpio,

   GPIO_DEVICE_ID,

   INTC_GPIO_INTERRUPT_ID,

   GPIO_CHANNEL1, &DataRead);


if (Status == 0 ){

if(DataRead == 0)

print("No button pressed. \r\n");

else

print("Gpio Interrupt Test PASSED. \r\n");

} else {

 print("Gpio Interrupt Test FAILED.\r\n");

 return XST_FAILURE;

}


return XST_SUCCESS;

}

#endif


/******************************************************************************/

/**

*

* This is the entry function from the TestAppGen tool generated application

* which tests the interrupts when enabled in the GPIO

*

* @param IntcInstancePtr is a reference to the Interrupt Controller

* driver Instance

* @param InstancePtr is a reference to the GPIO driver Instance

* @param DeviceId is the XPAR__DEVICE_ID value from

* xparameters.h

* @param IntrId is XPAR___IP2INTC_IRPT_INTR

* value from xparameters.h

* @param IntrMask is the GPIO channel mask

* @param DataRead is the pointer where the data read from GPIO Input is

* returned

*

* @return

* - XST_SUCCESS if the Test is successful

* - XST_FAILURE if the test is not successful

*

* @note None.

*

******************************************************************************/

int GpioIntrExample(INTC *IntcInstancePtr, XGpio* InstancePtr, u16 DeviceId,

u16 IntrId, u16 IntrMask, u32 *DataRead)

{

int Status;

u32 delay;


/* Initialize the GPIO driver. If an error occurs then exit */

Status = XGpio_Initialize(InstancePtr, DeviceId);

if (Status != XST_SUCCESS) {

return XST_FAILURE;

}


Status = GpioSetupIntrSystem(IntcInstancePtr, InstancePtr, DeviceId,

IntrId, IntrMask);

if (Status != XST_SUCCESS) {

return XST_FAILURE;

}


IntrFlag = 0;

delay = 0;


while(!IntrFlag && (delay < INTR_DELAY)) {

delay++;

}


GpioDisableIntr(IntcInstancePtr, InstancePtr, IntrId, IntrMask);


*DataRead = IntrFlag;


return Status;

}



/******************************************************************************/

/**

*

* This function performs the GPIO set up for Interrupts

*

* @param IntcInstancePtr is a reference to the Interrupt Controller

* driver Instance

* @param InstancePtr is a reference to the GPIO driver Instance

* @param DeviceId is the XPAR__DEVICE_ID value from

* xparameters.h

* @param IntrId is XPAR___IP2INTC_IRPT_INTR

* value from xparameters.h

* @param IntrMask is the GPIO channel mask

*

* @return XST_SUCCESS if the Test is successful, otherwise XST_FAILURE

*

* @note None.

*

******************************************************************************/

int GpioSetupIntrSystem(INTC *IntcInstancePtr, XGpio *InstancePtr,

u16 DeviceId, u16 IntrId, u16 IntrMask)

{

int Result;


GlobalIntrMask = IntrMask;


#ifdef XPAR_INTC_0_DEVICE_ID


#ifndef TESTAPP_GEN

/*

 * Initialize the interrupt controller driver so that it's ready to use.

 * specify the device ID that was generated in xparameters.h

 */

Result = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID);

if (Result != XST_SUCCESS) {

return Result;

}

#endif /* TESTAPP_GEN */


/* Hook up interrupt service routine */

XIntc_Connect(IntcInstancePtr, IntrId,

      (Xil_ExceptionHandler)GpioHandler, InstancePtr);


/* Enable the interrupt vector at the interrupt controller */

XIntc_Enable(IntcInstancePtr, IntrId);


#ifndef TESTAPP_GEN

/*

 * Start the interrupt controller such that interrupts are recognized

 * and handled by the processor

 */

Result = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);

if (Result != XST_SUCCESS) {

return Result;

}

#endif /* TESTAPP_GEN */


#else /* !XPAR_INTC_0_DEVICE_ID */


#ifndef TESTAPP_GEN

XScuGic_Config *IntcConfig;


/*

 * Initialize the interrupt controller driver so that it is ready to

 * use.

 */

IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);

if (NULL == IntcConfig) {

return XST_FAILURE;

}


Result = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,

IntcConfig->CpuBaseAddress);

if (Result != XST_SUCCESS) {

return XST_FAILURE;

}

#endif /* TESTAPP_GEN */


XScuGic_SetPriorityTriggerType(IntcInstancePtr, IntrId,

0xA0, 0x3);


/*

 * Connect the interrupt handler that will be called when an

 * interrupt occurs for the device.

 */

Result = XScuGic_Connect(IntcInstancePtr, IntrId,

 (Xil_ExceptionHandler)GpioHandler, InstancePtr);

if (Result != XST_SUCCESS) {

return Result;

}


/* Enable the interrupt for the GPIO device.*/

XScuGic_Enable(IntcInstancePtr, IntrId);

#endif /* XPAR_INTC_0_DEVICE_ID */


/*

 * Enable the GPIO channel interrupts so that push button can be

 * detected and enable interrupts for the GPIO device

 */

XGpio_InterruptEnable(InstancePtr, IntrMask);

XGpio_InterruptGlobalEnable(InstancePtr);


/*

 * Initialize the exception table and register the interrupt

 * controller handler with the exception table

 */

Xil_ExceptionInit();


Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,

 (Xil_ExceptionHandler)INTC_HANDLER, IntcInstancePtr);


/* Enable non-critical exceptions */

Xil_ExceptionEnable();


return XST_SUCCESS;

}


/******************************************************************************/

/**

*

* This is the interrupt handler routine for the GPIO for this example.

*

* @param CallbackRef is the Callback reference for the handler.

*

* @return None.

*

* @note None.

*

******************************************************************************/

void GpioHandler(void *CallbackRef)

{

XGpio *GpioPtr = (XGpio *)CallbackRef;


IntrFlag = 1;


/* Clear the Interrupt */

XGpio_InterruptClear(GpioPtr, GlobalIntrMask);


}


/******************************************************************************/

/**

*

* This function disables the interrupts for the GPIO

*

* @param IntcInstancePtr is a pointer to the Interrupt Controller

* driver Instance

* @param InstancePtr is a pointer to the GPIO driver Instance

* @param IntrId is XPAR___VEC

* value from xparameters.h

* @param IntrMask is the GPIO channel mask

*

* @return None

*

* @note None.

*

******************************************************************************/

void GpioDisableIntr(INTC *IntcInstancePtr, XGpio *InstancePtr,

u16 IntrId, u16 IntrMask)

{

XGpio_InterruptDisable(InstancePtr, IntrMask);

#ifdef XPAR_INTC_0_DEVICE_ID

XIntc_Disable(IntcInstancePtr, IntrId);

#else

/* Disconnect the interrupt */

XScuGic_Disable(IntcInstancePtr, IntrId);

XScuGic_Disconnect(IntcInstancePtr, IntrId);

#endif

return;

}

      仔细的阅读上面的程序段,我们可以大致的总结出中断建立的一个流程,其主要位于GpioSetupIntrSystem这个函数当中,它是这么一个流程:

1

Intc初始化

2

连接中断

3

使能Intc

4

开启Intc

5

使能相应的中断

6

初始化中断异常处理程序


       基于上面的流程,其中1,3-4,6是所有的中断程序都适用的流程,因此可以建议另写一个c文件来保存这些程序段,好在后面继续调用。OK,了解了中断的设置流程就可以正式开始本章程序的讲解了。

       首先,开始设置中断之前,要先对用到的IP进行初始化操作,这是任何设计的首要工作,在本章中调用了两个GPIO,因此首先对GPIO进行初始化,GPIO的初始化在第二章已经讲解过,这里需要注意的是本章的程序有两个GPIO,本章使用了两个实例结构来分别存放这两个GPIO的设置,如下图所示:

       之后再看到初始化GPIO程序段:

       可以看到,初始化之后,本章将LED_Gpio设置为了输出,这样就可以通过LED来指示中断的情况。接着看到main函数的下一句:

       这个函数就是本章程序的重中之重-中断初始化程序,其函数原型如下图所示:

        这个函数就是依据我们刚才得出的流程来编写,那么就按这些流程来分别介绍:

1、Intc初始化

       本章使用Init_Intr_System这个函数来实现Intc的初始化,这个函数的函数原型如下图所示:

        在官方提供的驱动历程当中,也可以看到Intc的初始化是用XIntc_Initialize这个函数来进行的,与之前接触过

的XILINX官方IP的初始化语句也类似,这个函数带了两个参数,一个实例结构,一个DeviceID,由此也可以看到从事XILINX FPGA设计是有共通点的。接着看第二个流程。

连接中断

2、在这个流程中,也对这个函数进行了重新封装。封装后的函数为GpioSetupIntrSystem,来看看其函数原型:

       实际上这个函数与第五个流程封装在了一起,因为这两个流程都涉及到了中断器件,先看中断连接函数XIntc_Connect,这个函数比较重要,我们认真分析一下这个函数,按F3定位这个函数的函数原型,如下所示:

        首先先看看函数头的英文释义的意思:“使中断源的Id与在识别中断时运行的关联处理程序之间建立连接。 该调用中提供的参数作为Callbackref用作处理程序调用时的参数。 在级联模式下,根据中断ID将处理程序连接到从属控制器处理程序表。”接下来看到带的参数的定义,第一个参数是Intc的实例,第二个是中断ID,数字越小,优先级越高,这个参数可以在xparameters.h中找到,在MicroBlaze中,其格式为XPAR_INTC_X_XXX_X_VEC_ID,比如本章的为XPAR_INTC_0_GPIO_0_VEC_ID,大家可以在xparameters.h中搜索关键字VEC_ID进行查找。第三个参数是该中断处理程序的回调函数,第四个参数是回调函数的参数。有了这些,我们再回头看看之前的程序。

       此处重点介绍第三个参数,回调函数的作用简单点的话来说,那就是产生中断后,系统该干嘛,做什么操作。此处括号内的xil_ExceptionHandler就是中断处理程序,GpioHandler就是与之关联的回调函数,它是一个确确实实的函数,我们来看看这个函数:

     这部分程序相对比较简单,这里设置了一个全局变量Intr_times,每次产生中断,它都进行加1操作,但限制其范围为0~3,然后让LED_Gpio每次产生中断都移位操作一次,最后清理中断。

     继续回到连接中断函数的分析当中,其第四个参数是作为回调函数的参数来使用的,通常用来,这个参数是中断器件的实例(本章就是),但也并非一定是,也可以是数字之类。这点大家可以灵活的去运行,对回调函数不是很清楚的需要适当的通过网络恶补一下。

     回到GpioSetupIntrSystem函数的分析当中,接下来的这两个函数的功能不做过多的介绍,其目的就是开启GPIO的中断,这部分按照官方历程来就好。

3、使能Intc

     使能Intc使用的是XIntc_Enable这个函数,为了方便下次调用,将其重新封装成了一个新的函数Intc_Enable,这里它的第二个参数跟的是要使能的中断号,该函数如下图所示:

4、开启Intc

      这部分程序是通过函数XIntc_Start这个函数来完成,此处它的第二个参数我们来看一下,在其原函数中有注释:

从上面的描述中,可以看到其第二个参数带了两种模式,XIN_SIMULATION_MODE是软件模拟中断,XIN_REAL_MODE是硬件产生实际的中断,这些都在上面的注释中能够找到,顺带提一遍,英文看不懂的,请把英文复制到谷歌翻译,学会合理的使用资源。

6、初始化中断异常处理程序

      这一部分的设计在所有的MicroBlaze的中断程序设计中都是一样的,开启INTC和器件的中断之后,就是做中断异常程序的初始化,而这初始化程序又是xilinx官方给我们提供了的,因此不需要过多的去纠结,只需要参照官方的设计即可。这一部分的代码如下图所示:

5.7本章小结

      本章主要为大家介绍了如何设计MicroBlaze的中断,通过本章,大家应该熟悉如何通过官方的历程来修改自己想要的设计功能。本章还介绍了中断设计的六个步骤,它们分别是:

   1、Intc初始化

   2、连接中断

   3、使能Intc

   4、开启Intc

   5、使能相应的中断

   6、初始化中断异常处理程序


路过

雷人

握手

鲜花

鸡蛋

最新评论

本文作者
2019-11-6 17:07
  • 1
    粉丝
  • 6088
    阅读
  • 0
    回复

关注uisrc网络

扫描关注,了解最新资讯

电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼
热门评论
排行榜