AXI GPIO的使用

1 AXI GPIO

  • MIO和EMIO 是直接挂在PS上的GPIO,而AXI_GPIO相当于 GPIO 的 IP 核,该IP核通过AXI总线与PS互联实现了GPIO。 在PS端通过对该IP核的控制寄存器进行读写,即可控制GPIO端口的状态。
  • AXI GPIO 可以使用两个通道,分别是 GPIO 和 GPIO2。当PS的GPIO端口不够用时,我们可以用这种方法把GPIO挂接在AXI总线上与PS交互,大大拓展了PS可用的GPIO数量。
    在这里插入图片描述

1.1 PL逻辑部分设计

  • 我们用一个开发板上的按钮控制4个LED灯的亮暗情况,搭建好的系统如下所示:
    在这里插入图片描述
  • 当有IP核挂接在PS的AXI总线上时,会自动地为我们分配好地址以及可寻址的范围。在PS中我们就是对这一范围内的控制寄存器进行操作的。 最好不要自己分配,因为可能会与一些外设的控制寄存器地址冲突!!
    在这里插入图片描述
  • 注意引出的三态引脚在Creat HDL Wrapper时会自动加上IOBUF
    在这里插入图片描述
  • 然后对FPGA引脚根据开发板文档进行xdc约束。
set_property PACKAGE_PIN H11 [get_ports {AXI_GPIO_BTN_tri_io[0]}]
set_property IOSTANDARD LVCMOS15 [get_ports {AXI_GPIO_BTN_tri_io[0]}]

set_property PACKAGE_PIN E13 [get_ports {AXI_GPIO_LED_tri_io[0]}]
set_property IOSTANDARD LVCMOS15 [get_ports {AXI_GPIO_LED_tri_io[0]}]
set_property PACKAGE_PIN E12 [get_ports {AXI_GPIO_LED_tri_io[1]}]
set_property IOSTANDARD LVCMOS15 [get_ports {AXI_GPIO_LED_tri_io[1]}]
set_property PACKAGE_PIN F13 [get_ports {AXI_GPIO_LED_tri_io[2]}]
set_property IOSTANDARD LVCMOS15 [get_ports {AXI_GPIO_LED_tri_io[2]}]
set_property PACKAGE_PIN H13 [get_ports {AXI_GPIO_LED_tri_io[3]}]
set_property IOSTANDARD LVCMOS15 [get_ports {AXI_GPIO_LED_tri_io[3]}]
  • 然后生成bitstream,导出到SDK进行裸机程序开发。

1.2 PS程序部分设计

#include "xparameters.h"
#include "xgpio.h"
#include "xil_printf.h"
#include "sleep.h"

//axi_gpio ID
#define AXI_GPIO_DEV_ID	        XPAR_AXI_GPIO_0_DEVICE_ID
//channel1
#define BTN_CHANNEL    1
//channel2
#define LED_CHANNEL    2

XGpio Gpio;

int main(void)
{

	int Status;
	u32 Btn_val;

		/* Initialize the GPIO driver */
		Status = XGpio_Initialize(&Gpio, XPAR_AXI_GPIO_0_DEVICE_ID);
		if (Status != XST_SUCCESS)
		{
			xil_printf("Gpio Initialization Failed\r\n");
			return XST_FAILURE;
		}
		
		/* Set the direction for all signals as inputs or output ,Bits set to 0 are output and bits set to 1 are input.*/

		XGpio_SetDataDirection(&Gpio, BTN_CHANNEL, 1);
		XGpio_SetDataDirection(&Gpio, LED_CHANNEL, 0);

		 /* Write to discretes register for the specified GPIO channel */
		while(1)
		{
			/*Read state of discretes for the specified GPIO channnel.*/
			Btn_val = XGpio_DiscreteRead(&Gpio, BTN_CHANNEL);
  
			if(Btn_val)
			{
				XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, 0x0);
		    }
			else
			{
		    	XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, 0xf);
		    }
		}
}
  • 这里要注意,使用GPIO时要包含的头文件为xgpiops.h,而使用AXI GPIO时要包含xgpio.h
XGpio_Initialize
  • 在根据hw_platform导出的bsp中查找,获取AXI GPIO相关信息,并将其赋给用户定义的XGpio结构体。用户每操作一个AXI GPIO的IP核,都要定义一个这样的结构体。
    在这里插入图片描述
XGpio_SetDataDirection
  • 配置GPIO为输入或输出,0 为输出,1 为输入。Channel指示配置哪一个的通道,为 1 或 2。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 控制寄存器详细信息可见pg144
    在这里插入图片描述
XGpio_DiscreteRead
  • 读取指定Channel的端口数据,注意虽然返回的是u32,但是我们要根据GPIO端口配置的位数来合理使用这一返回值。
    在这里插入图片描述
    在这里插入图片描述
XGpio_DiscreteWrite
  • 向指定Channel写数据,注意写入的参数类型为u32,注意实际写入的是低位。
    在这里插入图片描述