区分ZYNQ PS端MIO中断和AXI_GPIO中断

keke‘

想随手记录下在学习PS部分中断的过程,记录可以帮助我发现一些细节上面的问题,或许也会帮到你们。

在使用XIlinx开发软件SDK过程中,我参考了system.mss文件中的xgpiops_intr_example示例,通过调用相关函数,建立中断系统和中断服务函数。

在开发过程中,因为我是用的是zynq开发板,所以要常常翻阅UG585赛灵思官方提供的数据手册,手册中介绍了机制和原理,适合用到的时候去参考。

MIO 配置中断

首先打开xgpiops_intr_example示例,我们可以看到一下函数:

int GpioIntrExample(XScuGic *Intc, XGpioPs *Gpio, u16 DeviceId, u16 GpioIntrId)

这个函数当中首先执行了对GPIO器件 ID 查找配置信息,然后初始化 Gpio driver,定义GPIO输入输出方向,使能要输出引脚,最后重点才是建立中断系统:

SetupInterruptSystem(Intc, Gpio, GPIO_INTERRUPT_ID);

转到该函数的定义,可以看到它和GPIO的初始化比较类似,也是先找到配置信息,初始化一些引脚,我们可以重点参考下面的代码来帮助我们移植。

	/*
	 * Connect the interrupt controller interrupt handler to the hardware
	 * interrupt handling logic in the processor.
	 */
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
				(Xil_ExceptionHandler)XScuGic_InterruptHandler,
				GicInstancePtr);

	/*
	 * Connect the device driver handler that will be called when an
	 * interrupt for the device occurs, the handler defined above performs
	 * the specific interrupt processing for the device.
	 */
	Status = XScuGic_Connect(GicInstancePtr, GpioIntrId,
				(Xil_ExceptionHandler)XGpioPs_IntrHandler,
				(void *)Gpio);
	if (Status != XST_SUCCESS) {
		return Status;
	}
	/* Enable falling edge interrupts for all the pins in bank 0. */
	XGpioPs_SetIntrType(Gpio, GPIO_BANK, 0x00, 0xFFFFFFFF, 0x00);

	/* Set the handler for gpio interrupts. */
	XGpioPs_SetCallbackHandler(Gpio, (void *)Gpio, IntrHandler);


	/* Enable the GPIO interrupts of Bank 0. */
	XGpioPs_IntrEnable(Gpio, GPIO_BANK, (1 << Input_Pin));


	/* Enable the interrupt for the GPIO device. */
	XScuGic_Enable(GicInstancePtr, GpioIntrId);


	/* Enable interrupts in the Processor. */
	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);

上面这些代码的主要作用是设置并使能中断异常与中断处理函数,在移植代码的过程中,我们要重点关系参数的传递与相关具体函数的调用。

需要先明白,实例好以后是具有动态空间的。

整个函数的需要传入的第一个参数是一个实例化好的中断控制器,以指针形式传入,正如GPIO实例,我们要在主函数前先声明,记得包含xscugic.h的头文。第二个参数是实例化的GPIO,第三个参数是使能GPIO中断号,通过查阅手册我们知道GPIO中断号是52,找到GPIO_INTERRUPT_ID的定义,添加宏定义        #define GPIO_INTERRUPT_ID    XPAR_XGPIOPS_0_INTR

接下来我们要做的事情,就是修改这些函数内部的参数。

    int setup_interrupt_system(XScuGic *gic_ins_ptr, XGpioPs *gpio, u16 GpioIntrId)
    {
            int status;
        XScuGic_Config *IntcConfig; //中断控制器配置信息

        //查找中断控制器配置信息并初始化中断控制器驱动
        IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
        if (NULL == IntcConfig) {
        return XST_FAILURE;
        }

        status = XScuGic_CfgInitialize(gic_ins_ptr, IntcConfig,
        IntcConfig->CpuBaseAddress);
        if (status != XST_SUCCESS) {
        return XST_FAILURE;
        }

        //设置并使能中断异常
        Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
        (Xil_ExceptionHandler) XScuGic_InterruptHandler, gic_ins_ptr);
        Xil_ExceptionEnable();

        //为中断设置中断处理函数
        status = XScuGic_Connect(gic_ins_ptr, GpioIntrId,
        (Xil_ExceptionHandler) intr_handler, (void *) gpio);
        if (status != XST_SUCCESS) {
        return status;
        }

        //使能来自于 Gpio 器件的中断
        XScuGic_Enable(gic_ins_ptr, GpioIntrId);

        //设置 KEY 按键的中断类型为下降沿中断
        XGpioPs_SetIntrTypePin(gpio, KEY, XGPIOPS_IRQ_TYPE_EDGE_FALLING);

        //使能按键 KEY 中断
        XGpioPs_IntrEnablePin(gpio, KEY);

        return XST_SUCCESS;
    }

写中断函数:

使用前先调用函数SetupInterruptSystem(Intc, Gpio, GPIO_INTERRUPT_ID)即可。

    static void intr_handler(void *callback_ref)
    {
        /**/

    }


使用AXI接口产生IRQ到GIC

