ZYNQ笔记(五):AXI GPIO 中断

 版本:Vivado2020.2(Vitis)

任务:使用 AXI GPIO IP 核以中断方式实现按键 KEY 控制 LED 亮灭翻转(两个都在PL端)

目录

一、介绍

二、硬件设计

三、软件设计

四、效果


一、介绍       

        AXI GPIO 中断通常基于以下机制:当 AXI GPIO 输入引脚满足触发条件时,AXI GPIO 会通过 IRQ(Interrupt Request) 信号向 PS端 处理器发送中断请求。

  • 中断触发条件

    • 边沿触发:上升沿、下降沿、双边沿。

      扫描二维码关注公众号,回复: 17617679 查看本文章
    • 电平触发;高电平、低电平。

  • 中断处理流程

    1. 检测到 GPIO 信号变化(如按键按下)。

    2. AXI GPIO IP 核触发中断(IRQ 信号拉高)。

    3. CPU 响应中断,执行中断服务程序。

    4. 清除中断标志(防止重复触发)。

二、硬件设计

        (1)直接沿用上一次 AXI GPIO 例程的硬件设计(ZYNQ笔记(四):AXI GPIO),然后稍作修改即可。

        (2)按键 KEY 用到了 AXI GPIO 中断,双击IP进行配置:

1.通过软件设置io的输入输出方向(不勾选 All In/Outputs)

2.各只用了1个引脚,故设置1通道(不勾选 Enable Dual Channel)、位宽1位(GPIO Width )

3.使能中断(勾选 Enable Interruput)

        (3)双击 ZYNQ 修改配置,配置由PL向PS端的中断。IRQ_F2P指的是FPGA向PS端发送的中断请求,16位对应16个中断号(中断ID),ZYNQ将PL到PS的16个中断ID分成了两组,第一组ID为61到68,第二组ID为84到91。

        (4)回到bd设计可以看到多出了两个端口,一个AXI GPIO的中断端口、一个ZYNQ的中断请求端口。将两个端口连接。

        (5)最后整体 bd 设计部分如图所示:设计检查、Generate Output Products、 Create HDL Wrapper、管脚约束、Gnerate Bitstream、Export Hardware(包含比特流文件)、启动Vitis

三、软件设计

        关于中断ID,由 PL 产生的共享外设中断(SPI)共 16 个,中断 ID 分别为 61 到 68, 84 到 91。具体可以在参数头文件 xparameter.h 里查看(也可以通过官方例程跳转查看),可以看到AXI GPIO 按键的中断ID的确是61。

#include "stdio.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xgpio.h"
#include "xscugic.h"
#include "sleep.h"

//===========================自定义宏===========================//

#define GPIO_DEVICE_ID  	XPAR_XGPIOPS_0_DEVICE_ID          //宏定义器件ID
#define INTC_DEVICE_ID		XPAR_SCUGIC_SINGLE_DEVICE_ID	  //宏定义中断控制器(GIC)ID
#define AXI_GPIO_INTR_ID	XPAR_FABRIC_KEY_IP2INTC_IRPT_INTR //宏定义GPIO中断号(每个器件都有中断号,可跳转参数头文件查询)

#define KEY_AXI_GPIO_ID  	XPAR_GPIO_0_DEVICE_ID	//宏定义KEY AXI GPIO 器件ID
#define KEY_CHANNEL  		1						//宏定义KEY所在的axi gpio通道
#define KEY_MASK   			0x00000001   		    //宏定义KEY所在通道掩码(这里表示启用第0位)

#define LED_AXI_GPIO_ID  	XPAR_GPIO_1_DEVICE_ID   //宏定义LED AXI GPIO 器件ID
#define LED_CHANNEL  		1						//宏定义LED所在的axi gpio通道
#define LED_MASK            0x00000001   			//宏定义LED所在通道掩码(这里表示启用第0位)

//===========================实例化===========================//

XGpio LED_AXI_GPIO;				//定义LED AXI GPIO驱动实例
XGpio KEY_AXI_GPIO;				//定义KEY AXI GPIO驱动实例
XScuGic Intc;					//中断控制器驱动实例

//===========================函数变量声明===========================//

static void IntrHandler();  		//中断处理函数
static void AXI_GPIO_Init();		//AXI GPIO 初始化
static void Set_Intr_Sys(XScuGic *GicInstancePtr, XGpio *AxiGpio, u16 AxiGpioIntrID); //建立中断系统

