Xilinx ZYNQ 7000 AXI GPIO 读写/中断

打开SDK 后,创建官方例程
在这里插入图片描述

在这里插入图片描述
打开官方例程后,会发现这个AXI GPIO设置和 PS MIO/EMIO一模一样

int main(void)
{
	int Status;
	volatile int Delay;

	/* Initialize the GPIO driver */
	Status = XGpio_Initialize(&Gpio, GPIO_EXAMPLE_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		xil_printf("Gpio Initialization Failed\r\n");
		return XST_FAILURE;
	}

	/* Set the direction for all signals as inputs except the LED output */
	XGpio_SetDataDirection(&Gpio, LED_CHANNEL, ~LED);

	/* Loop forever blinking the LED */

	while (1) {
		/* Set the LED to High */
		XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, LED);

		/* Wait a small amount of time so the LED is visible */
		for (Delay = 0; Delay < LED_DELAY; Delay++);

		/* Clear the LED bit */
		XGpio_DiscreteClear(&Gpio, LED_CHANNEL, LED);

		/* Wait a small amount of time so the LED is visible */
		for (Delay = 0; Delay < LED_DELAY; Delay++);
	}

	xil_printf("Successfully ran Gpio Example\r\n");
	return XST_SUCCESS;
}

这是什么情况,那怎么区分AXI GPIO和PS MIO EMIO呢
在这里插入图片描述
在BSP中有gpio和gpiops两个文件夹,分别使用两套函数。
在这里插入图片描述
请仔细看下面两个获取gpio实体的函数

XGpioPs_Config *XGpioPs_LookupConfig(u16 DeviceId)
{
	XGpioPs_Config *CfgPtr = NULL;
	u32 Index;

	for (Index = 0U; Index < (u32)XPAR_XGPIOPS_NUM_INSTANCES; Index++) {
		if (XGpioPs_ConfigTable[Index].DeviceId == DeviceId) {
			CfgPtr = &XGpioPs_ConfigTable[Index];
			break;
		}
	}

	return (XGpioPs_Config *)CfgPtr;
}
XGpio_Config *XGpio_LookupConfig(u16 DeviceId)
{
	XGpio_Config *CfgPtr = NULL;

	int Index;

	for (Index = 0; Index < XPAR_XGPIO_NUM_INSTANCES; Index++) {
		if (XGpio_ConfigTable[Index].DeviceId == DeviceId) {
			CfgPtr = &XGpio_ConfigTable[Index];
			break;
		}
	}

	return CfgPtr;
}

没错,AXI GPIO和PS GPIO使用了两套ConfigTable。
两套table 分别定义了不同的实体位置
在这里插入图片描述
也就是说AXI GPIO和PS GPIO使用了两套地址,分别指向了不同的地址。
对于APU来说一切都是地址。

需要注意的是Channel 是AXI GPIO的Channel,在IP生成的时候可以选择 2个通道。
data写入的数据是整个AXI GPIO的位宽。

/****************************************************************************/
/**
* Write to discretes register for the specified GPIO channel.
*
* @param	InstancePtr is a pointer to an XGpio instance to be worked on.
* @param	Channel contains the channel of the GPIO (1 or 2) to operate on.
* @param	Data is the value to be written to the discretes register.
*
* @return	None.
*
* @note		The hardware must be built for dual channels if this function
*		is  used with any channel other than 1.  If it is not, this
*		function will assert. See also XGpio_DiscreteSet() and
*		XGpio_DiscreteClear().
*
*****************************************************************************/
void XGpio_DiscreteWrite(XGpio * InstancePtr, unsigned Channel, u32 Data)
{
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
	Xil_AssertVoid((Channel == 1) ||
		     ((Channel == 2) && (InstancePtr->IsDual == TRUE)));

	XGpio_WriteReg(InstancePtr->BaseAddress,
			((Channel - 1) * XGPIO_CHAN_OFFSET) + XGPIO_DATA_OFFSET,
			Data);
}

AXI GPIO中断之前先来看一下AXI GPIO Read
以ZC702官方开发板为例
在这里插入图片描述
配置AXI GPIO 1,2位按键输入
AXI GPIO 3 位LED输出

