简介
在本实验中,我们将在硬件设计时添加一个 AXI GPIO 的 IP 核。IP 的定义为“用于 ASIC 或 FPGA 中的预先设计好的电路功能模块”。IP 主要分为软 IP、固 IP 和硬 IP。软 IP 是用 Verilog/VHDL 等硬件描述语言描述的功能块,但是并不涉及用什么具体电路元件实现这些功能。固 IP 是完成了综合的功能块。硬 IP 提供设计的最终阶段产品——掩膜。
AXI GPIO 就是一个软 IP,它通过使用 PL 端的逻辑资源来实现我们需要的功能,实际上在芯片中并不存在这样一个电路。这与 PS 端的 GPIO 不同,PS 端的 GPIO 是一个实际的电路。在官方资料中我们可以看到 AXI GPIO 的结构框图如下图所示,从结构框图中我们可以看到模块通过一个 AXI4-Lite 来实现主机对模块的访问,来读取和配置 AXI GPIO 内的各个寄存器,同时,模块还可以产生中断信号来通知主机中断事件的发生。另外可以看到 AXI GPIO 有两个通道,可以配置为单通道或双通道模式。各个I/O既可以在软件上配置也可以在硬件设计时被动的配置为输入或输出。
BD硬件设计
BD设计也比较简单,加入ZYNQ核和一个AXI_GPIO核,然后自动连线就好了。
软件设计
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include <xgpiops.h>
#include "xgpio.h"
#include "xil_exception.h"
#include "xscugic.h"
#include <xil_types.h>
#include <sleep.h>
#define AXI_GPIO_ID XPAR_GPIO_0_DEVICE_ID
#define PS_GPIO_ID XPAR_XGPIOPS_0_DEVICE_ID
#define AXI_INT_ID XPAR_FABRIC_GPIO_0_VEC_ID
#define SGC_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define PS_LED 50
XGpioPs gpiops;
XGpioPs_Config *gpiops_config;
XGpio axi_gpio;
XScuGic_Config *SCG_config;
XScuGic SGC_inst;
void AXI_Handler(void *callback);
u32 init();
u32 setup();
int data = 0x0;
int main()
{
init_platform();
print("Hello World\n\r");
init();
setup();
cleanup_platform();
return 0;
}
u32 init(){
u32 status;
//PS端的led进行初始化
gpiops_config = XGpioPs_LookupConfig(PS_GPIO_ID);
status = XGpioPs_CfgInitialize(&gpiops, gpiops_config,
gpiops_config->BaseAddr);
if(status!=XST_SUCCESS){
print("failed\n");
return XST_FAILURE;
}
//对AXI_GPIO进行初始化
status = XGpio_Initialize(&axi_gpio, AXI_GPIO_ID);
if(status!=XST_SUCCESS){
print("failed\n");
return XST_FAILURE;
}
return 0;
}
u32 setup(){
u32 status;
XGpio_SetDataDirection(&axi_gpio, 0x1,
0x1);
XGpioPs_SetDirectionPin(&gpiops, PS_LED, 0x1);
XGpioPs_SetOutputEnablePin(&gpiops, PS_LED, 0x1);
XGpioPs_WritePin(&gpiops, PS_LED, 0x0);
XGpio_InterruptEnable(&axi_gpio, 0x1);
XGpio_InterruptGlobalEnable(&axi_gpio);
SCG_config = XScuGic_LookupConfig(SGC_ID);
status = XScuGic_CfgInitialize(&SGC_inst, SCG_config,
SCG_config->CpuBaseAddress);
if(status!=XST_SUCCESS){
print("failed\n");
return XST_FAILURE;
}
//中断优先级和触发方式设置
XScuGic_SetPriorityTriggerType(&SGC_inst, AXI_INT_ID,
0xA0, 0x1);
//异常中断处理部分
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&SGC_inst);
Xil_ExceptionEnable();
//设置中断控制器的回调函数,打开中断控制器的使能
XScuGic_Connect(&SGC_inst, AXI_INT_ID,
(Xil_InterruptHandler)AXI_Handler, &axi_gpio);
XScuGic_Enable(&SGC_inst, AXI_INT_ID);
return 0;
}
void AXI_Handler(void *callback){
int key_value;
XGpio *xgpio_axi = (XGpio *)callback;
print("产生中断\n");
key_value = XGpio_DiscreteRead(xgpio_axi, 0x1);
XGpio_InterruptDisable(xgpio_axi,0x1);
usleep(20000);
if(key_value == 0){
data = ~data;
XGpioPs_WritePin(&gpiops,PS_LED , data);
}
XGpio_InterruptClear(xgpio_axi, 0x1);
XGpio_InterruptEnable(xgpio_axi, 0x1);
}
利用AXI_GPIO产生中断控制PS端的LED。