ZYNQ-AXIO_GPIO多位宽示例代码

正在跟着原子哥的教程学VITIS,学到AXI_GPIO部分尝试把位宽从1位拓展到3位,但是看了手册半天不知道咋设置,网上也找不到相关教程。现在摸索了一个上午总算知道该咋改了。

1.首先VIVADO部分修改AXI_GPIO这个IP核,选择位宽为3位

2.其余设置参照正点原子VITIS手册。配置完IP核后打开RTL_ANALYSIS配置引脚

3.然后generate output products,wrapper,bit-stream,export output;在vitis中要update hardware specification

4.修改main.c代码如下



 #include "xparameters.h"
 #include "xgpiops.h"
 #include "xgpio.h"
 #include "xscugic.h"
 #include "xil_exception.h"
 #include "xplatform_info.h"
 #include <xil_printf.h>
 #include "sleep.h"
 #include "stdio.h"
 /************************** Constant Definitions *****************************/

 //以下常量映射到xparameters.h文件
 #define GPIOPS_DEVICE_ID    XPAR_XGPIOPS_0_DEVICE_ID     	//PS端GPIO器件ID
 #define AXI_GPIO_DEVICE_ID  XPAR_AXI_GPIO_0_DEVICE_ID    	//PL端AXI GPIO器件ID
 #define SCUGIC_ID           XPAR_SCUGIC_SINGLE_DEVICE_ID 	//通用中断控制器ID
 #define AXI_GPIO_INT_ID     XPAR_FABRIC_GPIO_0_VEC_ID    	//PL端AXI GPIO中断ID

 #define MIO_LED0       0                                  	//LED 连接到 MIO0
 #define MIO_LED1      13                                  	//LED 连接到 MIO13
 #define KEY_CHANNEL1  1                                  	//PL 按键使用 AXI GPIO 通道 1
 #define KEY_CH1_MASK  0X1                  				//通道 1的中断位定义
 #define AXI_GPIO_ALL_MASK 0x07								//AXIOGPIO总位宽,我设置的是3位,因此这里设置为0x07=0000_0111
 /************************** Function Prototypes ******************************/
 void instance_init();
 int setup_interrupt_system(XScuGic *gic_inst_ptr, XGpio *axi_gpio_inst_ptr,
     u16 AXI_GpioIntrId);
 static void intr_handler(void *callback_ref);

 /**************************Global Variable Definitions ***********************/
 XGpioPs gpiops_inst;        //PS端GPIO驱动实例
 XGpio   axi_gpio_inst;      //PL端AXI GPIO驱动实例
 XScuGic scugic_inst;        //通用中断控制器驱动实例
 int led0_value=0;            //ps端LED0的显示状态
 int led1_value=0;            //ps端LED1的显示状态

 /************************** Function Definitions *****************************/

 int main(void)
 {
     int status;

     //初始化各器件驱动
     instance_init();

     xil_printf("AXI_Gpio interrupt test \r\n");

     //设置LED所连接的MIO引脚的方向为输出并使能输出
     XGpioPs_SetDirectionPin(&gpiops_inst, MIO_LED0, 1);
     XGpioPs_SetOutputEnablePin(&gpiops_inst, MIO_LED0, 1);
     XGpioPs_WritePin(&gpiops_inst, MIO_LED0, led0_value);

     XGpioPs_SetDirectionPin(&gpiops_inst, MIO_LED1, 1);
     XGpioPs_SetOutputEnablePin(&gpiops_inst, MIO_LED1, 1);
     XGpioPs_WritePin(&gpiops_inst, MIO_LED1, led1_value);
     //建立中断,出现错误则打印信息并退出
     status = setup_interrupt_system(&scugic_inst, &axi_gpio_inst, AXI_GPIO_INT_ID);
     if (status != XST_SUCCESS) {
         xil_printf("Setup interrupt system failed\r\n");
         return XST_FAILURE;
     }

     return XST_SUCCESS;
 }

 //初始化各器件驱动
 void instance_init()
 {
     XScuGic_Config *scugic_cfg_ptr;
     XGpioPs_Config *gpiops_cfg_ptr;

     //初始化中断控制器驱动
 	 scugic_cfg_ptr = XScuGic_LookupConfig(SCUGIC_ID);
     XScuGic_CfgInitialize(&scugic_inst, scugic_cfg_ptr, scugic_cfg_ptr->CpuBaseAddress);

     //初始化PS端  GPIO驱动
     gpiops_cfg_ptr = XGpioPs_LookupConfig(GPIOPS_DEVICE_ID );
     XGpioPs_CfgInitialize(&gpiops_inst, gpiops_cfg_ptr, gpiops_cfg_ptr->BaseAddr);

     //初始化PL端  AXI GPIO驱动
     XGpio_Initialize(&axi_gpio_inst, AXI_GPIO_DEVICE_ID);//该函数内部已经调用XGpioPs_LookupConfig,因此无需另外调
 }

 //建立中断系统,使能KEY按键的下降沿中断
 //  @param   GicInstancePtr是一个指向XScuGic驱动实例的指针
 //  @param   gpio是一个指向连接到中断的GPIO组件实例的指针
 //  @param   GpioIntrId是Gpio中断ID
 //  @return  如果成功返回XST_SUCCESS, 否则返回XST_FAILURE
 int setup_interrupt_system(XScuGic *gic_inst_ptr, XGpio *axi_gpio_inst_ptr, u16 AXI_GpioIntrId)
 {
	 //*****************************************************************************//
	 //这三个函数是固定的,缺一不可。
     //设置并使能中断异常
     Xil_ExceptionInit();
     Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
    		 (Xil_ExceptionHandler) XScuGic_InterruptHandler, gic_inst_ptr);
     Xil_ExceptionEnable();
     //*****************************************************************************//
     //设置中断源的优先级和触发类型(高电平触发)
     XScuGic_SetPriorityTriggerType(gic_inst_ptr, AXI_GpioIntrId, 0xA0, 0x01);
     /*优先级:0(最高), 8, 16, 32, 40 ..., 248(最低)
      * ip2intc_irpt信号为高电平敏感信号,因此触发类型选择0x01(电平敏感)
      */
     //为中断设置中断处理函数
     XScuGic_Connect(gic_inst_ptr, AXI_GpioIntrId,
             (Xil_ExceptionHandler) intr_handler, (void *) axi_gpio_inst_ptr);

     //使能来自于axi_Gpio器件的中断
     XScuGic_Enable(gic_inst_ptr, AXI_GpioIntrId);

     //配置PL端 AXI GPIO
	 //设置 AXI GPIO 通道 1方向为输入
     XGpio_SetDataDirection(axi_gpio_inst_ptr, KEY_CHANNEL1, AXI_GPIO_ALL_MASK);
     XGpio_InterruptEnable(axi_gpio_inst_ptr, AXI_GPIO_ALL_MASK);  //使能中断
     XGpio_InterruptGlobalEnable(axi_gpio_inst_ptr);          //使能axi gpio全局中断

     return XST_SUCCESS;
 }

 //中断处理函数
 //  @param   CallBackRef是指向上层回调引用的指针
 static void intr_handler(void *callback_ref)
 {
     XGpio *axi_gpio_inst_ptr = (XGpio *)callback_ref;

     usleep(20000);
     printf("key=%ld\r\n",XGpio_DiscreteRead(axi_gpio_inst_ptr, KEY_CHANNEL1));
     //延时20ms,按键消抖
   if (XGpio_DiscreteRead(axi_gpio_inst_ptr, KEY_CHANNEL1) == 5)
   {//按键有效按下
	   print("key=5,led1\r\n");
 	  led1_value = ~led1_value;
 	  XGpioPs_WritePin(&gpiops_inst, MIO_LED1, led1_value);	  //改变LED显示状态
 	  XGpio_InterruptDisable(axi_gpio_inst_ptr, KEY_CH1_MASK);//关闭 AXI GPIO中断使能
    }
   else if (XGpio_DiscreteRead(axi_gpio_inst_ptr, KEY_CHANNEL1) == 3)
   {//按键有效按下
	   print("key=3,led0\r\n");
 	  led0_value = ~led0_value;
 	  XGpioPs_WritePin(&gpiops_inst, MIO_LED0, led0_value);	  //改变LED显示状态
 	  XGpio_InterruptDisable(axi_gpio_inst_ptr, KEY_CH1_MASK);//关闭 AXI GPIO中断使能
    }

	  XGpio_InterruptClear(axi_gpio_inst_ptr, KEY_CH1_MASK);  //清除中断
	  XGpio_InterruptEnable(axi_gpio_inst_ptr, KEY_CH1_MASK); //使能AXI GPIO中断
 }

5.然后编译工程并下载即可

单位宽修改为多位宽的精髓在于AXI_GPIO_ALL_MASK 这个宏定义,这个宏定义在     XGpio_InterruptEnable和XGpio_SetDataDirection中有调用,哪一位为1则打开哪一位的中断以及设置为输入/输出。

中断函数intr_handler部分:我设置的位宽是3,实际上对应三个按钮。根据原理图设计这三个按钮默认高电平,按下是低电平。因此当按钮轮流按下时,XGpio_DiscreteRead(axi_gpio_inst_ptr, KEY_CHANNEL1)的值分别为3、5、6,调用if语句进行判断即可区分按下的是哪个按键。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

睿智の男孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值