#define LED 0x04   /* Assumes bit 0 of GPIO is connected to an LED  */
int main(void)
{
	int Status;
	u32 SwState;
	volatile int Delay;

	/* Initialize the GPIO driver */
	Status = XGpio_Initialize(&Gpio, GPIO_EXAMPLE_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		xil_printf("Gpio Initialization Failed\r\n");
		return XST_FAILURE;
	}

	/* Set the direction for all signals as inputs except the LED output */
	XGpio_SetDataDirection(&Gpio, LED_CHANNEL, ~LED);

	/* Loop forever blinking the LED */

	while (1) {
		/* Set the LED to High */
		XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, LED);

		/* Wait a small amount of time so the LED is visible */
		for (Delay = 0; Delay < LED_DELAY; Delay++);

		/* Clear the LED bit */
		XGpio_DiscreteClear(&Gpio, LED_CHANNEL, LED);

		/* Wait a small amount of time so the LED is visible */
		for (Delay = 0; Delay < LED_DELAY; Delay++);
		SwState = XGpio_DiscreteRead(&Gpio, LED_CHANNEL);
		xil_printf("AXI GPIO Read:%x \r\n",SwState);
	}

	xil_printf("Successfully ran Gpio Example\r\n");
	return XST_SUCCESS;
}

按下按键查看,输出值得变化

AXI GPIO Read:0
AXI GPIO Read:1
AXI GPIO Read:1
AXI GPIO Read:0
AXI GPIO Read:0
AXI GPIO Read:2
AXI GPIO Read:2
AXI GPIO Read:1
AXI GPIO Read:2

读取数据的API也是采用MASK的方式。

那么中断,本质上来说和GPIO中断的方式大致相同,区别在于有一条专门的中断信号线连接到GIC全局中断控制器上。

第二部分

回到中断的例程中

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

GIC初始化的套路。

设置中断优先级

XScuGic_SetPriorityTriggerType(IntcInstancePtr, IntrId,
					0xA0, 0x3);

这部分和GPIO中断是一样把,中断服务函数GpioHandler,装填到GIC的中断向量表中,注意这里不是CPU中断向量。

/*
	 * 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);


	/*
	 * 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();

这里是指定CPU Vector Table IRQ项的跳转函数。

Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			 (Xil_ExceptionHandler)INTC_HANDLER, IntcInstancePtr);

最后使能中断

/* Enable non-critical exceptions */
	Xil_ExceptionEnable();

以上过程并没有什么特别注意的地方,几乎和MIO,EMIO一致。

所以处理PL的中断在ARM端几乎和处理PS端中断一致。主要还是GIC依照中断号进行IRQ向量表装填。
CPU收到GIC发来的中断后硬件跳转到Vector Table执行IRQ函数,用来判断中断号调用GIC中断表。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
xilinx zynq7000参考手册是一本提供给用户的完整指南,涵盖了xilinx zynq7000系列器件的所有重要特性和功能。该手册的目的是帮助用户了解和使用zynq7000系列器件,以便能够根据特定的设计需求正确配置和编程。 参考手册首先介绍了zynq7000系列器件的总体架构,包括处理系统(PS)和可编程逻辑(PL)部分的功能和组件。这些组件包括处理器核心、存储器、外设接口和相互连接的总线系统。用户可以通过阅读手册了解这些组件的工作原理和互连方式,并理解它们如何协同工作以实现高性能的系统设计。 手册还详细描述了zynq7000系列器件的特定功能和特性,如时钟和重置控制、外设接口协议、中断和异常处理、低功耗设计等。这些内容可以帮助用户深入了解zynq7000系列器件的功能和性能限制,在设计过程中避免常见的错误和问题。 此外,手册还提供了丰富的编程和配置指南,包括使用软件开发工具(SDK)进行C/C++编程、使用硬件描述语言(HDL)进行可编程逻辑设计、使用Vivado开发环境进行系统集成等等。使用这些指南,用户可以了解如何使用各种工具和技术来开发和调试zynq7000系列器件的应用程序和系统设计。 总之,xilinx zynq7000参考手册是一本非常重要的资源,为用户提供了详尽全面的信息和指导,帮助他们成功设计和开发基于zynq7000系列器件的应用和系统。无论是初学者还是有经验的设计师,都可以从这本手册中获益并加深对zynq7000系列器件的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值