IRQ是中断请求,GIC用于管理PL和PS的中断,把中断发送到CPU进行处理。

AXI接口可以调用AXI GPIO的IP核实现PL与PS数据快速交互,这里是从PL到PS。

创建AXI GPIO  IP核(互联作用),我们可以打开AMD—— AXI GPIO  IP IP Product Guide

GPIOx_TRI register 使用三态缓冲区用于配置GPIO某一个引脚输入或是输出。

输出写0,输入写1。GPIO宽度可被配为1 - 32,其余较为常见,不做过多叙述。

PL端需要调用该IP核,与ZYNQ完成连接,做好管脚约束,(bit)直接导出HDL文件到SDK或Vitis即可。

与PS端GPIO相同,我们也需要配置器件ID初始化AXI GPIO驱动,可通过调用以下函数直接完成。

XGpio_Initialize(&AXI_Gpio, AXI_GPIO_DEVICE_ID);

可以在示例中找到AXI_GPIO的实例化函数和AXIGPIO的器件ID。

XGpio AXI_Gpio;  //实例化AXI
#define AXI_GPIO_DEVICE_ID		XPAR_GPIO_0_DEVICE_ID			//PL端 AXI GPIO器件ID
#define AXI_INTC_GPIO_INTERRUPT_ID	XPAR_INTC_0_GPIO_0_VEC_ID   //PL端 AXI GPIO中断ID

初始化好以后,我们可以查看pg144手册

首先设置AXIGPIO的方向,在xgpio.h文件中找到 :

void XGpio_SetDataDirection(XGpio *InstancePtr, unsigned Channel,
			    u32 DirectionMask);

第一个参数是实例化的AXIGPIO,传入其地址即;通道这里我们只用到一个通道,写1即可;最后一个输出方向,1为输出,0为输入。

其次打开全局中断和使能通道中断,为方便此步骤放在设置中断系统中。

查看示例,进行一步步移植:

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;
}

可以看到示例函数中首先进行了条件编译,预处理指令,我们确定了选型,可以删除,接下来设置优先级:

void XScuGic_SetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id,
					u8 Priority, u8 Trigger)

* @param    InstancePtr is a pointer to the instance to be worked on.
* @param    Int_Id is the IRQ source number to modify
* @param    Priority is the new priority for the IRQ source. 0 is highest
*           priority, 0xF8(248) is lowest. There are 32 priority levels
*           supported with a step of 8. Hence the supported priorities are
*           0, 8, 16, 32, 40 ..., 248.
* @param    Trigger is the new trigger type for the IRQ source.

对于最后一个参数:

* Each bit pair describes the configuration for an INT_ID.
* SFI    Read Only    b10 always
* PPI    Read Only    depending on how the PPIs are configured.
*                    b01    Active HIGH level sensitive
*                    b11 Rising edge sensitive
* SPI                LSB is read only.
*                    b01    Active HIGH level sensitive
*                    b11 Rising edge sensitive/

我们只要重点关注中断源和想要触发的具体类型即可。

这里我们将其配置为上升沿触发:

XScuGic_SetPriorityTriggerType(&scugic_inst, GPIO_INT_ID, 0xA0, 0x3);

接下来关联中断处理函数和其对应ID号,使能中断,注册中断异常函数即可:

    //关联中断 ID 和中断处理函数
    XScuGic_Connect(&scugic_inst, GPIO_INT_ID, axi_gpio_handler, &axi_gpio_inst);
    //使能 AXI GPIO 中断
    XScuGic_Enable(&scugic_inst, GPIO_INT_ID);

    //设置并打开中断异常处理功能
    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler, &scugic_inst);
    Xil_ExceptionEnable();

最后只要写好我们自己的中断服务函数就完成了配置,我们使用AXI接口的方式完成PL和PS的交互,在速率上要比EMIO更快速。

  • 26
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Zynq芯片中,GPIO引脚的中断是通过AXI_GPIO模块和PS相连的中断信号线的电平变换引发的。可以通过配置中断触发方式来设置GPIO引脚的中断。具体来说,可以使用XScuGic_SetPriorityTriggerType函数来设置中断触发优先级和触发类型。例如,可以通过设置中断触发类型为上升沿触发来使得当GPIO引脚的电平变为上升沿时触发中断。 需要注意的是,GPIO引脚的中断方式已经由硬件决定好了,无法在此处进行配置。参考函数的注释中提到,只有两种方式可以设置中断,即高电平和上升沿,这里的高电平和上升沿指的是AXI_GPIO模块和PS相连的中断信号线的电平变换引发PS中断,而不是GPIO引脚的中断方式。 因此,在配置中断触发方式时,需要确定好AXI_GPIO模块和PS相连的中断信号线的电平变换方式并设置相应的中断触发类型。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [zynq-7000.rar_linux 中断 zynq_zynq DMA_zynq DMA Linux_zynq gpio_i2](https://download.csdn.net/download/weixin_42651887/86201535)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [ZYNQ_GPIO_中断](https://blog.csdn.net/Master_0_/article/details/125125000)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值