软件部分编写
这里引用的AXI GPIO的资源对应的是gpio的部分,配置相应的功能函数可以参考相应的文件和对应的例程。
首先给出我本次的工程代码,在后面进行简要的说明:
#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xgpiops.h" #include "xgpio.h" #include "xparameters.h" #include "xparameters_ps.h" #include "xscugic.h" #include "sleep.h" //设置设备id和io编号 #define GPIO_ID XPAR_XGPIOPS_0_DEVICE_ID //PS GPIO的器件ID #define AXI_GPIO_ID XPAR_GPIO_0_DEVICE_ID//AXIGPIO的器件ID #define SCUGIC_ID XPAR_PS7_SCUGIC_0_DEVICE_ID//中断的ID //axi gpio的中断号 #define AXI_GPIO_INTR_ID XPAR_FABRIC_GPIO_0_VEC_ID #define LED0 54 //axi gpio通道1 #define AXI_GPIO_CHANNEL 1 //定义调用GpioPs的结构体 XGpioPs gpiops; XGpioPs_Config *gpio_cfg; //定义调用中断的结构体 XScuGic gpio_gic; XScuGic_Config *gpio_gic_cfg; //定义调用Gpio的结构体 XGpio axi_Gpio; //变量声明 u32 key_value=0; //函数声明 void Init_gpio(); void IntrHandler(); int main() { u32 led_status=0; init_platform(); Init_gpio(); Init_interrupt(); print("axi_gpio TEST\n\r"); while(1) { if(key_value==1){ //清除中断状态 if(XGpio_DiscreteRead(&axi_Gpio, AXI_GPIO_CHANNEL)==1){ led_status=~led_status; } XGpio_InterruptClear(&axi_Gpio, 0x0000001); key_value=0; XGpioPs_WritePin(&gpiops,LED0,led_status); usleep(200000); //打开中断使能 XGpio_InterruptEnable(&axi_Gpio, 0x0000001);//使能中断 } } cleanup_platform(); return 0; } //初始化gpio void Init_gpio(){ //查找设备ID ,gpio初始化操作 gpio_cfg=XGpioPs_LookupConfig(GPIO_ID); XGpioPs_CfgInitialize(&gpiops,gpio_cfg,gpio_cfg->BaseAddr); //设置gpio为输出,开启使能 XGpioPs_SetDirectionPin(&gpiops,LED0,1); XGpioPs_SetOutputEnablePin(&gpiops,LED0,1); //对PL端的gpio进行初始化 XGpio_Initialize(&axi_Gpio,AXI_GPIO_ID); //对AXI设置方向 XGpio_SetDataDirection(&axi_Gpio,AXI_GPIO_CHANNEL,0x0000001);//设置为输入 } void Init_interrupt(){ //初始化gic gpio_gic_cfg = XScuGic_LookupConfig(SCUGIC_ID); XScuGic_CfgInitialize(&gpio_gic,gpio_gic_cfg,gpio_gic_cfg->CpuBaseAddress); //初始化异常处理 Xil_ExceptionInit(); //CPU中断异常注册 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&gpio_gic); //使能处理器中断 Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); //链接中断信号 XScuGic_Connect(&gpio_gic,AXI_GPIO_INTR_ID,(Xil_InterruptHandler)IntrHandler,&axi_Gpio); //使能中断 XScuGic_Enable(&gpio_gic,AXI_GPIO_INTR_ID); //0xa0中断优先级 XScuGic_SetPriorityTriggerType(&gpio_gic,AXI_GPIO_INTR_ID,0xA0, 0x3); //axi gpio使能中断 XGpio_InterruptGlobalEnable(&axi_Gpio);//打开全局中断 XGpio_InterruptEnable(&axi_Gpio, 0x0000001);//使能中断 } void IntrHandler(){ printf("interrupt~~\n\r"); key_value=1; //关闭中断使能 XGpio_InterruptDisable(&axi_Gpio, 0x0000000); }
部分代码讲解
代码很类似上次的GPIO的中断功能的代码,这里只是更改了部分函数对axi gpio的ip进行ip的配置,实现带中断的输入功能的KEY。
axi的初始化只需要一行代码即可完成,然后根据编程指南设置下方向即可完成输入的配置
XGpio_Initialize(&axi_Gpio,AXI_GPIO_ID);//对PL端的gpio进行初始化
XGpio_SetDataDirection(&axi_Gpio,AXI_GPIO_CHANNEL,0x0000001);//对AXI设置方向设置为输入
对于这里的AXI_GPIO中断的标号就是我们前面提到的61,在这里我们可以进行define一下,方便我们进行引用。
#define AXI_GPIO_INTR_ID XPAR_FABRIC_GPIO_0_VEC_ID//axi gpio的中断号
在SDK中寻一下这个参数的数据也可以验证我们的标号数值:
对于axi _gpio,我们配置的时候可以看到,每个IP核有两路GPIO,这里我们只用了通道1,所以我们的通道编号定义为1 #define AXI_GPIO_CHANNEL 1//axi gpio通道1
在配置axi gpio的中断功能时,用的了XScuGic_SetPriorityTriggerType(&gpio_gic,AXI_GPIO_INTR_ID,0xA0, 0x3);在寻到该函数定义时候,可以简要了解下参数的配置功能。
0xa0配置了中断优先级,这里我们不进行中断优先级的配置,所以引用的是示例里面的默认值,中断编号就是我们AXI GPIO的编号,0x03这个值用于配置中断的方式。这里我们的中断有高电平触发和边沿触发模式。我们设置边沿触发后,在我们按下按键会满足两次边沿触发的条件(这里我感觉注释和实际操作不相符),然后回看我们的编程指南,在中断配置时候是也是要求我们:当接收到中断时,读取GPIOx_DATA寄存器中相应的位。通过写入值为1的对应位来清除IP中断状态寄存器中的状态。
所以我们就引用了XGpio_DiscreteRead(&axi_Gpio, AXI_GPIO_CHANNEL) 对中断的状态进行读取。
对应编程指南代码编写如下:
//清除中断状态 if(XGpio_DiscreteRead(&axi_Gpio, AXI_GPIO_CHANNEL)==1){ led_status=~led_status; } XGpio_InterruptClear(&axi_Gpio, 0x0000001);
完成代码编写后下载到我们的PYNQ的开发板即可完成本次实验。
Vuko公众号同步更新~
欢迎大家关注我的公众号。如果需要工程微信后台留言即可~