static u32 key_value;

//===========================主函数===========================//
int main()
{
	xil_printf("AXI GPIO Interrupt Test \r\n");

	AXI_GPIO_Init();
	Set_Intr_Sys(&Intc, &KEY_AXI_GPIO ,AXI_GPIO_INTR_ID);

	while(1)
	return 0;
}

//===========================中断处理函数===========================//
void IntrHandler()
{
	//屏蔽按键中断(对应位需为1)
	XGpio_InterruptDisable(&KEY_AXI_GPIO, KEY_MASK);
	//按键消抖延时20ns(不消抖会反复中断)
	usleep(20000);
	//延时后键值高电平说明有效(按下为1)
	if( (XGpio_DiscreteRead(&KEY_AXI_GPIO, KEY_CHANNEL) & KEY_MASK) == 1 ) //函数是读整个通道,与上掩码只取对应位
	{
		//debug打印字符串
		xil_printf("Interrupt detected! \n\r");
		//翻转数据并写入LED
		key_value = ~key_value;
		XGpio_DiscreteWrite(&LED_AXI_GPIO, LED_CHANNEL, key_value);
	}
	//清除按键中断状态(对应位需为1)(不清除会一直触发中断,导致死循环)
	XGpio_InterruptClear(&KEY_AXI_GPIO, KEY_MASK);
	//重新使能按键中断(对应位需为1)
	XGpio_InterruptEnable(&KEY_AXI_GPIO, KEY_MASK);
}

//===========================AXI GPIO 初始化===========================//
void AXI_GPIO_Init()
{
	//初始化器件驱动
	XGpio_Initialize(&LED_AXI_GPIO, LED_AXI_GPIO_ID);
	XGpio_Initialize(&KEY_AXI_GPIO, KEY_AXI_GPIO_ID);
	//GPIO方向设置(不同于GPIO (E)MIO , AXI GPIO是 0输出/1输入)
	XGpio_SetDataDirection(&KEY_AXI_GPIO, KEY_CHANNEL, KEY_MASK);
	XGpio_SetDataDirection(&LED_AXI_GPIO, LED_CHANNEL, ~LED_MASK);
}

//===========================建立中断系统===========================//
/* 建立中断系统,使能KEY按键的上升沿产生中断
 * @param GicInstancePtr 是一个指向 XScuGic 驱动实例的指针
 * @param AxiGpio 是一个指向连接到中断的 AXI GPIO 驱动实例的指针
 * @param AxiGpioIntrID 是 AXI GPIO中断控制器ID
 */
void Set_Intr_Sys(XScuGic *GicInstancePtr, XGpio *AxiGpio, u16 AxiGpioIntrID)
{
    //定义中断控制器配置信息(指针类型)
	XScuGic_Config * IntcConfig;
	//根据中断控制器ID,查找GIC配置信息(Generic Interrupt Controller(通用)中断控制器)
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	//初始化中断控制器驱动
	XScuGic_CfgInitialize(GicInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);
    //设置并打开中断异常处理功能
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			(Xil_ExceptionHandler)XScuGic_InterruptHandler,
			GicInstancePtr);
	Xil_ExceptionEnable();
	//为GPIO中断设置中断处理函数(IntrHandler为自己编写的中断函数)
	XScuGic_Connect(GicInstancePtr, AxiGpioIntrID,
				(Xil_ExceptionHandler)IntrHandler, (void *) AxiGpio);
	//使能来自于 AXI GPIO 器件的中断
	XScuGic_Enable(GicInstancePtr, AxiGpioIntrID);
	//设置中断优先级、触发类型(优先级从最高0开始步长8最大为248,0xA0=160优先级中等;触发类型:上升沿)
	XScuGic_SetPriorityTriggerType(GicInstancePtr, AxiGpioIntrID, 0xA0 , 0x3);
	//使能 AXI GPIO 全局中断
	XGpio_InterruptGlobalEnable(&KEY_AXI_GPIO);
	//使能中断(对应位为1使能)
	XGpio_InterruptEnable(&KEY_AXI_GPIO, KEY_MASK);
}

四、效果

        上板后串口打印“AXI GPIO Interrupt” debug信息,之后每按下一次按键LED翻转一次,同时串口打印中断debug信息。

猜你喜欢

转载自blog.csdn.net/2303_76814451/article/details/147146434
今日推荐